Compare commits
2214 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 992458ae4b | |||
| 8c16686150 | |||
| 7cbadfbd12 | |||
| 0e43697ee0 | |||
| 7de27df309 | |||
| b06db1ba39 | |||
| 5fe24cb689 | |||
| 733d1384a4 | |||
| 99e9d0d023 | |||
| 2bd1e46ab9 | |||
| cabaad4b17 | |||
| 8b6fe691ed | |||
| ccf9efdaa5 | |||
| bf66bec4c7 | |||
| 3319709526 | |||
| 7ceab5c88c | |||
| 94d4789e68 | |||
| b13985d550 | |||
| dc4a3e9b89 | |||
| d538c35532 | |||
| cfd26321b5 | |||
| 61d955f3de | |||
| a9f54c44e9 | |||
| 125877035f | |||
| 8f4b0c8078 | |||
| 1863e85bf5 | |||
| 488c6099fc | |||
| 67abc6d2cf | |||
| c56a57c0ba | |||
| 30b2c1ad61 | |||
| 5e279363e4 | |||
| abb7509f03 | |||
| 1cd60c05f3 | |||
| 510cc22484 | |||
| 3da664236c | |||
| 7e35a7fe0c | |||
| 58ef7db5d6 | |||
| f9de4a394c | |||
| dced5816df | |||
| 690ac740d2 | |||
| 89d0412e22 | |||
| a305752faf | |||
| 469b139e89 | |||
| 8f5d9c4816 | |||
| 7102c77e0b | |||
| 115ae21f1f | |||
| 8d3fdf45b9 | |||
| 1e7e5ea57c | |||
| 7c8b91456f | |||
| dc960f30f5 | |||
| ba12e31280 | |||
| 027a4081a2 | |||
| 190def17e5 | |||
| 9730526d33 | |||
| c87c843308 | |||
| 6453cdf0d6 | |||
| 5f80c33b24 | |||
| a33542c9b5 | |||
| 3a1d98648f | |||
| 4ec79d61d0 | |||
| b4f055f80c | |||
| 6bf35c679f | |||
| 3349d43c00 | |||
| ced961d24c | |||
| 419f708d87 | |||
| bbc1c04042 | |||
| 7a6865637d | |||
| ae96420925 | |||
| 2822812d0d | |||
| c8ab430491 | |||
| bb87f28e80 | |||
| 6db671215a | |||
| 64566ec6cf | |||
| faaf97ef62 | |||
| 67d6efed21 | |||
| 571d9bd610 | |||
| 4144698540 | |||
| 9bf6bf2c78 | |||
| cc9236b8db | |||
| 0103b59e61 | |||
| e9f6531db7 | |||
| 62c2c750ea | |||
| 3e5e3175e0 | |||
| 54c5af30d9 | |||
| ca4a3361c0 | |||
| 47d302221d | |||
| ed215657e6 | |||
| 3e63b14192 | |||
| 86433ab3a8 | |||
| 7214800d93 | |||
| 29f298fa4a | |||
| ef35bc77cb | |||
| 6ae880f61e | |||
| 0d1149310c | |||
| 51d32bb8d3 | |||
| 49a8980dea | |||
| 9fe1680c56 | |||
| b7db65a023 | |||
| 4c02002265 | |||
| d0198649f2 | |||
| 32c1fd082d | |||
| 363bf42b95 | |||
| a1ab2232f3 | |||
| cf69f43166 | |||
| 9833438733 | |||
| 67c5e3966a | |||
| aa0927911d | |||
| 13c9e1ed58 | |||
| 19a457ab7d | |||
| 0926bff0cc | |||
| 53a0bc963a | |||
| a2819d822a | |||
| 175112d97d | |||
| dced47024f | |||
| ffc361406e | |||
| 852c648235 | |||
| 1197b96c49 | |||
| f21fe81e16 | |||
| 593dfd0108 | |||
| aaf0fb9d12 | |||
| 02e9f8aef3 | |||
| 424055c04e | |||
| 02daf17326 | |||
| a666f0d52e | |||
| 27a760c58c | |||
| 0ba12f48c6 | |||
| eaaf54d886 | |||
| 4b3d634fe9 | |||
| f77a699ea4 | |||
| e989e38cc2 | |||
| 6a900ed6e7 | |||
| 29e6b85f79 | |||
| 2641408d53 | |||
| 5b79226183 | |||
| 98f9f0cd48 | |||
| cf7e107ad1 | |||
| ab66c1aa1b | |||
| 5b03366909 | |||
| 7824e1446a | |||
| 59cf1a4937 | |||
| 252113c838 | |||
| e2f84d1acd | |||
| 204dcecb28 | |||
| 70bbfbea12 | |||
| 2221a0a908 | |||
| 203b215093 | |||
| 76ee84dae8 | |||
| 79e1c87a01 | |||
| ed208114be | |||
| 7dd711b37c | |||
| 4852802d66 | |||
| c495b1faab | |||
| eb5bd8e6ac | |||
| ff7dcf9c17 | |||
| 2b12a16c84 | |||
| 4d00b2ebbb | |||
| 1ba5abbaef | |||
| b87a98bbda | |||
| f76361a345 | |||
| f25bab9555 | |||
| ed78b8429f | |||
| 94e9dd8f28 | |||
| 90215ca0dd | |||
| 34eb647fcb | |||
| 83205290de | |||
| 02fd528c32 | |||
| e05193f46d | |||
| 14e2d900b5 | |||
| ba4290340d | |||
| 5a04700bae | |||
| 999f50dce9 | |||
| 9522e6e714 | |||
| 7836ea4479 | |||
| 37e8ab8de1 | |||
| 34048497e7 | |||
| 5197422482 | |||
| d9987c2734 | |||
| c9671b4712 | |||
| bbf03e3060 | |||
| e35a78e3cf | |||
| e318be6a88 | |||
| 1dab0ebc25 | |||
| 687e58e9d4 | |||
| 993a4aa675 | |||
| c991510b0f | |||
| c8025bf004 | |||
| 9f5767a80c | |||
| ffb05d6271 | |||
| 2dd2d3dd7b | |||
| be29c7fca0 | |||
| 2c23a3c0b3 | |||
| 37e3ead8e9 | |||
| b018ea7b1b | |||
| d6cdca35d4 | |||
| a09d150b47 | |||
| 7cf46afc48 | |||
| 056c95670f | |||
| 35dffe43d9 | |||
| 19c26f0733 | |||
| 388ff10ff5 | |||
| 8c7be8e45f | |||
| 579aa67cde | |||
| 725f86a0d2 | |||
| 50a6ef18d2 | |||
| 1b3e924450 | |||
| a33e08e299 | |||
| 45dee5a666 | |||
| 642473244e | |||
| e92f344335 | |||
| 7951795ea4 | |||
| 101fbcca90 | |||
| d562132a4a | |||
| 7152ab39ff | |||
| 39c5279f5d | |||
| fef0e16f9c | |||
| fb1361b00d | |||
| 64c75c8b57 | |||
| f4e015a255 | |||
| 242b68c488 | |||
| 9452c7e0c7 | |||
| ab1d3d1ced | |||
| 41df92bb93 | |||
| 427db3f29a | |||
| b5600bdd7f | |||
| a2153b668a | |||
| 7d52c82c3b | |||
| 092f1a4959 | |||
| 21bee7e40c | |||
| a9ac0ac725 | |||
| 5dc1ed6696 | |||
| b55f66e69c | |||
| ab637e22b1 | |||
| fa665c5494 | |||
| e91b75a1bb | |||
| 4c6f85fd25 | |||
| f09e9b7790 | |||
| b51d3da7e5 | |||
| 861dbd5977 | |||
| 5001fcdd53 | |||
| eeb47dc724 | |||
| 5556dff11e | |||
| 18b57fa6aa | |||
| 12bb4d75fd | |||
| 411d8d4d98 | |||
| 748df0b21a | |||
| 8d98316a89 | |||
| c6b45a8e09 | |||
| d42920674a | |||
| c66fced161 | |||
| d3dee115ab | |||
| 77aa965533 | |||
| 29499f21c5 | |||
| 18d8968ae7 | |||
| 467cf73635 | |||
| 457519eae3 | |||
| 2a1c24763d | |||
| 92196dc207 | |||
| f73723f9af | |||
| 26ab8755b6 | |||
| d91382208d | |||
| 5f90ed8b3e | |||
| 644fad8355 | |||
| c4904cc365 | |||
| 613e38d7f8 | |||
| dee7c339b3 | |||
| b80cda66a9 | |||
| 411bcbcbde | |||
| 352bf8839b | |||
| 18f438a528 | |||
| 076944da5d | |||
| acbba95032 | |||
| 75f77783ff | |||
| 87e0f074e8 | |||
| 2211c69455 | |||
| a7449c913c | |||
| aaec0e641b | |||
| 5afed2d396 | |||
| 843348338a | |||
| 061ebc7942 | |||
| 822c1c97e3 | |||
| 65df6aa4a0 | |||
| 32719690ac | |||
| f83748fdc2 | |||
| a354d7c00b | |||
| 41f7312263 | |||
| d3804d2c2c | |||
| 96184b83a3 | |||
| 9bcc057176 | |||
| 20f3213477 | |||
| bf8505a285 | |||
| 770a07cc28 | |||
| 3f80f52ca5 | |||
| 52f6e149ec | |||
| 6893df9103 | |||
| 60546c9788 | |||
| 12f91564fb | |||
| ca448e682a | |||
| 2b077d140f | |||
| 0f58ff8356 | |||
| 940b740b24 | |||
| 0f258f94a8 | |||
| fd7b22f639 | |||
| ca3464512d | |||
| f59cb6417f | |||
| 74ccb53607 | |||
| e4c6e98099 | |||
| cfab0fa245 | |||
| 08d861e87c | |||
| 73234e7782 | |||
| de8d28ea5f | |||
| ed7b478ee0 | |||
| ff9a216990 | |||
| 58c94159b1 | |||
| 7a1bd4d53a | |||
| 5d7c23c62a | |||
| d91d911051 | |||
| cd0cab465d | |||
| a45b887c5b | |||
| f965b7129b | |||
| e894ce00c9 | |||
| 333aba8be6 | |||
| e9d93ae210 | |||
| 043c8be747 | |||
| 1be67518df | |||
| 4bf1987bb7 | |||
| ae45eed2b1 | |||
| 572a9393aa | |||
| 7579c41a35 | |||
| 4e589c2575 | |||
| 026da34ce9 | |||
| 0daf49a1da | |||
| f57e4c6c14 | |||
| 14bd1d01f2 | |||
| 918e20b164 | |||
| 6a0e90ef90 | |||
| 71fe8ed80d | |||
| 581c9c570b | |||
| b25fe3d127 | |||
| fc4aef6d89 | |||
| 6b4fa6a40d | |||
| 6756eea209 | |||
| bf3cd37b49 | |||
| cc7caa9e16 | |||
| 633060562f | |||
| cc48546f62 | |||
| 96cc44e521 | |||
| f2d9e4b2df | |||
| 049c7ad1f0 | |||
| 226dad651b | |||
| 0977cabc79 | |||
| 0b5e8a086e | |||
| e024ea5ee1 | |||
| 6f71092aa4 | |||
| edce44df97 | |||
| 54551d9f37 | |||
| 8521b5501f | |||
| 396dc21903 | |||
| 5e2b0ba46c | |||
| cce5d775de | |||
| 248a239c7b | |||
| 83655e9aef | |||
| 973d115edf | |||
| aaa9f89550 | |||
| 8afad5614a | |||
| a9fdabf926 | |||
| b5b262c722 | |||
| d1e1190cbd | |||
| 9812eaaca7 | |||
| 4520e04d37 | |||
| 5679b5862f | |||
| e72dc38d77 | |||
| 71fcfa4935 | |||
| c4463036c3 | |||
| b343a17b29 | |||
| 0b0fb249bf | |||
| 8d689974a7 | |||
| 375c81d38d | |||
| 0ef4f36d44 | |||
| c85f6c1228 | |||
| 0cabc81693 | |||
| 12b4fff81e | |||
| 27b6627110 | |||
| 387014dd37 | |||
| d5c91b9bda | |||
| 370f4f6257 | |||
| 49a665488e | |||
| 29da133726 | |||
| 1194bb8ae3 | |||
| 7599124aa0 | |||
| 01d2d91ecc | |||
| 6980d19214 | |||
| ac14a7b0da | |||
| 23f00ab533 | |||
| 39122bd61d | |||
| c5824765f9 | |||
| 547e942c66 | |||
| 2ab04e7e2f | |||
| a08fef172e | |||
| a04f77e7e0 | |||
| 4900f3e54d | |||
| 34ee6411d5 | |||
| 5abe7bc7e5 | |||
| a48aef4039 | |||
| e1198f29ce | |||
| 329e619c8c | |||
| 9a9e1b46ef | |||
| cc94ab6411 | |||
| e67541e82f | |||
| d907be264b | |||
| 003c1df53e | |||
| 6470838065 | |||
| a178555838 | |||
| f844e9e702 | |||
| 8753dbdb0f | |||
| 1bd24f7042 | |||
| 66d58bf047 | |||
| 1e5c4b0d79 | |||
| 711d402f17 | |||
| e19f54a378 | |||
| 5294fc4767 | |||
| 7ed3a1df04 | |||
| 2d45354f50 | |||
| 9f6d13f4c3 | |||
| 57a31d0ec9 | |||
| da277d9816 | |||
| 22dabc5180 | |||
| 47f11fc3a6 | |||
| 91a2e56215 | |||
| e6681af9d0 | |||
| d9e3c43c91 | |||
| f84de4ac21 | |||
| 3089231476 | |||
| 0f94fb9d6d | |||
| 01097f7225 | |||
| a25e4e1ed8 | |||
| 9e75595754 | |||
| f6d5945b59 | |||
| 250eb20851 | |||
| d2b00c4995 | |||
| 89c73d89b4 | |||
| fcd63bf9eb | |||
| 9a0cf6a609 | |||
| 6c32d97b23 | |||
| c9e40d3e59 | |||
| dc920a7e39 | |||
| 07262387e0 | |||
| 97e2ac689e | |||
| 286a80d03b | |||
| 3aaf31fdb9 | |||
| 71ae5764cc | |||
| 2e41ed153b | |||
| 9ee422e6ba | |||
| 8a008d1808 | |||
| d78faea737 | |||
| 3cf72e93e6 | |||
| caa02bbca1 | |||
| 33e64aee6f | |||
| d17150270e | |||
| 463a297f0c | |||
| 407d73a735 | |||
| b5bfdb56dc | |||
| 58b7ef8431 | |||
| 2211dfb741 | |||
| 1d6e602473 | |||
| a6c52fd154 | |||
| 7a5bceae4c | |||
| 6f3e7f9e56 | |||
| fb9822b507 | |||
| d0db09cb92 | |||
| 189fbb3f7e | |||
| 887c95fe2a | |||
| fdbeb951eb | |||
| 9d23dee3fc | |||
| 70b8cef318 | |||
| e1620b8fa2 | |||
| dabc9589e9 | |||
| da98900e3a | |||
| b584ba9149 | |||
| d24ba6d13d | |||
| aba078a9d8 | |||
| 161487d6c2 | |||
| d851dd7196 | |||
| cf29621aa7 | |||
| 9e46577f43 | |||
| b7980b83df | |||
| 0a0bed7ae0 | |||
| e42b8fc37d | |||
| b01e30acfd | |||
| 311c50df9f | |||
| c2f9467f61 | |||
| 06c8656b9e | |||
| 4748bca8a4 | |||
| 916387748c | |||
| 216d7dcb86 | |||
| 23f2c7e6f5 | |||
| c8e0e5eca2 | |||
| 3167d3f451 | |||
| beb9c1ba74 | |||
| dcd88260e9 | |||
| 5f4f631fc5 | |||
| dc6fda03a1 | |||
| 764ad81537 | |||
| e26c41095f | |||
| d7bd78d612 | |||
| c50b4c72d7 | |||
| 124e555ed0 | |||
| aeba3aa209 | |||
| e50b5202b8 | |||
| 32c7578629 | |||
| 5bc5e0e8e9 | |||
| 7ee4692e84 | |||
| 679688705d | |||
| 83f0a2c094 | |||
| 504817058b | |||
| 45754b27de | |||
| a75ae8bbef | |||
| c3e6dc69bb | |||
| 0285bb6ea5 | |||
| a542292ce2 | |||
| 0765ebf735 | |||
| e86e8c37a8 | |||
| 149a42cc94 | |||
| 8de4613a3e | |||
| 60950c57e3 | |||
| 4727bb5c9b | |||
| 1e1e254897 | |||
| df5455121c | |||
| 0e2570b204 | |||
| f57519b909 | |||
| 088393ca12 | |||
| 375dc63db3 | |||
| 503324162f | |||
| 5445b64376 | |||
| 7fe997d38c | |||
| d7673dad7b | |||
| 44eed9282b | |||
| 0eeb94b24c | |||
| ef221e1c6c | |||
| 75cdefa4fe | |||
| a609a1c6c2 | |||
| f4906a97b9 | |||
| 21ffd441fa | |||
| a82383d78e | |||
| b405029f0f | |||
| db7d4f56b3 | |||
| 3151197471 | |||
| e06fe6935a | |||
| e7cec83a4c | |||
| e5f0ad4f0b | |||
| cabbe70e47 | |||
| b86c3681bb | |||
| 0f8239bc8e | |||
| 13f5baf608 | |||
| 4f5d7f79bd | |||
| 23899613c3 | |||
| db46a915cc | |||
| b591aa013d | |||
| c0db8b71dd | |||
| 444bf41fa4 | |||
| 54302a53e1 | |||
| 63059cfab3 | |||
| ec7d3a9885 | |||
| 960b55fd6c | |||
| 3067ba60ae | |||
| c9a756eddc | |||
| d4ea5fc74f | |||
| 92e52f1a5d | |||
| ef1d75db83 | |||
| f03d1a5d27 | |||
| 8a55b706ca | |||
| 357133677a | |||
| 1b6c660a8f | |||
| 111e68831e | |||
| d9f6732ce2 | |||
| f2b81ba86c | |||
| 2542112301 | |||
| a45215ddf2 | |||
| cb28b2de07 | |||
| bf0b43aa24 | |||
| 811d6deb41 | |||
| bcdd9374c7 | |||
| f70174d1d1 | |||
| 4a39a4af1c | |||
| 0367399c89 | |||
| c5db4dc15f | |||
| 31fbfa3a70 | |||
| 3515ddcfe6 | |||
| 90303d5952 | |||
| 9a02421091 | |||
| 4961b819f3 | |||
| 61c2ea9225 | |||
| f5f7269f70 | |||
| 03f1430ddc | |||
| c3dab15eb6 | |||
| a4f6ec516b | |||
| 1ca213cec6 | |||
| b782c8560c | |||
| d2e68068bf | |||
| 129a846393 | |||
| 15308931e9 | |||
| 4dffeedd1c | |||
| d0c4111429 | |||
| f579b6f971 | |||
| f5124de327 | |||
| 9ab86ae2bf | |||
| 51a7d3ff50 | |||
| 80b9afc14d | |||
| 92ae8f37ba | |||
| df1f828488 | |||
| d8c97da087 | |||
| 9d29e5d87a | |||
| bf62147802 | |||
| 34735b8aad | |||
| 932b2b9acf | |||
| 7ab4472865 | |||
| e1e79206f9 | |||
| 7ebe6de022 | |||
| b234760e92 | |||
| 3119e4b82b | |||
| 2c3f05e6f1 | |||
| 5b5da8698e | |||
| c3c0c8d881 | |||
| 9de5e31a7a | |||
| dbf15c2db2 | |||
| c9c900b364 | |||
| 5c07204351 | |||
| 828b370ea1 | |||
| de947d8b17 | |||
| 8cb5e68b1a | |||
| 99aef2a178 | |||
| fff1460dfb | |||
| e3b619fd54 | |||
| 29e363e7fb | |||
| c209245b0e | |||
| 4194ce3095 | |||
| a0e9f59e04 | |||
| c940c2722e | |||
| 5c84c12f40 | |||
| 1bcacfab74 | |||
| 1f5f8a76fb | |||
| cfa8b1f0dd | |||
| aecbcdd390 | |||
| 74729a372b | |||
| 63d8abe32f | |||
| 2c397bfa0b | |||
| bfef8f39b7 | |||
| 4430cbc3cb | |||
| ae20bac3c5 | |||
| d9a26c4062 | |||
| 48cb374d94 | |||
| 9d6bd91279 | |||
| 163cfda282 | |||
| 72cda375c8 | |||
| ecb4a08655 | |||
| 05c50bc64f | |||
| 747e4a7061 | |||
| 2b8b876713 | |||
| f13694b539 | |||
| 648f9c9723 | |||
| 0a6c37b726 | |||
| b43a51f912 | |||
| fa328c5a78 | |||
| 728bcc2b10 | |||
| 941903a243 | |||
| 4c8579b340 | |||
| 17416a09f1 | |||
| fdda21b114 | |||
| c75ae957f1 | |||
| 8c678126f1 | |||
| 2b0590f9bd | |||
| a31992aac7 | |||
| 829d2505e3 | |||
| df30498365 | |||
| 5d553bf9f2 | |||
| 03e3673dbb | |||
| 25b8b37f00 | |||
| 665f97e782 | |||
| 48a007febd | |||
| 155e0fada6 | |||
| fe2f1d32b5 | |||
| 2fcbb19e72 | |||
| 06a50d637a | |||
| 811b33e31a | |||
| 54c83ee940 | |||
| 7406e83dde | |||
| dc2c7d5339 | |||
| aaa25e5d48 | |||
| b757bd0ea2 | |||
| dd971d6b7d | |||
| c07966408b | |||
| 2557956b68 | |||
| 735260d21b | |||
| e5b0e43e18 | |||
| aa42b2494c | |||
| f057054172 | |||
| c39314c643 | |||
| ae018b759c | |||
| 556b498e06 | |||
| 19f1110421 | |||
| cc73ed19b3 | |||
| ccb7cc40df | |||
| 6d61e950d6 | |||
| 438c6e616c | |||
| 8d2396b81f | |||
| 9588ef00a5 | |||
| 411603ea03 | |||
| 67addfdb37 | |||
| 3afcd31f61 | |||
| 7ac901cb08 | |||
| fcdee8f5d5 | |||
| a7c32dfa95 | |||
| 36f3c0f77a | |||
| dad4981a57 | |||
| df53357ef1 | |||
| 85e333127a | |||
| d52d86ae82 | |||
| f62293275f | |||
| af490bae8e | |||
| edf5a0f677 | |||
| 5eecd0a57d | |||
| 1fc11a6b06 | |||
| 3516538813 | |||
| e3af8cb2e8 | |||
| 16cd822555 | |||
| 5938368a09 | |||
| 50f865b81c | |||
| 96cd09471b | |||
| cf6c1e97bb | |||
| f557e1efb4 | |||
| 8893fd1656 | |||
| 081831e6ea | |||
| 46c3ce0e34 | |||
| 6031a45c68 | |||
| ca64887cba | |||
| 3f1d67ca4c | |||
| ff09af2812 | |||
| 42b68fa834 | |||
| 2cc2c967d1 | |||
| bec4e4437d | |||
| f9abfbf68a | |||
| 53af4ee39f | |||
| af5f2f85da | |||
| ea83231da5 | |||
| c4693602ef | |||
| 3c8dd85966 | |||
| 0399022d25 | |||
| c6840496c0 | |||
| f7657280b6 | |||
| f88a4baf79 | |||
| b051f715e6 | |||
| 81a05c89e4 | |||
| cc55b016e9 | |||
| ae8e51074e | |||
| 313b93169d | |||
| db148741e9 | |||
| 1ecad20a0d | |||
| 22c5c539c2 | |||
| d59e526e1e | |||
| 94fa0047db | |||
| 26e2f9ddd1 | |||
| 23254b4f24 | |||
| 9a44f16846 | |||
| cad0069be2 | |||
| f315a013b8 | |||
| f780aa6160 | |||
| 0f03beb2b5 | |||
| 7e39c43896 | |||
| 906d28fa5d | |||
| 4d017f5d49 | |||
| 6410314b0b | |||
| 1c0202e790 | |||
| 918c978551 | |||
| 3d1a85bbea | |||
| 1a442c36e9 | |||
| a4e322f085 | |||
| 0b1d268b09 | |||
| c2be6bc019 | |||
| 9e11e832da | |||
| 348e656671 | |||
| 54cdf6d6f2 | |||
| 7c5ca8f199 | |||
| ee42d94e2d | |||
| 91baa9dfd7 | |||
| 572b176401 | |||
| 97f1dc0749 | |||
| d67ac1a708 | |||
| 2707001a3a | |||
| bb1064ac42 | |||
| 436cc692da | |||
| 76decf2e8b | |||
| ccdd0f599a | |||
| c65fed1d38 | |||
| c36ec7c95b | |||
| 305ce04284 | |||
| 034ce137a9 | |||
| 73c81a0a6c | |||
| 7544727f7a | |||
| 961a379f79 | |||
| 9ffcaa5550 | |||
| 2dbae6ce51 | |||
| f7505e8877 | |||
| c453f8e7a9 | |||
| 3a4695713d | |||
| 7d9d0878de | |||
| 26729ca482 | |||
| 405600783e | |||
| 5b5e9296b3 | |||
| dd5d520b53 | |||
| b3d517943a | |||
| 59ca59d431 | |||
| 78c92be14b | |||
| adf0c726ef | |||
| 9ecfed4e56 | |||
| 9db884f371 | |||
| e0c211085c | |||
| 555bfaf37a | |||
| bcf4af4a2f | |||
| 6a71163912 | |||
| cb2fcf4f52 | |||
| 061d78c681 | |||
| 0ffa973ec6 | |||
| 03de87c213 | |||
| 59481dd762 | |||
| 86f4aebead | |||
| a92950d234 | |||
| ccdc6f1a63 | |||
| 62cc8f456c | |||
| f7c6b9a0f7 | |||
| 01a6e3c619 | |||
| 6948d56e5d | |||
| 6373b3e49c | |||
| 91dc1b6639 | |||
| 6317b08090 | |||
| aae0547cca | |||
| 4f9c422e2f | |||
| 3595ac08f7 | |||
| 5339f440bd | |||
| 86d7442a5f | |||
| e6e5626a2c | |||
| 4a52dd1c5b | |||
| dd1302e8b1 | |||
| 7b4b7232fc | |||
| b069725df0 | |||
| aa9d8c773f | |||
| c68a03d05c | |||
| cbea651cf8 | |||
| b4ee345966 | |||
| 296e7ccb08 | |||
| 43bb53e789 | |||
| 384be58230 | |||
| 46d1a87b89 | |||
| 7c8bf18cc6 | |||
| 35255d052d | |||
| cf5c776990 | |||
| 9961172d70 | |||
| c1c46544a6 | |||
| fc24dbf9b7 | |||
| 7f311551dd | |||
| 1a6c01769e | |||
| 9da4e18099 | |||
| b19e2fbafe | |||
| 7f69857376 | |||
| a64420d700 | |||
| 2ccd3da5b3 | |||
| 845c73af73 | |||
| f7d79209dc | |||
| 0017aef89a | |||
| 7449f81ed4 | |||
| 724e96f0c1 | |||
| 8158e7f1c5 | |||
| 7d7baa70a9 | |||
| 2e3947cc6d | |||
| 54774726b2 | |||
| 2af9fcad68 | |||
| fd79e81fe5 | |||
| 2b5e110719 | |||
| 864c2d9f49 | |||
| 764fe533e8 | |||
| f1f59d770e | |||
| 950baaa9fc | |||
| 5b3aacb4b2 | |||
| d6adc56b3a | |||
| dbe1a4255c | |||
| eed20b2271 | |||
| e70adbb1cb | |||
| 06c22a478f | |||
| 565b0e97d1 | |||
| 00168cb12f | |||
| ffdaa71086 | |||
| 5de2aa1cbf | |||
| 64988ed831 | |||
| fa050ad616 | |||
| d2458f3169 | |||
| 551af0e45a | |||
| 4ac5440a4a | |||
| 7c54d4e62f | |||
| 8ab5915983 | |||
| 877865a4b1 | |||
| 7cf4d37595 | |||
| 80add9f820 | |||
| 12a35c1214 | |||
| 9379d2462e | |||
| c5e8bed1fb | |||
| 4aa7ade32c | |||
| c4ed218a7a | |||
| ff417fac01 | |||
| 0f4207f85e | |||
| f4431ed837 | |||
| 0235cf5d8e | |||
| 8fc8a4e303 | |||
| 943c15927a | |||
| 28f0782b17 | |||
| 09e331a76b | |||
| ce43b09991 | |||
| 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 | |||
| caf908669f | |||
| 39c10e2b6a | |||
| 295164302a | |||
| 9a65d480a8 | |||
| b5a1bf6a84 | |||
| d72c48500b | |||
| 8b2be2639e | |||
| 7295811965 | |||
| a3000019db | |||
| 44235d427d | |||
| 18b4f44605 | |||
| 17a5b7a363 | |||
| 8d008f9dcc | |||
| d32734af0b | |||
| d68f72ec6d | |||
| 37f80e027d | |||
| 7585dec359 | |||
| b98a67223b | |||
| 7c17344a42 | |||
| 3279ce3ea9 | |||
| 7e52e2c691 | |||
| 4e75bd1de6 | |||
| b5d2e56faf | |||
| fb1857f7cc | |||
| 885d45e9b8 | |||
| 070050a48e | |||
| 8c0db16b13 | |||
| 99641bd55c | |||
| 14c999fc82 | |||
| 95bcfa3dce | |||
| 5e345fa7b0 | |||
| 8578a1c101 | |||
| 4100b05fd9 | |||
| e7439e92ed | |||
| d874b51419 | |||
| cebef471a5 | |||
| be9b21edc4 | |||
| 37e07025f7 | |||
| f66c1e4a4f | |||
| 9a6cf7b991 | |||
| caf8cd701e | |||
| eca2c0c5ef | |||
| 11653ef58f | |||
| d05638f64f | |||
| d80586e405 | |||
| a62e757099 | |||
| 274189ee7e | |||
| 18c7aa7f89 | |||
| 735b4e2db1 | |||
| f7326ca7f1 | |||
| 647f054714 | |||
| b6ddccc793 | |||
| 1e54b3e69a | |||
| 8f3de7d022 | |||
| d1436cce38 | |||
| 97afa231ca | |||
| 34e4ead885 | |||
| afaca23f12 | |||
| c6f6a7baed | |||
| 25ac07f8a6 | |||
| 1bac501cbd | |||
| f8135c56b7 | |||
| eb9630251f | |||
| 08dd04a0d6 | |||
| a5c4d2102c | |||
| 3fcabb642e | |||
| 63e8793c7f | |||
| 2a6275cf38 | |||
| 43438dbfab | |||
| eae9e95c66 | |||
| 77c6a06c15 | |||
| 3f49351d38 | |||
| c1e0387f3b | |||
| 52430b0180 | |||
| cc737e54d4 | |||
| a9f9857ab8 | |||
| d7f82db8bd | |||
| 4e2be10574 | |||
| 4e3f975221 | |||
| 5274af7730 | |||
| 1fb34be11e | |||
| 5e1f621c50 | |||
| 9091c8702d | |||
| a2389d741e | |||
| 7541a614b0 | |||
| 2f2b1f874a | |||
| c3125c2e5e | |||
| 3a8ed01b8f | |||
| 35a2dad993 | |||
| 9f04305c12 | |||
| a69d378b84 | |||
| a9ce528744 | |||
| aae7027ac6 | |||
| 0745341d49 | |||
| 68ecc270f7 | |||
| 5132c84dfa | |||
| 0ec648217a | |||
| e603a41fb6 | |||
| 89e4d4ac30 | |||
| 789cb99292 | |||
| 0f440610b6 | |||
| cf8de234be | |||
| cd03ad9207 | |||
| b1f2f2786c | |||
| 1db1b4e5ae | |||
| 3ec4487297 | |||
| 88bd5aefe0 | |||
| a73d79b138 | |||
| cd9a01bdf0 | |||
| 2f65370d19 | |||
| 54de6d4afb | |||
| 858adeb9db | |||
| 109279d0b5 | |||
| c4fb8f74ac | |||
| 528d0a2899 | |||
| faba474def | |||
| 7dc17ae693 | |||
| 482edd0b02 | |||
| d1b723e5e1 | |||
| 89c9ca183f | |||
| 54d8a362fc | |||
| 0c4c1ce878 | |||
| 816657347f | |||
| 8533b5d0a2 | |||
| 2523f845d2 | |||
| 30cffd2563 | |||
| bcb39b9e69 | |||
| a5c94c4630 | |||
| b5813ae18b | |||
| 4919f72060 | |||
| c8b0f96251 | |||
| 3bcd262099 | |||
| ff3de43ec6 | |||
| 79083e7585 | |||
| 29fb07446a | |||
| a816630f2f | |||
| 24ca42c017 | |||
| 39fe92ebc4 | |||
| 905b0331b8 | |||
| 88a8d9043a | |||
| d05e097a78 | |||
| 2d5d1f4a29 | |||
| 85c1a74c1b | |||
| f7e81a8d22 | |||
| 61bc95dc9a | |||
| 53e9d70d3d | |||
| 11dbf03467 | |||
| 4f23dfef64 | |||
| 83fca53d04 | |||
| e93735903e | |||
| ddc7e8b8c7 | |||
| 5377e82ca0 | |||
| fdb46f5445 | |||
| a76cf5cad4 | |||
| 96f5c1c735 | |||
| 307c9ae9c5 | |||
| 83b5774d1a | |||
| ae81a8d118 | |||
| 77ae0d8ef4 | |||
| 2e8744a034 | |||
| f29f6c65a5 | |||
| 4bbf53ce62 | |||
| 9878372866 | |||
| 302255807c | |||
| c60c3fcd3c | |||
| ccf40b53eb | |||
| e3d97ec41b | |||
| cdad977341 | |||
| 717d25cad0 | |||
| 9ffe6ccb6a | |||
| af98879303 | |||
| 57809439a8 | |||
| 44e03627c3 | |||
| 13f8c973f4 | |||
| 00e0d46e92 | |||
| 7fee51081f | |||
| 6b99e44177 | |||
| 87bc397ee0 | |||
| ac3ccf1d7a | |||
| a8ad4695aa | |||
| dae6d1c730 | |||
| 132c25fd3b | |||
| 943a0203f2 | |||
| 6e8a1e0e31 | |||
| 108e1ad5e6 | |||
| a79231c666 | |||
| 97bd93f9bc | |||
| a37528362d | |||
| 4883c6c197 | |||
| 5ef8afe7c4 | |||
| 229cddb5c6 | |||
| bb9cb9a1ef | |||
| eca141eebc | |||
| e7a4070339 | |||
| 9551eff4fb | |||
| 4639187180 | |||
| 5b621d8fe9 | |||
| e3b648ea72 | |||
| 676333ab5a | |||
| bd7aa1cc7b | |||
| 88cfb538bd | |||
| b844634a85 | |||
| c93e948bc8 | |||
| dafb0f7e37 | |||
| d531a1f255 | |||
| 39d6527ea4 | |||
| ffb21d613e | |||
| 46afc9fb08 | |||
| f2a3041ce7 | |||
| d761d0fa9d | |||
| 5f6cac9155 | |||
| 860e73a633 | |||
| 9ad7d9db8f | |||
| fba77ff459 | |||
| 8d5c42d7f8 | |||
| 408dc7358b | |||
| ff5ac3a109 | |||
| 8f637b95ef | |||
| fadaf7ec5c | |||
| 8b8e0eb9ef | |||
| 3bfb274d24 | |||
| 0d3e8914ae | |||
| 5cebe65f38 | |||
| 023c655c6e | |||
| 8bae431503 | |||
| 87eab2b242 | |||
| 86ec00867a | |||
| 2df5d58027 | |||
| 5f327f450d | |||
| 10bd19f4e1 | |||
| 4962678776 | |||
| 82ef4170cb | |||
| fca4c19406 | |||
| bf7bab8ea3 | |||
| ce73bd7501 | |||
| 0239365964 | |||
| 1ff580d9eb | |||
| db9b65d7ed | |||
| c0f33222ea | |||
| 0328057a9d | |||
| d531c5beb5 | |||
| 243fc2664a | |||
| 61b8b320e3 | |||
| 689b447990 | |||
| 1cbf2ab0d7 | |||
| 5c0ed9229d | |||
| 0a29df80d0 | |||
| d2b6ac722b | |||
| 2784e273bc | |||
| 0332b11793 | |||
| 9de3a5a586 | |||
| 5642dc00e1 | |||
| 75f80029f6 | |||
| a93738dd79 | |||
| 4f78634994 | |||
| 1f7ddc865f | |||
| 2c6e68dda7 | |||
| d29a27cca7 | |||
| 90bd34d8ac | |||
| fb2a414839 | |||
| 68c210d184 | |||
| 4e01f75be7 | |||
| 9514c4b811 | |||
| 51d0b94e90 | |||
| 66a3da0694 | |||
| b5562485ab | |||
| c62e1ac5fe | |||
| df6e229cfc | |||
| 92b467ae77 | |||
| 8502b62c77 | |||
| 6b91ae4585 | |||
| 43c2e3a291 | |||
| 08854d9f6b | |||
| 571e6be9ce | |||
| b5aa1554c0 | |||
| 68b02a2348 | |||
| 08661558f2 | |||
| ed608f9f13 | |||
| ac6583906d | |||
| 878e837679 | |||
| 3a421f04ad | |||
| 929793f7a8 | |||
| 5217307132 | |||
| 06ce09d0d7 | |||
| 010627b75a | |||
| 26966f5cdb | |||
| 9be6c1c795 | |||
| 3d44f3eb64 | |||
| b6cf33b353 | |||
| 7437bad834 | |||
| 78df3ae23a | |||
| b5c92f20b4 | |||
| 4fef3195b9 | |||
| 03a53c4fdb | |||
| a60c5f651a | |||
| ddd6d800fc | |||
| 5f711c5e03 | |||
| 417f02d30a | |||
| 654ca2de2b | |||
| 846bb11cc0 | |||
| 29977c4b88 | |||
| 445f7c9a92 | |||
| 0e44126df6 | |||
| 5347b285e5 | |||
| df4ead91b6 | |||
| 73dc97b95d | |||
| 6b6ed949b4 | |||
| cd51481ce1 | |||
| 09ad2ff699 | |||
| df4768132e | |||
| 247dee0966 | |||
| 3db44b3ce1 | |||
| e695e269b1 | |||
| 7562795b4b | |||
| 951d6d9311 | |||
| 7d5cb718cf | |||
| be34eebda7 | |||
| 229812cd95 | |||
| 4c5f8f1ce3 | |||
| f231484cc9 | |||
| 9d1d1a3a54 | |||
| 30369c7701 | |||
| f1f2541e4d | |||
| 2b639a5a14 | |||
| da3789f2ce | |||
| 50373d0a94 | |||
| 72fc514370 | |||
| dae3152c9c | |||
| a2b096b096 | |||
| 6a3fe6edeb | |||
| d2c532e4d5 | |||
| 75ba542c38 | |||
| 221080e281 | |||
| d0547f3d69 | |||
| e48b47f1ec | |||
| 164c9333ef | |||
| e32ba24b6a | |||
| 46a690dfc2 | |||
| e9cfe94dfd | |||
| cf46fd79b0 | |||
| d38adbe7f1 | |||
| 85bc62948b | |||
| f663df87d4 | |||
| edfa70aff0 | |||
| 7584c78c25 | |||
| 1ecca0db74 | |||
| bfd2a8aee2 | |||
| f45af2ba72 | |||
| 17310a9d2b | |||
| e176115273 | |||
| 73ab331506 | |||
| 03772fd85b | |||
| 545162cd4c | |||
| 054bffc0f6 | |||
| ddad5a0523 | |||
| b1ee58b8e8 | |||
| 0f1f99dbf2 | |||
| 5692d43abb | |||
| 512aabc7a4 | |||
| 3b885a492c | |||
| e91058c2eb | |||
| 7e77a1f9cd | |||
| f35d87f685 | |||
| 5637c2f92a | |||
| 94cfb4aad7 | |||
| 676f64b0ef | |||
| 4c47d5b70e | |||
| affaa106d1 | |||
| 76488c58e8 | |||
| 586e8b4c4b | |||
| 2acfe2591f | |||
| 8f06b2fa31 | |||
| c36fc9e49f | |||
| ee56d0051f | |||
| 1de5496e9a | |||
| 61a8b6820f | |||
| 4a9698844e | |||
| 27ff707d54 | |||
| 53aa2f54e5 | |||
| be836dc950 | |||
| 9c13a8a6dd | |||
| 41e5a52509 | |||
| 6cefcf568b | |||
| a07efcc4b7 | |||
| 10ea331909 | |||
| 94c8c61a05 | |||
| 43bbf953c1 | |||
| effee46011 | |||
| 891b068551 | |||
| 32a357c434 | |||
| 6fcc6722c4 | |||
| f9f4fa2972 | |||
| 1ba915cbed | |||
| e79e36bea9 | |||
| cc44fef25d | |||
| 0875c2d557 | |||
| 027c0e46ee | |||
| 34b67d0621 | |||
| b3fded0725 | |||
| dc889cfe80 | |||
| a9b76e8050 | |||
| 897f328b45 | |||
| 8148fad464 | |||
| 95dddcf522 | |||
| d8701a7e41 | |||
| 3bdfd1437b | |||
| 106155a97a | |||
| 59abeccc3e | |||
| 4f883aaeda | |||
| 77df6616a9 | |||
| 171815c9b7 | |||
| b87d6f3c66 | |||
| 52d1c1abfc | |||
| a96f932016 | |||
| 85388b3112 | |||
| 65351959fe | |||
| d07dd71078 | |||
| 5a67a79569 | |||
| 25ecd5072f | |||
| 7c05cf9980 | |||
| 051b710484 | |||
| ae0e6d6516 | |||
| 048c04d0f1 | |||
| 38fd46565e | |||
| 2acad805b3 | |||
| 7f63a84295 | |||
| 1f8235ec98 | |||
| ec0108553f | |||
| 92963ced1f | |||
| 5052302f97 | |||
| a83b790225 | |||
| e8baf75ec2 | |||
| e38d473fdd | |||
| 49a088ac87 | |||
| 51cc0bb209 | |||
| 4ce7739453 | |||
| a02dafb8d7 | |||
| 5c13171e29 | |||
| 681f3c46e7 | |||
| 13a88e712f | |||
| 4177ab6df9 | |||
| 60d472ac56 | |||
| dd6c87e12d | |||
| 27a6bcd7ce | |||
| 94d50c1fdd | |||
| 604024e3e3 | |||
| 4df82206b4 | |||
| 72e314d1c0 | |||
| 61c19405fd | |||
| 4351e8850a | |||
| fa5a042071 | |||
| 18b278fe1d | |||
| eead597c9e | |||
| cea7c28626 | |||
| d4a64d2168 | |||
| a44a309de5 |
+91
-2
@@ -1,2 +1,91 @@
|
||||
/.settings
|
||||
/.project
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
*.class
|
||||
*.dll
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
|
||||
# Packages #
|
||||
############
|
||||
# it's better to unpack these files and commit the raw source
|
||||
# git has its own built in compression methods
|
||||
*.7z
|
||||
*.dmg
|
||||
*.gz
|
||||
*.iso
|
||||
*.jar
|
||||
*.rar
|
||||
*.tar
|
||||
*.zip
|
||||
|
||||
# Logs and databases #
|
||||
######################
|
||||
*.log
|
||||
*.sql
|
||||
*.sqlite
|
||||
|
||||
# OS generated files #
|
||||
######################
|
||||
.DS_Store
|
||||
ehthumbs.db
|
||||
Icon?
|
||||
Thumbs.db
|
||||
|
||||
# build related files #
|
||||
#######################
|
||||
/build/
|
||||
/Util/UUID.cpp
|
||||
/Util/GitDescription.cpp
|
||||
|
||||
# Eclipse related files #
|
||||
#########################
|
||||
.setting*
|
||||
.scb
|
||||
.cproject
|
||||
.project
|
||||
|
||||
# stxxl related files #
|
||||
#######################
|
||||
.stxxl
|
||||
stxxl.log
|
||||
stxxl.errlog
|
||||
|
||||
# compiled protobuffers #
|
||||
#########################
|
||||
/DataStructures/pbf-proto/*.pb.h
|
||||
/DataStructures/pbf-proto/*.pb.cc
|
||||
|
||||
# External Libs #
|
||||
#################
|
||||
/lib/
|
||||
/win/lib
|
||||
|
||||
# Visual Studio Temp + build Files #
|
||||
####################################
|
||||
/win/*.user
|
||||
/win/*.ncb
|
||||
/win/*.suo
|
||||
/win/Debug/
|
||||
/win/Release/
|
||||
/win/bin/
|
||||
/win/bin-debug/
|
||||
/osrm-extract
|
||||
/osrm-io-benchmark
|
||||
/osrm-components
|
||||
/osrm-routed
|
||||
/osrm-datastore
|
||||
/osrm-prepare
|
||||
/osrm-cli
|
||||
/nohup.out
|
||||
|
||||
# Sandbox folder #
|
||||
###################
|
||||
/sandbox/
|
||||
|
||||
/test/profile.lua
|
||||
|
||||
# Deprecated config file #
|
||||
##########################
|
||||
/server.ini
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
# - clang
|
||||
# Make sure CMake is installed
|
||||
install:
|
||||
- sudo apt-get update >/dev/null
|
||||
- sudo apt-get -q install libprotoc-dev libprotobuf7 protobuf-compiler libprotobuf-dev libosmpbf-dev libpng12-dev libbz2-dev libstxxl-dev libstxxl-doc libstxxl1 libxml2-dev libzip-dev libboost1.46-all-dev lua5.1 liblua5.1-0-dev libluabind-dev rubygems osmosis
|
||||
before_script:
|
||||
- sudo gem install bundler
|
||||
- bundle install
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake .. $CMAKEOPTIONS
|
||||
script: make
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
env:
|
||||
- CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Release"
|
||||
- CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Debug"
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- irc.oftc.net#osrm
|
||||
on_success: change
|
||||
on_failure: always
|
||||
use_notice: true
|
||||
skip_join: false
|
||||
|
||||
recipients:
|
||||
- dennis@mapbox.com
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DOUGLASPEUCKER_H_
|
||||
#define DOUGLASPEUCKER_H_
|
||||
|
||||
#include "../DataStructures/Coordinate.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <limits>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
/*This class object computes the bitvector of indicating generalized input points
|
||||
* according to the (Ramer-)Douglas-Peucker algorithm.
|
||||
*
|
||||
* Input is vector of pairs. Each pair consists of the point information and a bit
|
||||
* indicating if the points is present in the generalization.
|
||||
* Note: points may also be pre-selected*/
|
||||
|
||||
class DouglasPeucker {
|
||||
private:
|
||||
typedef std::pair<std::size_t, std::size_t> PairOfPoints;
|
||||
//Stack to simulate the recursion
|
||||
std::stack<PairOfPoints > recursion_stack;
|
||||
|
||||
/**
|
||||
* This distance computation does integer arithmetic only and is about twice as fast as
|
||||
* the other distance function. It is an approximation only, but works more or less ok.
|
||||
*/
|
||||
int fastDistance(
|
||||
const FixedPointCoordinate& point,
|
||||
const FixedPointCoordinate& segA,
|
||||
const FixedPointCoordinate& segB
|
||||
) const;
|
||||
public:
|
||||
void Run(std::vector<SegmentInformation> & input_geometry, const unsigned zoom_level);
|
||||
|
||||
};
|
||||
|
||||
#endif /* DOUGLASPEUCKER_H_ */
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "DouglasPeucker.h"
|
||||
|
||||
//These thresholds are more or less heuristically chosen.
|
||||
static double DouglasPeuckerThresholds[19] = {
|
||||
32000000., //z0
|
||||
16240000., //z1
|
||||
8240000., //z2
|
||||
4240000., //z3
|
||||
2000000., //z4
|
||||
1000000., //z5
|
||||
500000., //z6
|
||||
240000., //z7
|
||||
120000., //z8
|
||||
60000., //z9
|
||||
30000., //z10
|
||||
19000., //z11
|
||||
5000., //z12
|
||||
2000., //z13
|
||||
200., //z14
|
||||
16., //z15
|
||||
6., //z16
|
||||
3., //z17
|
||||
3. //z18
|
||||
};
|
||||
|
||||
/**
|
||||
* This distance computation does integer arithmetic only and is about twice as
|
||||
* fast as the other distance function. It is an approximation only, but works
|
||||
* more or less ok.
|
||||
*/
|
||||
int DouglasPeucker::fastDistance(
|
||||
const FixedPointCoordinate& point,
|
||||
const FixedPointCoordinate& segA,
|
||||
const FixedPointCoordinate& segB
|
||||
) const {
|
||||
const int p2x = (segB.lon - segA.lon);
|
||||
const int p2y = (segB.lat - segA.lat);
|
||||
const int something = p2x*p2x + p2y*p2y;
|
||||
double u = ( 0 == something ? 0 : ((point.lon - segA.lon) * p2x + (point.lat - segA.lat) * p2y) / something);
|
||||
|
||||
if (u > 1) {
|
||||
u = 1;
|
||||
} else if (u < 0) {
|
||||
u = 0;
|
||||
}
|
||||
|
||||
const int x = segA.lon + u * p2x;
|
||||
const int y = segA.lat + u * p2y;
|
||||
|
||||
const int dx = x - point.lon;
|
||||
const int dy = y - point.lat;
|
||||
|
||||
const int dist = (dx*dx + dy*dy);
|
||||
|
||||
return dist;
|
||||
}
|
||||
|
||||
void DouglasPeucker::Run(
|
||||
std::vector<SegmentInformation> & input_geometry,
|
||||
const unsigned zoom_level
|
||||
) {
|
||||
{
|
||||
BOOST_ASSERT_MSG(zoom_level < 19, "unsupported zoom level");
|
||||
BOOST_ASSERT_MSG(1 < input_geometry.size(), "geometry invalid");
|
||||
std::size_t left_border = 0;
|
||||
std::size_t right_border = 1;
|
||||
//Sweep linerarily over array and identify those ranges that need to be checked
|
||||
do {
|
||||
BOOST_ASSERT_MSG(
|
||||
input_geometry[left_border].necessary,
|
||||
"left border must be necessary"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
input_geometry.back().necessary,
|
||||
"right border must be necessary"
|
||||
);
|
||||
|
||||
if(input_geometry[right_border].necessary) {
|
||||
recursion_stack.push(std::make_pair(left_border, right_border));
|
||||
left_border = right_border;
|
||||
}
|
||||
++right_border;
|
||||
} while( right_border < input_geometry.size());
|
||||
}
|
||||
while(!recursion_stack.empty()) {
|
||||
//pop next element
|
||||
const PairOfPoints pair = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
BOOST_ASSERT_MSG(
|
||||
input_geometry[pair.first].necessary,
|
||||
"left border mus be necessary"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
input_geometry[pair.second].necessary,
|
||||
"right border must be necessary"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
pair.second < input_geometry.size(),
|
||||
"right border outside of geometry"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
pair.first < pair.second,
|
||||
"left border on the wrong side"
|
||||
);
|
||||
int max_distance = INT_MIN;
|
||||
|
||||
std::size_t farthest_element_index = pair.second;
|
||||
//find index idx of element with max_distance
|
||||
for(std::size_t i = pair.first+1; i < pair.second; ++i){
|
||||
const int temp_dist = fastDistance(
|
||||
input_geometry[i].location,
|
||||
input_geometry[pair.first].location,
|
||||
input_geometry[pair.second].location
|
||||
);
|
||||
const double distance = std::fabs(temp_dist);
|
||||
if(
|
||||
distance > DouglasPeuckerThresholds[zoom_level] &&
|
||||
distance > max_distance
|
||||
) {
|
||||
farthest_element_index = i;
|
||||
max_distance = distance;
|
||||
}
|
||||
}
|
||||
if (max_distance > DouglasPeuckerThresholds[zoom_level]) {
|
||||
// mark idx as necessary
|
||||
input_geometry[farthest_element_index].necessary = true;
|
||||
if (1 < (farthest_element_index - pair.first) ) {
|
||||
recursion_stack.push(
|
||||
std::make_pair(pair.first, farthest_element_index)
|
||||
);
|
||||
}
|
||||
if (1 < (pair.second - farthest_element_index) ) {
|
||||
recursion_stack.push(
|
||||
std::make_pair(farthest_element_index, pair.second)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ITERATORBASEDCRC32_H_
|
||||
#define ITERATORBASEDCRC32_H_
|
||||
|
||||
#include "../Util/SimpleLogger.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;
|
||||
|
||||
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) {
|
||||
SimpleLogger().Write() << "using hardware based CRC32 computation";
|
||||
return &IteratorbasedCRC32::SSEBasedCRC32; //crc32 hardware accelarated;
|
||||
} else {
|
||||
SimpleLogger().Write() << "using software based CRC32 computation";
|
||||
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,100 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OBJECTTOBASE64_H_
|
||||
#define OBJECTTOBASE64_H_
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/archive/iterators/base64_from_binary.hpp>
|
||||
#include <boost/archive/iterators/binary_from_base64.hpp>
|
||||
#include <boost/archive/iterators/transform_width.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef
|
||||
boost::archive::iterators::base64_from_binary<
|
||||
boost::archive::iterators::transform_width<const char *, 6, 8>
|
||||
> base64_t;
|
||||
|
||||
typedef
|
||||
boost::archive::iterators::transform_width<
|
||||
boost::archive::iterators::binary_from_base64<
|
||||
std::string::const_iterator>, 8, 6
|
||||
> binary_t;
|
||||
|
||||
template<class ObjectT>
|
||||
static void EncodeObjectToBase64(const ObjectT & object, std::string& encoded) {
|
||||
const char * char_ptr_to_object = (const char *)&object;
|
||||
std::vector<unsigned char> data(sizeof(object));
|
||||
std::copy(
|
||||
char_ptr_to_object,
|
||||
char_ptr_to_object + sizeof(ObjectT),
|
||||
data.begin()
|
||||
);
|
||||
|
||||
unsigned char number_of_padded_chars = 0; // is in {0,1,2};
|
||||
while(data.size() % 3 != 0) {
|
||||
++number_of_padded_chars;
|
||||
data.push_back(0x00);
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(
|
||||
0 == data.size() % 3,
|
||||
"base64 input data size is not a multiple of 3!"
|
||||
);
|
||||
encoded.resize(sizeof(ObjectT));
|
||||
encoded.assign(
|
||||
base64_t( &data[0] ),
|
||||
base64_t( &data[0] + (data.size() - number_of_padded_chars) )
|
||||
);
|
||||
replaceAll(encoded, "+", "-");
|
||||
replaceAll(encoded, "/", "_");
|
||||
}
|
||||
|
||||
template<class ObjectT>
|
||||
static void DecodeObjectFromBase64(const std::string& input, ObjectT & object) {
|
||||
try {
|
||||
std::string encoded(input);
|
||||
//replace "-" with "+" and "_" with "/"
|
||||
replaceAll(encoded, "-", "+");
|
||||
replaceAll(encoded, "_", "/");
|
||||
|
||||
std::copy (
|
||||
binary_t( encoded.begin() ),
|
||||
binary_t( encoded.begin() + encoded.length() - 1),
|
||||
(char *)&object
|
||||
);
|
||||
|
||||
} catch(...) { }
|
||||
}
|
||||
|
||||
#endif /* OBJECTTOBASE64_H_ */
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "PolylineCompressor.h"
|
||||
|
||||
void PolylineCompressor::encodeVectorSignedNumber(
|
||||
std::vector<int> & numbers,
|
||||
std::string & output
|
||||
) const {
|
||||
for(unsigned i = 0; i < numbers.size(); ++i) {
|
||||
numbers[i] <<= 1;
|
||||
if (numbers[i] < 0) {
|
||||
numbers[i] = ~(numbers[i]);
|
||||
}
|
||||
}
|
||||
for(unsigned i = 0; i < numbers.size(); ++i) {
|
||||
encodeNumber(numbers[i], output);
|
||||
}
|
||||
}
|
||||
|
||||
void PolylineCompressor::encodeNumber(int number_to_encode, std::string & output) const {
|
||||
while (number_to_encode >= 0x20) {
|
||||
int nextValue = (0x20 | (number_to_encode & 0x1f)) + 63;
|
||||
output += static_cast<char>(nextValue);
|
||||
if(92 == nextValue) {
|
||||
output += static_cast<char>(nextValue);
|
||||
}
|
||||
number_to_encode >>= 5;
|
||||
}
|
||||
|
||||
number_to_encode += 63;
|
||||
output += static_cast<char>(number_to_encode);
|
||||
if(92 == number_to_encode) {
|
||||
output += static_cast<char>(number_to_encode);
|
||||
}
|
||||
}
|
||||
|
||||
void PolylineCompressor::printEncodedString(
|
||||
const std::vector<SegmentInformation> & polyline,
|
||||
std::string & output
|
||||
) const {
|
||||
std::vector<int> deltaNumbers;
|
||||
output += "\"";
|
||||
if(!polyline.empty()) {
|
||||
FixedPointCoordinate lastCoordinate = polyline[0].location;
|
||||
deltaNumbers.push_back( lastCoordinate.lat );
|
||||
deltaNumbers.push_back( lastCoordinate.lon );
|
||||
for(unsigned i = 1; i < polyline.size(); ++i) {
|
||||
if(!polyline[i].necessary) {
|
||||
continue;
|
||||
}
|
||||
deltaNumbers.push_back(polyline[i].location.lat - lastCoordinate.lat);
|
||||
deltaNumbers.push_back(polyline[i].location.lon - lastCoordinate.lon);
|
||||
lastCoordinate = polyline[i].location;
|
||||
}
|
||||
encodeVectorSignedNumber(deltaNumbers, output);
|
||||
}
|
||||
output += "\"";
|
||||
|
||||
}
|
||||
|
||||
void PolylineCompressor::printEncodedString(
|
||||
const std::vector<FixedPointCoordinate>& polyline,
|
||||
std::string &output
|
||||
) const {
|
||||
std::vector<int> deltaNumbers(2*polyline.size());
|
||||
output += "\"";
|
||||
if(!polyline.empty()) {
|
||||
deltaNumbers[0] = polyline[0].lat;
|
||||
deltaNumbers[1] = polyline[0].lon;
|
||||
for(unsigned i = 1; i < polyline.size(); ++i) {
|
||||
deltaNumbers[(2*i)] = (polyline[i].lat - polyline[i-1].lat);
|
||||
deltaNumbers[(2*i)+1] = (polyline[i].lon - polyline[i-1].lon);
|
||||
}
|
||||
encodeVectorSignedNumber(deltaNumbers, output);
|
||||
}
|
||||
output += "\"";
|
||||
}
|
||||
|
||||
void PolylineCompressor::printUnencodedString(
|
||||
const std::vector<FixedPointCoordinate> & polyline,
|
||||
std::string & output
|
||||
) const {
|
||||
output += "[";
|
||||
std::string tmp;
|
||||
for(unsigned i = 0; i < polyline.size(); i++) {
|
||||
convertInternalLatLonToString(polyline[i].lat, tmp);
|
||||
output += "[";
|
||||
output += tmp;
|
||||
convertInternalLatLonToString(polyline[i].lon, tmp);
|
||||
output += ", ";
|
||||
output += tmp;
|
||||
output += "]";
|
||||
if( i < polyline.size()-1 ) {
|
||||
output += ",";
|
||||
}
|
||||
}
|
||||
output += "]";
|
||||
}
|
||||
|
||||
void PolylineCompressor::printUnencodedString(
|
||||
const std::vector<SegmentInformation> & polyline,
|
||||
std::string & output
|
||||
) const {
|
||||
output += "[";
|
||||
std::string tmp;
|
||||
for(unsigned i = 0; i < polyline.size(); i++) {
|
||||
if(!polyline[i].necessary) {
|
||||
continue;
|
||||
}
|
||||
convertInternalLatLonToString(polyline[i].location.lat, tmp);
|
||||
output += "[";
|
||||
output += tmp;
|
||||
convertInternalLatLonToString(polyline[i].location.lon, tmp);
|
||||
output += ", ";
|
||||
output += tmp;
|
||||
output += "]";
|
||||
if( i < polyline.size()-1 ) {
|
||||
output += ",";
|
||||
}
|
||||
}
|
||||
output += "]";
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef POLYLINECOMPRESSOR_H_
|
||||
#define POLYLINECOMPRESSOR_H_
|
||||
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class PolylineCompressor {
|
||||
private:
|
||||
void encodeVectorSignedNumber(
|
||||
std::vector<int> & numbers,
|
||||
std::string & output
|
||||
) const;
|
||||
|
||||
void encodeNumber(int number_to_encode, std::string & output) const;
|
||||
|
||||
public:
|
||||
void printEncodedString(
|
||||
const std::vector<SegmentInformation> & polyline,
|
||||
std::string & output
|
||||
) const;
|
||||
|
||||
void printEncodedString(
|
||||
const std::vector<FixedPointCoordinate>& polyline,
|
||||
std::string &output
|
||||
) const;
|
||||
|
||||
void printUnencodedString(
|
||||
const std::vector<FixedPointCoordinate> & polyline,
|
||||
std::string & output
|
||||
) const;
|
||||
|
||||
void printUnencodedString(
|
||||
const std::vector<SegmentInformation> & polyline,
|
||||
std::string & output
|
||||
) const;
|
||||
|
||||
};
|
||||
|
||||
#endif /* POLYLINECOMPRESSOR_H_ */
|
||||
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef STRONGLYCONNECTEDCOMPONENTS_H_
|
||||
#define STRONGLYCONNECTEDCOMPONENTS_H_
|
||||
|
||||
#include "../DataStructures/Coordinate.h"
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../DataStructures/ImportEdge.h"
|
||||
#include "../DataStructures/QueryNode.h"
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/integer.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <gdal.h>
|
||||
#include <ogrsf_frmts.h>
|
||||
#else
|
||||
#include <gdal/gdal.h>
|
||||
#include <gdal/ogrsf_frmts.h>
|
||||
#endif
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
class TarjanSCC {
|
||||
private:
|
||||
|
||||
struct TarjanNode {
|
||||
TarjanNode() : index(UINT_MAX), lowlink(UINT_MAX), onStack(false) {}
|
||||
unsigned index;
|
||||
unsigned lowlink;
|
||||
bool onStack;
|
||||
};
|
||||
|
||||
struct TarjanEdgeData {
|
||||
int distance;
|
||||
unsigned nameID:31;
|
||||
bool shortcut:1;
|
||||
short type;
|
||||
bool isAccessRestricted:1;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
bool roundabout:1;
|
||||
bool ignoreInGrid:1;
|
||||
bool reversedEdge:1;
|
||||
};
|
||||
|
||||
struct TarjanStackFrame {
|
||||
explicit TarjanStackFrame(
|
||||
NodeID v,
|
||||
NodeID parent
|
||||
) : v(v), parent(parent) { }
|
||||
NodeID v;
|
||||
NodeID parent;
|
||||
};
|
||||
|
||||
typedef DynamicGraph<TarjanEdgeData> TarjanDynamicGraph;
|
||||
typedef TarjanDynamicGraph::InputEdge TarjanEdge;
|
||||
typedef std::pair<NodeID, NodeID> RestrictionSource;
|
||||
typedef std::pair<NodeID, bool> restriction_target;
|
||||
typedef std::vector<restriction_target> EmanatingRestrictionsVector;
|
||||
typedef boost::unordered_map<RestrictionSource, unsigned > RestrictionMap;
|
||||
|
||||
std::vector<NodeInfo> m_coordinate_list;
|
||||
std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
|
||||
boost::shared_ptr<TarjanDynamicGraph> m_node_based_graph;
|
||||
boost::unordered_set<NodeID> m_barrier_node_list;
|
||||
boost::unordered_set<NodeID> m_traffic_light_list;
|
||||
unsigned m_restriction_counter;
|
||||
RestrictionMap m_restriction_map;
|
||||
|
||||
struct EdgeBasedNode {
|
||||
bool operator<(const EdgeBasedNode & other) const {
|
||||
return other.id < id;
|
||||
}
|
||||
bool operator==(const EdgeBasedNode & other) const {
|
||||
return id == other.id;
|
||||
}
|
||||
NodeID id;
|
||||
int lat1;
|
||||
int lat2;
|
||||
int lon1;
|
||||
int lon2:31;
|
||||
bool belongsToTinyComponent:1;
|
||||
NodeID nameID;
|
||||
unsigned weight:31;
|
||||
bool ignoreInGrid:1;
|
||||
};
|
||||
|
||||
public:
|
||||
TarjanSCC(
|
||||
int number_of_nodes,
|
||||
std::vector<NodeBasedEdge> & input_edges,
|
||||
std::vector<NodeID> & bn,
|
||||
std::vector<NodeID> & tl,
|
||||
std::vector<TurnRestriction> & irs,
|
||||
std::vector<NodeInfo> & nI
|
||||
) :
|
||||
m_coordinate_list(nI),
|
||||
m_restriction_counter(irs.size())
|
||||
{
|
||||
BOOST_FOREACH(const TurnRestriction & restriction, irs) {
|
||||
std::pair<NodeID, NodeID> restrictionSource = std::make_pair(
|
||||
restriction.fromNode, restriction.viaNode
|
||||
);
|
||||
unsigned index;
|
||||
RestrictionMap::iterator restriction_iterator = m_restriction_map.find(restrictionSource);
|
||||
if(restriction_iterator == m_restriction_map.end()) {
|
||||
index = m_restriction_bucket_list.size();
|
||||
m_restriction_bucket_list.resize(index+1);
|
||||
m_restriction_map[restrictionSource] = index;
|
||||
} else {
|
||||
index = restriction_iterator->second;
|
||||
//Map already contains an is_only_*-restriction
|
||||
if(m_restriction_bucket_list.at(index).begin()->second) {
|
||||
continue;
|
||||
} else if(restriction.flags.isOnly) {
|
||||
//We are going to insert an is_only_*-restriction. There can be only one.
|
||||
m_restriction_bucket_list.at(index).clear();
|
||||
}
|
||||
}
|
||||
|
||||
m_restriction_bucket_list.at(index).push_back(
|
||||
std::make_pair(restriction.toNode, restriction.flags.isOnly)
|
||||
);
|
||||
}
|
||||
|
||||
m_barrier_node_list.insert(bn.begin(), bn.end());
|
||||
m_traffic_light_list.insert(tl.begin(), tl.end());
|
||||
|
||||
DeallocatingVector< TarjanEdge > edge_list;
|
||||
BOOST_FOREACH(const NodeBasedEdge & input_edge, input_edges) {
|
||||
TarjanEdge edge;
|
||||
if(!input_edge.isForward()) {
|
||||
edge.source = input_edge.target();
|
||||
edge.target = input_edge.source();
|
||||
edge.data.backward = input_edge.isForward();
|
||||
edge.data.forward = input_edge.isBackward();
|
||||
} else {
|
||||
edge.source = input_edge.source();
|
||||
edge.target = input_edge.target();
|
||||
edge.data.forward = input_edge.isForward();
|
||||
edge.data.backward = input_edge.isBackward();
|
||||
}
|
||||
if(edge.source == edge.target) {
|
||||
continue;
|
||||
}
|
||||
|
||||
edge.data.distance = (std::max)((int)input_edge.weight(), 1 );
|
||||
BOOST_ASSERT( edge.data.distance > 0 );
|
||||
edge.data.shortcut = false;
|
||||
edge.data.roundabout = input_edge.isRoundabout();
|
||||
edge.data.ignoreInGrid = input_edge.ignoreInGrid();
|
||||
edge.data.nameID = input_edge.name();
|
||||
edge.data.type = input_edge.type();
|
||||
edge.data.isAccessRestricted = input_edge.isAccessRestricted();
|
||||
edge.data.reversedEdge = false;
|
||||
edge_list.push_back( edge );
|
||||
if( edge.data.backward ) {
|
||||
std::swap( edge.source, edge.target );
|
||||
edge.data.forward = input_edge.isBackward();
|
||||
edge.data.backward = input_edge.isForward();
|
||||
edge.data.reversedEdge = true;
|
||||
edge_list.push_back( edge );
|
||||
}
|
||||
}
|
||||
std::vector<NodeBasedEdge>().swap(input_edges);
|
||||
BOOST_ASSERT_MSG(
|
||||
0 == input_edges.size() && 0 == input_edges.capacity(),
|
||||
"input edge vector not properly deallocated"
|
||||
);
|
||||
|
||||
std::sort( edge_list.begin(), edge_list.end() );
|
||||
|
||||
m_node_based_graph = boost::make_shared<TarjanDynamicGraph>(
|
||||
number_of_nodes,
|
||||
edge_list
|
||||
);
|
||||
}
|
||||
|
||||
~TarjanSCC() {
|
||||
m_node_based_graph.reset();
|
||||
}
|
||||
|
||||
void Run() {
|
||||
//remove files from previous run if exist
|
||||
DeleteFileIfExists("component.dbf");
|
||||
DeleteFileIfExists("component.shx");
|
||||
DeleteFileIfExists("component.shp");
|
||||
|
||||
Percent p(m_node_based_graph->GetNumberOfNodes());
|
||||
|
||||
OGRRegisterAll();
|
||||
|
||||
const char *pszDriverName = "ESRI Shapefile";
|
||||
OGRSFDriver * poDriver = OGRSFDriverRegistrar::GetRegistrar()->
|
||||
GetDriverByName( pszDriverName );
|
||||
if( NULL == poDriver ) {
|
||||
throw OSRMException("ESRI Shapefile driver not available");
|
||||
}
|
||||
OGRDataSource * poDS = poDriver->CreateDataSource(
|
||||
"component.shp",
|
||||
NULL
|
||||
);
|
||||
|
||||
if( NULL == poDS ) {
|
||||
throw OSRMException("Creation of output file failed");
|
||||
}
|
||||
|
||||
OGRLayer * poLayer = poDS->CreateLayer(
|
||||
"component",
|
||||
NULL,
|
||||
wkbLineString,
|
||||
NULL
|
||||
);
|
||||
|
||||
if( NULL == poLayer ) {
|
||||
throw OSRMException("Layer creation failed.");
|
||||
}
|
||||
|
||||
//The following is a hack to distinguish between stuff that happens
|
||||
//before the recursive call and stuff that happens after
|
||||
std::stack<std::pair<bool, TarjanStackFrame> > recursion_stack;
|
||||
//true = stuff before, false = stuff after call
|
||||
std::stack<NodeID> tarjan_stack;
|
||||
std::vector<unsigned> components_index(
|
||||
m_node_based_graph->GetNumberOfNodes(),
|
||||
UINT_MAX
|
||||
);
|
||||
std::vector<NodeID> component_size_vector;
|
||||
std::vector<TarjanNode> tarjan_node_list(
|
||||
m_node_based_graph->GetNumberOfNodes()
|
||||
);
|
||||
unsigned component_index = 0, size_of_current_component = 0;
|
||||
int index = 0;
|
||||
for(
|
||||
NodeID node = 0, last_node = m_node_based_graph->GetNumberOfNodes();
|
||||
node < last_node;
|
||||
++node
|
||||
) {
|
||||
if(UINT_MAX == components_index[node]) {
|
||||
recursion_stack.push(
|
||||
std::make_pair(true, TarjanStackFrame(node,node))
|
||||
);
|
||||
}
|
||||
|
||||
while(!recursion_stack.empty()) {
|
||||
bool before_recursion = recursion_stack.top().first;
|
||||
TarjanStackFrame currentFrame = recursion_stack.top().second;
|
||||
NodeID v = currentFrame.v;
|
||||
recursion_stack.pop();
|
||||
|
||||
if(before_recursion) {
|
||||
//Mark frame to handle tail of recursion
|
||||
recursion_stack.push(std::make_pair(false, currentFrame));
|
||||
|
||||
//Mark essential information for SCC
|
||||
tarjan_node_list[v].index = index;
|
||||
tarjan_node_list[v].lowlink = index;
|
||||
tarjan_stack.push(v);
|
||||
tarjan_node_list[v].onStack = true;
|
||||
++index;
|
||||
|
||||
//Traverse outgoing edges
|
||||
for(
|
||||
TarjanDynamicGraph::EdgeIterator e2 = m_node_based_graph->BeginEdges(v);
|
||||
e2 < m_node_based_graph->EndEdges(v);
|
||||
++e2
|
||||
) {
|
||||
const TarjanDynamicGraph::NodeIterator vprime =
|
||||
m_node_based_graph->GetTarget(e2);
|
||||
if(UINT_MAX == tarjan_node_list[vprime].index) {
|
||||
recursion_stack.push(
|
||||
std::make_pair(
|
||||
true,
|
||||
TarjanStackFrame(vprime, v)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
if(
|
||||
tarjan_node_list[vprime].onStack &&
|
||||
tarjan_node_list[vprime].index < tarjan_node_list[v].lowlink
|
||||
) {
|
||||
tarjan_node_list[v].lowlink = tarjan_node_list[vprime].index;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tarjan_node_list[currentFrame.parent].lowlink =
|
||||
std::min(
|
||||
tarjan_node_list[currentFrame.parent].lowlink,
|
||||
tarjan_node_list[v].lowlink
|
||||
);
|
||||
//after recursion, lets do cycle checking
|
||||
//Check if we found a cycle. This is the bottom part of the recursion
|
||||
if(tarjan_node_list[v].lowlink == tarjan_node_list[v].index) {
|
||||
NodeID vprime;
|
||||
do {
|
||||
vprime = tarjan_stack.top(); tarjan_stack.pop();
|
||||
tarjan_node_list[vprime].onStack = false;
|
||||
components_index[vprime] = component_index;
|
||||
++size_of_current_component;
|
||||
} while( v != vprime);
|
||||
|
||||
component_size_vector.push_back(size_of_current_component);
|
||||
|
||||
if(size_of_current_component > 1000) {
|
||||
SimpleLogger().Write() <<
|
||||
"large component [" << component_index << "]=" <<
|
||||
size_of_current_component;
|
||||
}
|
||||
|
||||
++component_index;
|
||||
size_of_current_component = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleLogger().Write() <<
|
||||
"identified: " << component_size_vector.size() <<
|
||||
" many components, marking small components";
|
||||
|
||||
unsigned size_one_counter = 0;
|
||||
for(unsigned i = 0, end = component_size_vector.size(); i < end; ++i){
|
||||
if(1 == component_size_vector[i]) {
|
||||
++size_one_counter;
|
||||
}
|
||||
}
|
||||
|
||||
SimpleLogger().Write() <<
|
||||
"identified " << size_one_counter << " SCCs of size 1";
|
||||
|
||||
uint64_t total_network_distance = 0;
|
||||
p.reinit(m_node_based_graph->GetNumberOfNodes());
|
||||
for(
|
||||
TarjanDynamicGraph::NodeIterator u = 0, last_u_node = m_node_based_graph->GetNumberOfNodes();
|
||||
u < last_u_node;
|
||||
++u
|
||||
) {
|
||||
p.printIncrement();
|
||||
for(
|
||||
TarjanDynamicGraph::EdgeIterator e1 = m_node_based_graph->BeginEdges(u), last_edge = m_node_based_graph->EndEdges(u);
|
||||
e1 < last_edge;
|
||||
++e1
|
||||
) {
|
||||
if(!m_node_based_graph->GetEdgeData(e1).reversedEdge) {
|
||||
continue;
|
||||
}
|
||||
const TarjanDynamicGraph::NodeIterator v = m_node_based_graph->GetTarget(e1);
|
||||
|
||||
total_network_distance += 100*ApproximateDistance(
|
||||
m_coordinate_list[u].lat,
|
||||
m_coordinate_list[u].lon,
|
||||
m_coordinate_list[v].lat,
|
||||
m_coordinate_list[v].lon
|
||||
);
|
||||
|
||||
if( SHRT_MAX != m_node_based_graph->GetEdgeData(e1).type ) {
|
||||
BOOST_ASSERT(e1 != UINT_MAX);
|
||||
BOOST_ASSERT(u != UINT_MAX);
|
||||
BOOST_ASSERT(v != UINT_MAX);
|
||||
|
||||
const unsigned size_of_containing_component =
|
||||
std::min(
|
||||
component_size_vector[components_index[u]],
|
||||
component_size_vector[components_index[v]]
|
||||
);
|
||||
|
||||
//edges that end on bollard nodes may actually be in two distinct components
|
||||
if(size_of_containing_component < 10) {
|
||||
OGRLineString lineString;
|
||||
lineString.addPoint(
|
||||
m_coordinate_list[u].lon/COORDINATE_PRECISION,
|
||||
m_coordinate_list[u].lat/COORDINATE_PRECISION
|
||||
);
|
||||
lineString.addPoint(
|
||||
m_coordinate_list[v].lon/COORDINATE_PRECISION,
|
||||
m_coordinate_list[v].lat/COORDINATE_PRECISION
|
||||
);
|
||||
|
||||
OGRFeature * poFeature = OGRFeature::CreateFeature(
|
||||
poLayer->GetLayerDefn()
|
||||
);
|
||||
|
||||
poFeature->SetGeometry( &lineString );
|
||||
if( OGRERR_NONE != poLayer->CreateFeature(poFeature) ) {
|
||||
throw OSRMException(
|
||||
"Failed to create feature in shapefile."
|
||||
);
|
||||
}
|
||||
OGRFeature::DestroyFeature( poFeature );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OGRDataSource::DestroyDataSource( poDS );
|
||||
std::vector<NodeID>().swap(component_size_vector);
|
||||
BOOST_ASSERT_MSG(
|
||||
0 == component_size_vector.size() &&
|
||||
0 == component_size_vector.capacity(),
|
||||
"component_size_vector not properly deallocated"
|
||||
);
|
||||
|
||||
std::vector<NodeID>().swap(components_index);
|
||||
BOOST_ASSERT_MSG(
|
||||
0 == components_index.size() && 0 == components_index.capacity(),
|
||||
"icomponents_index not properly deallocated"
|
||||
);
|
||||
|
||||
SimpleLogger().Write()
|
||||
<< "total network distance: " <<
|
||||
(uint64_t)total_network_distance/100/1000. <<
|
||||
" km";
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const {
|
||||
std::pair < NodeID, NodeID > restriction_source = std::make_pair(u, v);
|
||||
RestrictionMap::const_iterator restriction_iterator = m_restriction_map.find(restriction_source);
|
||||
if (restriction_iterator != m_restriction_map.end()) {
|
||||
const unsigned index = restriction_iterator->second;
|
||||
BOOST_FOREACH(
|
||||
const RestrictionSource & restriction_target,
|
||||
m_restriction_bucket_list.at(index)
|
||||
) {
|
||||
if(restriction_target.second) {
|
||||
return restriction_target.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
bool CheckIfTurnIsRestricted(
|
||||
const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w
|
||||
) const {
|
||||
//only add an edge if turn is not a U-turn except it is the end of dead-end street.
|
||||
std::pair < NodeID, NodeID > restriction_source = std::make_pair(u, v);
|
||||
RestrictionMap::const_iterator restriction_iterator = m_restriction_map.find(restriction_source);
|
||||
if (restriction_iterator != m_restriction_map.end()) {
|
||||
const unsigned index = restriction_iterator->second;
|
||||
BOOST_FOREACH(
|
||||
const restriction_target & restriction_target,
|
||||
m_restriction_bucket_list.at(index)
|
||||
) {
|
||||
if(w == restriction_target.first) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeleteFileIfExists(const std::string & file_name) const {
|
||||
if (boost::filesystem::exists(file_name) ) {
|
||||
boost::filesystem::remove(file_name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* STRONGLYCONNECTEDCOMPONENTS_H_ */
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
project(OSRM)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||
include(GetGitRevisionDescription)
|
||||
git_describe(GIT_DESCRIPTION)
|
||||
|
||||
TRY_RUN(SHARED_LIBRARY_PATH_TYPE SHARED_LIBRARY_PATH_INFO_COMPILED ${PROJECT_BINARY_DIR}/CMakeTmp ${PROJECT_SOURCE_DIR}/cmake/size.cpp OUTPUT_VARIABLE IS_64_SYSTEM)
|
||||
if(IS_64_SYSTEM)
|
||||
message(STATUS "System supports 64 bits.")
|
||||
set( HAS64BITS 1 )
|
||||
else(IS_64_SYSTEM)
|
||||
MESSAGE(WARNING "Compiling on a 32 bit system is unsupported!")
|
||||
set( HAS64BITS 0 )
|
||||
endif(IS_64_SYSTEM)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/UUID.cpp UUID.cpp.alwaysbuild
|
||||
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/UUID-Config.cmake
|
||||
DEPENDS
|
||||
${CMAKE_SOURCE_DIR}/Util/UUID.cpp.in
|
||||
${CMAKE_SOURCE_DIR}/cmake/UUID-Config.cmake
|
||||
COMMENT "Configuring UUID.cpp"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(UUIDConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/UUID.cpp )
|
||||
|
||||
set(BOOST_COMPONENTS filesystem iostreams program_options regex system thread)
|
||||
|
||||
configure_file(Util/GitDescription.cpp.in ${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp)
|
||||
file(GLOB ExtractorGlob Extractor/*.cpp)
|
||||
set(ExtractorSources extractor.cpp ${ExtractorGlob})
|
||||
add_executable(osrm-extract ${ExtractorSources} )
|
||||
|
||||
file( GLOB PrepareGlob Contractor/*.cpp )
|
||||
set( PrepareSources prepare.cpp ${PrepareGlob} )
|
||||
add_executable( osrm-prepare ${PrepareSources} )
|
||||
|
||||
file(GLOB ServerGlob Server/*.cpp)
|
||||
file(GLOB DescriptorGlob Descriptors/*.cpp)
|
||||
file(GLOB DatastructureGlob DataStructures/*.cpp)
|
||||
file(GLOB AlgorithmGlob Algorithms/*.cpp)
|
||||
file(GLOB HttpGlob Server/Http/*.cpp)
|
||||
file(GLOB LibOSRMGlob Library/*.cpp)
|
||||
|
||||
set(OSRMSources ${LibOSRMGlob} ${DescriptorGlob} ${DatastructureGlob} ${AlgorithmGlob} ${HttpGlob})
|
||||
add_library( OSRM SHARED ${OSRMSources} )
|
||||
add_library( UUID STATIC Util/UUID.cpp )
|
||||
add_library( GITDESCRIPTION STATIC Util/GitDescription.cpp )
|
||||
add_dependencies( UUID UUIDConfigure )
|
||||
add_dependencies( GITDESCRIPTION GIT_DESCRIPTION )
|
||||
|
||||
add_executable(osrm-routed routed.cpp ${ServerGlob})
|
||||
set_target_properties(osrm-routed PROPERTIES COMPILE_FLAGS -DROUTED)
|
||||
add_executable(osrm-datastore datastore.cpp)
|
||||
|
||||
# Check the release mode
|
||||
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif(NOT CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
message(STATUS "Configuring OSRM in debug mode")
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
if(CMAKE_BUILD_TYPE MATCHES Release)
|
||||
message(STATUS "Configuring OSRM in release mode")
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Release)
|
||||
|
||||
# set compile switches
|
||||
if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# not using Visual Studio C++
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fPIC")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fPIC")
|
||||
endif()
|
||||
|
||||
# Configuring compilers
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
# using Clang
|
||||
set(CMAKE_CXX_FLAGS "-Wall -Wno-unknown-pragmas -Wno-unneeded-internal-declaration")
|
||||
message(STATUS "OpenMP parallelization not available using clang++")
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
# using GCC
|
||||
set(CMAKE_CXX_FLAGS "-Wall -fopenmp -pedantic")
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
|
||||
# using Intel C++
|
||||
set(CMAKE_CXX_FLAGS "-static-intel -wd10237 -Wall -openmp -ipo")
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
endif()
|
||||
|
||||
# Configuring other platform dependencies
|
||||
if(APPLE)
|
||||
SET(CMAKE_OSX_ARCHITECTURES "x86_64")
|
||||
message(STATUS "Set Architecture to x64 on OS X")
|
||||
EXEC_PROGRAM(uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION)
|
||||
STRING(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION})
|
||||
IF (DARWIN_VERSION GREATER 12)
|
||||
MESSAGE(STATUS "Activating -std=c++11 flag for >= OS X 10.9")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
|
||||
ENDIF (DARWIN_VERSION GREATER 12)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries( osrm-datastore rt )
|
||||
target_link_libraries( OSRM rt )
|
||||
endif(UNIX AND NOT APPLE)
|
||||
|
||||
#Check Boost
|
||||
set(BOOST_MIN_VERSION "1.44.0")
|
||||
find_package( Boost ${BOOST_MIN_VERSION} COMPONENTS ${BOOST_COMPONENTS} REQUIRED )
|
||||
if (NOT Boost_FOUND)
|
||||
message(FATAL_ERROR "Fatal error: Boost (version >= 1.44.0) required.\n")
|
||||
endif (NOT Boost_FOUND)
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
|
||||
IF( APPLE )
|
||||
target_link_libraries( OSRM ${Boost_LIBRARIES} UUID )
|
||||
ELSE( APPLE )
|
||||
target_link_libraries( OSRM ${Boost_LIBRARIES} )
|
||||
ENDIF( APPLE )
|
||||
target_link_libraries( osrm-extract ${Boost_LIBRARIES} UUID GITDESCRIPTION )
|
||||
target_link_libraries( osrm-prepare ${Boost_LIBRARIES} UUID GITDESCRIPTION )
|
||||
target_link_libraries( osrm-routed ${Boost_LIBRARIES} OSRM UUID GITDESCRIPTION )
|
||||
target_link_libraries( osrm-datastore ${Boost_LIBRARIES} UUID GITDESCRIPTION )
|
||||
|
||||
find_package ( BZip2 REQUIRED )
|
||||
include_directories(${BZIP_INCLUDE_DIRS})
|
||||
target_link_libraries (osrm-extract ${BZIP2_LIBRARIES})
|
||||
|
||||
find_package( ZLIB REQUIRED )
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
target_link_libraries (osrm-extract ${ZLIB_LIBRARY})
|
||||
target_link_libraries (osrm-routed ${ZLIB_LIBRARY})
|
||||
|
||||
find_package( Threads REQUIRED )
|
||||
target_link_libraries (osrm-extract ${Threads_LIBRARY})
|
||||
|
||||
find_package( Lua52 )
|
||||
IF ( NOT LUA52_FOUND )
|
||||
find_package( Lua51 REQUIRED )
|
||||
IF (NOT APPLE)
|
||||
find_package( LuaJIT 5.1 )
|
||||
ENDIF ( NOT APPLE )
|
||||
ELSE( NOT LUA52_FOUND )
|
||||
IF(NOT APPLE)
|
||||
find_package( LuaJIT 5.2 )
|
||||
ENDIF(NOT APPLE)
|
||||
ENDIF( NOT LUA52_FOUND )
|
||||
|
||||
IF ( LUAJIT_FOUND )
|
||||
target_link_libraries( osrm-extract ${LUAJIT_LIBRARIES} )
|
||||
target_link_libraries( osrm-prepare ${LUAJIT_LIBRARIES} )
|
||||
ELSE ()
|
||||
target_link_libraries( osrm-extract ${LUA_LIBRARY} )
|
||||
target_link_libraries( osrm-prepare ${LUA_LIBRARY} )
|
||||
ENDIF ()
|
||||
include_directories(${LUA_INCLUDE_DIR})
|
||||
|
||||
|
||||
find_package( LibXml2 REQUIRED )
|
||||
include_directories(${LIBXML2_INCLUDE_DIR})
|
||||
target_link_libraries (osrm-extract ${LIBXML2_LIBRARIES})
|
||||
|
||||
find_package( Luabind REQUIRED )
|
||||
include_directories(${LUABIND_INCLUDE_DIR})
|
||||
target_link_libraries (osrm-extract ${LUABIND_LIBRARY})
|
||||
target_link_libraries (osrm-prepare ${LUABIND_LIBRARY})
|
||||
|
||||
find_package( Protobuf REQUIRED )
|
||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||
target_link_libraries (osrm-extract ${PROTOBUF_LIBRARY})
|
||||
target_link_libraries (osrm-prepare ${PROTOBUF_LIBRARY})
|
||||
|
||||
find_package( STXXL REQUIRED )
|
||||
include_directories(${STXXL_INCLUDE_DIR})
|
||||
target_link_libraries (OSRM ${STXXL_LIBRARY})
|
||||
target_link_libraries (osrm-extract ${STXXL_LIBRARY})
|
||||
target_link_libraries (osrm-prepare ${STXXL_LIBRARY})
|
||||
|
||||
find_package( OSMPBF REQUIRED )
|
||||
include_directories(${OSMPBF_INCLUDE_DIR})
|
||||
target_link_libraries (osrm-extract ${OSMPBF_LIBRARY})
|
||||
target_link_libraries (osrm-prepare ${OSMPBF_LIBRARY})
|
||||
|
||||
if(WITH_TOOLS)
|
||||
message(STATUS "Activating OSRM internal tools")
|
||||
find_package( GDAL )
|
||||
if(GDAL_FOUND)
|
||||
add_executable(osrm-components Tools/componentAnalysis.cpp)
|
||||
include_directories(${GDAL_INCLUDE_DIR})
|
||||
target_link_libraries(
|
||||
osrm-components ${GDAL_LIBRARIES} ${Boost_LIBRARIES} UUID GITDESCRIPTION
|
||||
)
|
||||
endif(GDAL_FOUND)
|
||||
add_executable ( osrm-cli Tools/simpleclient.cpp)
|
||||
target_link_libraries( osrm-cli ${Boost_LIBRARIES} OSRM UUID GITDESCRIPTION )
|
||||
add_executable ( osrm-io-benchmark Tools/io-benchmark.cpp )
|
||||
target_link_libraries( osrm-io-benchmark ${Boost_LIBRARIES} GITDESCRIPTION)
|
||||
add_executable ( osrm-unlock-all Tools/unlock_all_mutexes.cpp )
|
||||
target_link_libraries( osrm-unlock-all ${Boost_LIBRARIES} GITDESCRIPTION)
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries( osrm-unlock-all rt )
|
||||
endif(UNIX AND NOT APPLE)
|
||||
endif(WITH_TOOLS)
|
||||
@@ -0,0 +1,792 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CONTRACTOR_H_INCLUDED
|
||||
#define CONTRACTOR_H_INCLUDED
|
||||
|
||||
#include "TemporaryStorage.h"
|
||||
#include "../DataStructures/BinaryHeap.h"
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/XORFastHash.h"
|
||||
#include "../DataStructures/XORFastHashStorage.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
class Contractor {
|
||||
|
||||
private:
|
||||
struct _ContractorEdgeData {
|
||||
_ContractorEdgeData() :
|
||||
distance(0), id(0), originalEdges(0), shortcut(0), forward(0), backward(0), originalViaNodeID(false) {}
|
||||
_ContractorEdgeData( unsigned _distance, unsigned _originalEdges, unsigned _id, bool _shortcut, bool _forward, bool _backward) :
|
||||
distance(_distance), id(_id), originalEdges(std::min((unsigned)1<<28, _originalEdges) ), shortcut(_shortcut), forward(_forward), backward(_backward), originalViaNodeID(false) {}
|
||||
unsigned distance;
|
||||
unsigned id;
|
||||
unsigned originalEdges:28;
|
||||
bool shortcut:1;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
bool originalViaNodeID:1;
|
||||
} data;
|
||||
|
||||
struct _HeapData {
|
||||
short hop;
|
||||
bool target;
|
||||
_HeapData() : hop(0), target(false) {}
|
||||
_HeapData( short h, bool t ) : hop(h), target(t) {}
|
||||
};
|
||||
|
||||
typedef DynamicGraph< _ContractorEdgeData > _DynamicGraph;
|
||||
// typedef BinaryHeap< NodeID, NodeID, int, _HeapData, ArrayStorage<NodeID, NodeID> > _Heap;
|
||||
typedef BinaryHeap< NodeID, NodeID, int, _HeapData, XORFastHashStorage<NodeID, NodeID> > _Heap;
|
||||
typedef _DynamicGraph::InputEdge _ContractorEdge;
|
||||
|
||||
struct _ThreadData {
|
||||
_Heap heap;
|
||||
std::vector< _ContractorEdge > insertedEdges;
|
||||
std::vector< NodeID > neighbours;
|
||||
_ThreadData( NodeID nodes ): heap( nodes ) { }
|
||||
};
|
||||
|
||||
struct _PriorityData {
|
||||
int depth;
|
||||
_PriorityData() : depth(0) { }
|
||||
};
|
||||
|
||||
struct _ContractionInformation {
|
||||
int edgesDeleted;
|
||||
int edgesAdded;
|
||||
int originalEdgesDeleted;
|
||||
int originalEdgesAdded;
|
||||
_ContractionInformation() : edgesDeleted(0), edgesAdded(0), originalEdgesDeleted(0), originalEdgesAdded(0) {}
|
||||
};
|
||||
|
||||
struct _RemainingNodeData {
|
||||
_RemainingNodeData() : id (0), isIndependent(false) {}
|
||||
NodeID id:31;
|
||||
bool isIndependent:1;
|
||||
};
|
||||
|
||||
struct _NodePartitionor {
|
||||
inline bool operator()(_RemainingNodeData & nodeData ) const {
|
||||
return !nodeData.isIndependent;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
template<class ContainerT >
|
||||
Contractor( int nodes, ContainerT& inputEdges) {
|
||||
std::vector< _ContractorEdge > edges;
|
||||
edges.reserve(inputEdges.size()*2);
|
||||
|
||||
typename ContainerT::deallocation_iterator diter = inputEdges.dbegin();
|
||||
typename ContainerT::deallocation_iterator dend = inputEdges.dend();
|
||||
|
||||
_ContractorEdge newEdge;
|
||||
while(diter!=dend) {
|
||||
newEdge.source = diter->source();
|
||||
newEdge.target = diter->target();
|
||||
newEdge.data = _ContractorEdgeData( (std::max)((int)diter->weight(), 1 ), 1, diter->id(), false, diter->isForward(), diter->isBackward());
|
||||
|
||||
BOOST_ASSERT_MSG( newEdge.data.distance > 0, "edge distance < 1" );
|
||||
#ifndef NDEBUG
|
||||
if ( newEdge.data.distance > 24 * 60 * 60 * 10 ) {
|
||||
SimpleLogger().Write(logWARNING) <<
|
||||
"Edge weight large -> " << newEdge.data.distance;
|
||||
}
|
||||
#endif
|
||||
edges.push_back( newEdge );
|
||||
std::swap( newEdge.source, newEdge.target );
|
||||
newEdge.data.forward = diter->isBackward();
|
||||
newEdge.data.backward = diter->isForward();
|
||||
edges.push_back( newEdge );
|
||||
++diter;
|
||||
}
|
||||
//clear input vector and trim the current set of edges with the well-known swap trick
|
||||
inputEdges.clear();
|
||||
sort( edges.begin(), edges.end() );
|
||||
NodeID edge = 0;
|
||||
for ( NodeID i = 0; i < edges.size(); ) {
|
||||
const NodeID source = edges[i].source;
|
||||
const NodeID target = edges[i].target;
|
||||
const NodeID id = edges[i].data.id;
|
||||
//remove eigenloops
|
||||
if ( source == target ) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
_ContractorEdge forwardEdge;
|
||||
_ContractorEdge backwardEdge;
|
||||
forwardEdge.source = backwardEdge.source = source;
|
||||
forwardEdge.target = backwardEdge.target = target;
|
||||
forwardEdge.data.forward = backwardEdge.data.backward = true;
|
||||
forwardEdge.data.backward = backwardEdge.data.forward = false;
|
||||
forwardEdge.data.shortcut = backwardEdge.data.shortcut = false;
|
||||
forwardEdge.data.id = backwardEdge.data.id = id;
|
||||
forwardEdge.data.originalEdges = backwardEdge.data.originalEdges = 1;
|
||||
forwardEdge.data.distance = backwardEdge.data.distance = std::numeric_limits< int >::max();
|
||||
//remove parallel edges
|
||||
while ( i < edges.size() && edges[i].source == source && edges[i].target == target ) {
|
||||
if ( edges[i].data.forward) {
|
||||
forwardEdge.data.distance = std::min( edges[i].data.distance, forwardEdge.data.distance );
|
||||
}
|
||||
if ( edges[i].data.backward) {
|
||||
backwardEdge.data.distance = std::min( edges[i].data.distance, backwardEdge.data.distance );
|
||||
}
|
||||
++i;
|
||||
}
|
||||
//merge edges (s,t) and (t,s) into bidirectional edge
|
||||
if ( forwardEdge.data.distance == backwardEdge.data.distance ) {
|
||||
if ( (int)forwardEdge.data.distance != std::numeric_limits< int >::max() ) {
|
||||
forwardEdge.data.backward = true;
|
||||
edges[edge++] = forwardEdge;
|
||||
}
|
||||
} else { //insert seperate edges
|
||||
if ( ((int)forwardEdge.data.distance) != std::numeric_limits< int >::max() ) {
|
||||
edges[edge++] = forwardEdge;
|
||||
}
|
||||
if ( (int)backwardEdge.data.distance != std::numeric_limits< int >::max() ) {
|
||||
edges[edge++] = backwardEdge;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "merged " << edges.size() - edge << " edges out of " << edges.size() << std::endl;
|
||||
edges.resize( edge );
|
||||
_graph = boost::make_shared<_DynamicGraph>( nodes, edges );
|
||||
edges.clear();
|
||||
std::vector<_ContractorEdge>().swap(edges);
|
||||
// unsigned maxdegree = 0;
|
||||
// NodeID highestNode = 0;
|
||||
//
|
||||
// for(unsigned i = 0; i < _graph->GetNumberOfNodes(); ++i) {
|
||||
// unsigned degree = _graph->EndEdges(i) - _graph->BeginEdges(i);
|
||||
// if(degree > maxdegree) {
|
||||
// maxdegree = degree;
|
||||
// highestNode = i;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// SimpleLogger().Write() << "edges at node with id " << highestNode << " has degree " << maxdegree;
|
||||
// for(unsigned i = _graph->BeginEdges(highestNode); i < _graph->EndEdges(highestNode); ++i) {
|
||||
// SimpleLogger().Write() << " ->(" << highestNode << "," << _graph->GetTarget(i) << "); via: " << _graph->GetEdgeData(i).via;
|
||||
// }
|
||||
|
||||
//Create temporary file
|
||||
|
||||
// GetTemporaryFileName(temporaryEdgeStorageFilename);
|
||||
temporaryStorageSlotID = TemporaryStorage::GetInstance().allocateSlot();
|
||||
std::cout << "contractor finished initalization" << std::endl;
|
||||
}
|
||||
|
||||
~Contractor() {
|
||||
//Delete temporary file
|
||||
// remove(temporaryEdgeStorageFilename.c_str());
|
||||
TemporaryStorage::GetInstance().deallocateSlot(temporaryStorageSlotID);
|
||||
}
|
||||
|
||||
void Run() {
|
||||
const NodeID numberOfNodes = _graph->GetNumberOfNodes();
|
||||
Percent p (numberOfNodes);
|
||||
|
||||
const unsigned maxThreads = omp_get_max_threads();
|
||||
std::vector < _ThreadData* > threadData;
|
||||
for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
threadData.push_back( new _ThreadData( numberOfNodes ) );
|
||||
}
|
||||
std::cout << "Contractor is using " << maxThreads << " threads" << std::endl;
|
||||
|
||||
NodeID numberOfContractedNodes = 0;
|
||||
std::vector< _RemainingNodeData > remainingNodes( numberOfNodes );
|
||||
std::vector< float > nodePriority( numberOfNodes );
|
||||
std::vector< _PriorityData > nodeData( numberOfNodes );
|
||||
|
||||
//initialize the variables
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for ( int x = 0; x < ( int ) numberOfNodes; ++x ) {
|
||||
remainingNodes[x].id = x;
|
||||
}
|
||||
|
||||
std::cout << "initializing elimination PQ ..." << std::flush;
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for ( int x = 0; x < ( int ) numberOfNodes; ++x ) {
|
||||
nodePriority[x] = _Evaluate( data, &nodeData[x], x );
|
||||
}
|
||||
}
|
||||
std::cout << "ok" << std::endl << "preprocessing " << numberOfNodes << " nodes ..." << std::flush;
|
||||
|
||||
bool flushedContractor = false;
|
||||
while ( numberOfNodes > 2 && numberOfContractedNodes < numberOfNodes ) {
|
||||
if(!flushedContractor && (numberOfContractedNodes > (numberOfNodes*0.65) ) ){
|
||||
DeallocatingVector<_ContractorEdge> newSetOfEdges; //this one is not explicitely cleared since it goes out of scope anywa
|
||||
std::cout << " [flush " << numberOfContractedNodes << " nodes] " << std::flush;
|
||||
|
||||
//Delete old heap data to free memory that we need for the coming operations
|
||||
BOOST_FOREACH(_ThreadData * data, threadData)
|
||||
delete data;
|
||||
threadData.clear();
|
||||
|
||||
|
||||
//Create new priority array
|
||||
std::vector<float> newNodePriority(remainingNodes.size());
|
||||
//this map gives the old IDs from the new ones, necessary to get a consistent graph at the end of contraction
|
||||
oldNodeIDFromNewNodeIDMap.resize(remainingNodes.size());
|
||||
//this map gives the new IDs from the old ones, necessary to remap targets from the remaining graph
|
||||
std::vector<NodeID> newNodeIDFromOldNodeIDMap(numberOfNodes, UINT_MAX);
|
||||
|
||||
//build forward and backward renumbering map and remap ids in remainingNodes and Priorities.
|
||||
for(unsigned newNodeID = 0; newNodeID < remainingNodes.size(); ++newNodeID) {
|
||||
//create renumbering maps in both directions
|
||||
oldNodeIDFromNewNodeIDMap[newNodeID] = remainingNodes[newNodeID].id;
|
||||
newNodeIDFromOldNodeIDMap[remainingNodes[newNodeID].id] = newNodeID;
|
||||
newNodePriority[newNodeID] = nodePriority[remainingNodes[newNodeID].id];
|
||||
remainingNodes[newNodeID].id = newNodeID;
|
||||
}
|
||||
TemporaryStorage & tempStorage = TemporaryStorage::GetInstance();
|
||||
//Write dummy number of edges to temporary file
|
||||
// std::ofstream temporaryEdgeStorage(temporaryEdgeStorageFilename.c_str(), std::ios::binary);
|
||||
uint64_t 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) {
|
||||
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;
|
||||
BOOST_ASSERT_MSG(
|
||||
UINT_MAX != newNodeIDFromOldNodeIDMap[start],
|
||||
"new start id not resolveable"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
UINT_MAX != newNodeIDFromOldNodeIDMap[target],
|
||||
"new target id not resolveable"
|
||||
);
|
||||
newSetOfEdges.push_back(newEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Note the number of temporarily stored edges
|
||||
tempStorage.seek(temporaryStorageSlotID, initialFilePosition);
|
||||
tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&numberOfTemporaryEdges, sizeof(unsigned));
|
||||
|
||||
//Delete map from old NodeIDs to new ones.
|
||||
std::vector<NodeID>().swap(newNodeIDFromOldNodeIDMap);
|
||||
|
||||
//Replace old priorities array by new one
|
||||
nodePriority.swap(newNodePriority);
|
||||
//Delete old nodePriority vector
|
||||
std::vector<float>().swap(newNodePriority);
|
||||
//old Graph is removed
|
||||
_graph.reset();
|
||||
|
||||
//create new graph
|
||||
std::sort(newSetOfEdges.begin(), newSetOfEdges.end());
|
||||
_graph = boost::make_shared<_DynamicGraph>(remainingNodes.size(), newSetOfEdges);
|
||||
|
||||
newSetOfEdges.clear();
|
||||
flushedContractor = true;
|
||||
|
||||
//INFO: MAKE SURE THIS IS THE LAST OPERATION OF THE FLUSH!
|
||||
//reinitialize heaps and ThreadData objects with appropriate size
|
||||
for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
threadData.push_back( new _ThreadData( _graph->GetNumberOfNodes() ) );
|
||||
}
|
||||
}
|
||||
|
||||
const int last = ( int ) remainingNodes.size();
|
||||
#pragma omp parallel
|
||||
{
|
||||
//determine independent node set
|
||||
_ThreadData* const data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided )
|
||||
for ( int i = 0; i < last; ++i ) {
|
||||
const NodeID node = remainingNodes[i].id;
|
||||
remainingNodes[i].isIndependent = _IsIndependent( nodePriority/*, nodeData*/, data, node );
|
||||
}
|
||||
}
|
||||
_NodePartitionor functor;
|
||||
const std::vector < _RemainingNodeData >::const_iterator first = stable_partition( remainingNodes.begin(), remainingNodes.end(), functor );
|
||||
const int firstIndependent = first - remainingNodes.begin();
|
||||
//contract independent nodes
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided ) nowait
|
||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||
NodeID x = remainingNodes[position].id;
|
||||
_Contract< false > ( data, x );
|
||||
//nodePriority[x] = -1;
|
||||
}
|
||||
|
||||
std::sort( data->insertedEdges.begin(), data->insertedEdges.end() );
|
||||
}
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided ) nowait
|
||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||
NodeID x = remainingNodes[position].id;
|
||||
_DeleteIncomingEdges( data, x );
|
||||
}
|
||||
}
|
||||
//insert new edges
|
||||
for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
_ThreadData& data = *threadData[threadNum];
|
||||
BOOST_FOREACH(const _ContractorEdge& edge, data.insertedEdges) {
|
||||
_DynamicGraph::EdgeIterator currentEdgeID = _graph->FindEdge(edge.source, edge.target);
|
||||
if(currentEdgeID < _graph->EndEdges(edge.source) ) {
|
||||
_DynamicGraph::EdgeData & currentEdgeData = _graph->GetEdgeData(currentEdgeID);
|
||||
if( currentEdgeData.shortcut
|
||||
&& edge.data.forward == currentEdgeData.forward
|
||||
&& edge.data.backward == currentEdgeData.backward ) {
|
||||
currentEdgeData.distance = std::min(currentEdgeData.distance, edge.data.distance);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_graph->InsertEdge( edge.source, edge.target, edge.data );
|
||||
}
|
||||
data.insertedEdges.clear();
|
||||
}
|
||||
//update priorities
|
||||
#pragma omp parallel
|
||||
{
|
||||
_ThreadData* data = threadData[omp_get_thread_num()];
|
||||
#pragma omp for schedule ( guided ) nowait
|
||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||
NodeID x = remainingNodes[position].id;
|
||||
_UpdateNeighbours( nodePriority, nodeData, data, x );
|
||||
}
|
||||
}
|
||||
//remove contracted nodes from the pool
|
||||
numberOfContractedNodes += last - firstIndependent;
|
||||
remainingNodes.resize( firstIndependent );
|
||||
std::vector< _RemainingNodeData>( remainingNodes ).swap( remainingNodes );
|
||||
// unsigned maxdegree = 0;
|
||||
// unsigned avgdegree = 0;
|
||||
// unsigned mindegree = UINT_MAX;
|
||||
// unsigned quaddegree = 0;
|
||||
//
|
||||
// for(unsigned i = 0; i < remainingNodes.size(); ++i) {
|
||||
// unsigned degree = _graph->EndEdges(remainingNodes[i].first) - _graph->BeginEdges(remainingNodes[i].first);
|
||||
// if(degree > maxdegree)
|
||||
// maxdegree = degree;
|
||||
// if(degree < mindegree)
|
||||
// mindegree = degree;
|
||||
//
|
||||
// avgdegree += degree;
|
||||
// quaddegree += (degree*degree);
|
||||
// }
|
||||
//
|
||||
// avgdegree /= std::max((unsigned)1,(unsigned)remainingNodes.size() );
|
||||
// quaddegree /= std::max((unsigned)1,(unsigned)remainingNodes.size() );
|
||||
//
|
||||
// SimpleLogger().Write() << "rest: " << remainingNodes.size() << ", max: " << maxdegree << ", min: " << mindegree << ", avg: " << avgdegree << ", quad: " << quaddegree;
|
||||
|
||||
p.printStatus(numberOfContractedNodes);
|
||||
}
|
||||
BOOST_FOREACH(_ThreadData * data, threadData) {
|
||||
delete data;
|
||||
}
|
||||
threadData.clear();
|
||||
}
|
||||
|
||||
template< class Edge >
|
||||
inline void GetEdges( DeallocatingVector< Edge >& edges ) {
|
||||
Percent p (_graph->GetNumberOfNodes());
|
||||
SimpleLogger().Write() << "Getting edges of minimized graph";
|
||||
NodeID numberOfNodes = _graph->GetNumberOfNodes();
|
||||
if(_graph->GetNumberOfNodes()) {
|
||||
for ( NodeID node = 0; node < numberOfNodes; ++node ) {
|
||||
p.printStatus(node);
|
||||
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge < endEdges; ++edge ) {
|
||||
const NodeID target = _graph->GetTarget( edge );
|
||||
const _DynamicGraph::EdgeData& data = _graph->GetEdgeData( edge );
|
||||
Edge newEdge;
|
||||
if(0 != oldNodeIDFromNewNodeIDMap.size()) {
|
||||
newEdge.source = oldNodeIDFromNewNodeIDMap[node];
|
||||
newEdge.target = oldNodeIDFromNewNodeIDMap[target];
|
||||
} else {
|
||||
newEdge.source = node;
|
||||
newEdge.target = target;
|
||||
}
|
||||
BOOST_ASSERT_MSG(
|
||||
UINT_MAX != newEdge.source,
|
||||
"Source id invalid"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
UINT_MAX != newEdge.target,
|
||||
"Target id invalid"
|
||||
);
|
||||
newEdge.data.distance = data.distance;
|
||||
newEdge.data.shortcut = data.shortcut;
|
||||
if(!data.originalViaNodeID && oldNodeIDFromNewNodeIDMap.size()) {
|
||||
newEdge.data.id = oldNodeIDFromNewNodeIDMap[data.id];
|
||||
} else {
|
||||
newEdge.data.id = data.id;
|
||||
}
|
||||
BOOST_ASSERT_MSG(
|
||||
newEdge.data.id != INT_MAX, //2^31
|
||||
"edge id invalid"
|
||||
);
|
||||
newEdge.data.forward = data.forward;
|
||||
newEdge.data.backward = data.backward;
|
||||
edges.push_back( newEdge );
|
||||
}
|
||||
}
|
||||
}
|
||||
_graph.reset();
|
||||
std::vector<NodeID>().swap(oldNodeIDFromNewNodeIDMap);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private:
|
||||
inline void _Dijkstra( const int maxDistance, const unsigned numTargets, const int maxNodes, _ThreadData* const data, const NodeID middleNode ){
|
||||
|
||||
_Heap& heap = data->heap;
|
||||
|
||||
int nodes = 0;
|
||||
unsigned targetsFound = 0;
|
||||
while ( heap.Size() > 0 ) {
|
||||
const NodeID node = heap.DeleteMin();
|
||||
const int distance = heap.GetKey( node );
|
||||
const short currentHop = heap.GetData( node ).hop+1;
|
||||
|
||||
if ( ++nodes > maxNodes )
|
||||
return;
|
||||
//Destination settled?
|
||||
if ( distance > maxDistance )
|
||||
return;
|
||||
|
||||
if ( heap.GetData( node ).target ) {
|
||||
++targetsFound;
|
||||
if ( targetsFound >= numTargets ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//iterate over all edges of node
|
||||
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge != endEdges; ++edge ) {
|
||||
const _ContractorEdgeData& data = _graph->GetEdgeData( edge );
|
||||
if ( !data.forward ){
|
||||
continue;
|
||||
}
|
||||
const NodeID to = _graph->GetTarget( edge );
|
||||
if(middleNode == to) {
|
||||
continue;
|
||||
}
|
||||
const int toDistance = distance + data.distance;
|
||||
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !heap.WasInserted( to ) ) {
|
||||
heap.Insert( to, toDistance, _HeapData(currentHop, false) );
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < heap.GetKey( to ) ) {
|
||||
heap.DecreaseKey( to, toDistance );
|
||||
heap.GetData( to ).hop = currentHop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline float _Evaluate( _ThreadData* const data, _PriorityData* const nodeData, const NodeID node){
|
||||
_ContractionInformation stats;
|
||||
|
||||
//perform simulated contraction
|
||||
_Contract< true> ( data, node, &stats );
|
||||
|
||||
// Result will contain the priority
|
||||
float result;
|
||||
if ( 0 == (stats.edgesDeleted*stats.originalEdgesDeleted) )
|
||||
result = 1 * nodeData->depth;
|
||||
else
|
||||
result = 2 * ((( float ) stats.edgesAdded ) / stats.edgesDeleted ) + 4 * ((( float ) stats.originalEdgesAdded ) / stats.originalEdgesDeleted ) + 1 * nodeData->depth;
|
||||
assert( result >= 0 );
|
||||
return result;
|
||||
}
|
||||
|
||||
template< bool Simulate >
|
||||
inline bool _Contract( _ThreadData* data, NodeID node, _ContractionInformation* stats = NULL ) {
|
||||
_Heap& heap = data->heap;
|
||||
int insertedEdgesSize = data->insertedEdges.size();
|
||||
std::vector< _ContractorEdge >& insertedEdges = data->insertedEdges;
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator inEdge = _graph->BeginEdges( node ), endInEdges = _graph->EndEdges( node ); inEdge != endInEdges; ++inEdge ) {
|
||||
const _ContractorEdgeData& inData = _graph->GetEdgeData( inEdge );
|
||||
const NodeID source = _graph->GetTarget( inEdge );
|
||||
if ( Simulate ) {
|
||||
assert( stats != NULL );
|
||||
++stats->edgesDeleted;
|
||||
stats->originalEdgesDeleted += inData.originalEdges;
|
||||
}
|
||||
if ( !inData.backward )
|
||||
continue;
|
||||
|
||||
heap.Clear();
|
||||
heap.Insert( source, 0, _HeapData() );
|
||||
int maxDistance = 0;
|
||||
unsigned numTargets = 0;
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
|
||||
const _ContractorEdgeData& outData = _graph->GetEdgeData( outEdge );
|
||||
if ( !outData.forward ) {
|
||||
continue;
|
||||
}
|
||||
const NodeID target = _graph->GetTarget( outEdge );
|
||||
const int pathDistance = inData.distance + outData.distance;
|
||||
maxDistance = std::max( maxDistance, pathDistance );
|
||||
if ( !heap.WasInserted( target ) ) {
|
||||
heap.Insert( target, INT_MAX, _HeapData( 0, true ) );
|
||||
++numTargets;
|
||||
}
|
||||
}
|
||||
|
||||
if( Simulate ) {
|
||||
_Dijkstra( maxDistance, numTargets, 1000, data, node );
|
||||
} else {
|
||||
_Dijkstra( maxDistance, numTargets, 2000, data, node );
|
||||
}
|
||||
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
|
||||
const _ContractorEdgeData& outData = _graph->GetEdgeData( outEdge );
|
||||
if ( !outData.forward ) {
|
||||
continue;
|
||||
}
|
||||
const NodeID target = _graph->GetTarget( outEdge );
|
||||
const int pathDistance = inData.distance + outData.distance;
|
||||
const int distance = heap.GetKey( target );
|
||||
if ( pathDistance < distance ) {
|
||||
if ( Simulate ) {
|
||||
assert( stats != NULL );
|
||||
stats->edgesAdded+=2;
|
||||
stats->originalEdgesAdded += 2* ( outData.originalEdges + inData.originalEdges );
|
||||
} else {
|
||||
_ContractorEdge newEdge;
|
||||
newEdge.source = source;
|
||||
newEdge.target = target;
|
||||
newEdge.data = _ContractorEdgeData( pathDistance, outData.originalEdges + inData.originalEdges, node/*, 0, inData.turnInstruction*/, true, true, false);;
|
||||
insertedEdges.push_back( newEdge );
|
||||
std::swap( newEdge.source, newEdge.target );
|
||||
newEdge.data.forward = false;
|
||||
newEdge.data.backward = true;
|
||||
insertedEdges.push_back( newEdge );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !Simulate ) {
|
||||
for ( int i = insertedEdgesSize, iend = insertedEdges.size(); i < iend; ++i ) {
|
||||
bool found = false;
|
||||
for ( int other = i + 1 ; other < iend ; ++other ) {
|
||||
if ( insertedEdges[other].source != insertedEdges[i].source )
|
||||
continue;
|
||||
if ( insertedEdges[other].target != insertedEdges[i].target )
|
||||
continue;
|
||||
if ( insertedEdges[other].data.distance != insertedEdges[i].data.distance )
|
||||
continue;
|
||||
if ( insertedEdges[other].data.shortcut != insertedEdges[i].data.shortcut )
|
||||
continue;
|
||||
insertedEdges[other].data.forward |= insertedEdges[i].data.forward;
|
||||
insertedEdges[other].data.backward |= insertedEdges[i].data.backward;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if ( !found ) {
|
||||
insertedEdges[insertedEdgesSize++] = insertedEdges[i];
|
||||
}
|
||||
}
|
||||
insertedEdges.resize( insertedEdgesSize );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void _DeleteIncomingEdges( _ThreadData* data, const NodeID node ) {
|
||||
std::vector< NodeID >& neighbours = data->neighbours;
|
||||
neighbours.clear();
|
||||
|
||||
//find all neighbours
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
||||
const NodeID u = _graph->GetTarget( e );
|
||||
if ( u != node )
|
||||
neighbours.push_back( u );
|
||||
}
|
||||
//eliminate duplicate entries ( forward + backward edges )
|
||||
std::sort( neighbours.begin(), neighbours.end() );
|
||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||
|
||||
for ( int i = 0, e = ( int ) neighbours.size(); i < e; ++i ) {
|
||||
_graph->DeleteEdgesTo( neighbours[i], node );
|
||||
}
|
||||
}
|
||||
|
||||
inline bool _UpdateNeighbours( std::vector< float > & priorities, std::vector< _PriorityData > & nodeData, _ThreadData* const data, const NodeID node) {
|
||||
std::vector< NodeID >& neighbours = data->neighbours;
|
||||
neighbours.clear();
|
||||
|
||||
//find all neighbours
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ) ; e < endEdges ; ++e ) {
|
||||
const NodeID u = _graph->GetTarget( e );
|
||||
if ( u == node )
|
||||
continue;
|
||||
neighbours.push_back( u );
|
||||
nodeData[u].depth = (std::max)(nodeData[node].depth + 1, nodeData[u].depth );
|
||||
}
|
||||
//eliminate duplicate entries ( forward + backward edges )
|
||||
std::sort( neighbours.begin(), neighbours.end() );
|
||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||
|
||||
BOOST_FOREACH(const NodeID u, neighbours) {
|
||||
priorities[u] = _Evaluate( data, &( nodeData )[u], u );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool _IsIndependent( const std::vector< float >& priorities/*, const std::vector< _PriorityData >& nodeData*/, _ThreadData* const data, NodeID node ) const {
|
||||
const double priority = priorities[node];
|
||||
|
||||
std::vector< NodeID >& neighbours = data->neighbours;
|
||||
neighbours.clear();
|
||||
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
|
||||
const NodeID target = _graph->GetTarget( e );
|
||||
if(node==target)
|
||||
continue;
|
||||
const double targetPriority = priorities[target];
|
||||
assert( targetPriority >= 0 );
|
||||
//found a neighbour with lower priority?
|
||||
if ( priority > targetPriority )
|
||||
return false;
|
||||
//tie breaking
|
||||
if ( fabs(priority - targetPriority) < std::numeric_limits<double>::epsilon() && bias(node, target) ) {
|
||||
return false;
|
||||
}
|
||||
neighbours.push_back( target );
|
||||
}
|
||||
|
||||
std::sort( neighbours.begin(), neighbours.end() );
|
||||
neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
|
||||
|
||||
//examine all neighbours that are at most 2 hops away
|
||||
BOOST_FOREACH(const NodeID u, neighbours) {
|
||||
for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( u ) ; e < _graph->EndEdges( u ) ; ++e ) {
|
||||
const NodeID target = _graph->GetTarget( e );
|
||||
if(node==target)
|
||||
continue;
|
||||
|
||||
const double targetPriority = priorities[target];
|
||||
assert( targetPriority >= 0 );
|
||||
//found a neighbour with lower priority?
|
||||
if ( priority > targetPriority)
|
||||
return false;
|
||||
//tie breaking
|
||||
if ( fabs(priority - targetPriority) < std::numeric_limits<double>::epsilon() && bias(node, target) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This bias function takes up 22 assembly instructions in total on X86
|
||||
*/
|
||||
inline bool bias(const NodeID a, const NodeID b) const {
|
||||
unsigned short hasha = fastHash(a);
|
||||
unsigned short hashb = fastHash(b);
|
||||
|
||||
//The compiler optimizes that to conditional register flags but without branching statements!
|
||||
if(hasha != hashb)
|
||||
return hasha < hashb;
|
||||
return a < b;
|
||||
}
|
||||
|
||||
boost::shared_ptr<_DynamicGraph> _graph;
|
||||
std::vector<_DynamicGraph::InputEdge> contractedEdges;
|
||||
unsigned temporaryStorageSlotID;
|
||||
std::vector<NodeID> oldNodeIDFromNewNodeIDMap;
|
||||
XORFastHash fastHash;
|
||||
};
|
||||
|
||||
#endif // CONTRACTOR_H_INCLUDED
|
||||
@@ -0,0 +1,578 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "EdgeBasedGraphFactory.h"
|
||||
|
||||
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
||||
int number_of_nodes,
|
||||
std::vector<ImportEdge> & input_edge_list,
|
||||
std::vector<NodeID> & barrier_node_list,
|
||||
std::vector<NodeID> & traffic_light_node_list,
|
||||
std::vector<TurnRestriction> & input_restrictions_list,
|
||||
std::vector<NodeInfo> & m_node_info_list,
|
||||
SpeedProfileProperties speed_profile
|
||||
) : speed_profile(speed_profile),
|
||||
m_turn_restrictions_count(0),
|
||||
m_node_info_list(m_node_info_list)
|
||||
{
|
||||
BOOST_FOREACH(const TurnRestriction & restriction, input_restrictions_list) {
|
||||
std::pair<NodeID, NodeID> restriction_source =
|
||||
std::make_pair(restriction.fromNode, restriction.viaNode);
|
||||
unsigned index;
|
||||
RestrictionMap::iterator restriction_iter = m_restriction_map.find(restriction_source);
|
||||
if(restriction_iter == m_restriction_map.end()) {
|
||||
index = m_restriction_bucket_list.size();
|
||||
m_restriction_bucket_list.resize(index+1);
|
||||
m_restriction_map.emplace(restriction_source, index);
|
||||
} else {
|
||||
index = restriction_iter->second;
|
||||
//Map already contains an is_only_*-restriction
|
||||
if(m_restriction_bucket_list.at(index).begin()->second) {
|
||||
continue;
|
||||
} else if(restriction.flags.isOnly) {
|
||||
//We are going to insert an is_only_*-restriction. There can be only one.
|
||||
m_turn_restrictions_count -= m_restriction_bucket_list.at(index).size();
|
||||
m_restriction_bucket_list.at(index).clear();
|
||||
}
|
||||
}
|
||||
++m_turn_restrictions_count;
|
||||
m_restriction_bucket_list.at(index).push_back(
|
||||
std::make_pair( restriction.toNode, restriction.flags.isOnly)
|
||||
);
|
||||
}
|
||||
|
||||
m_barrier_nodes.insert(
|
||||
barrier_node_list.begin(),
|
||||
barrier_node_list.end()
|
||||
);
|
||||
|
||||
m_traffic_lights.insert(
|
||||
traffic_light_node_list.begin(),
|
||||
traffic_light_node_list.end()
|
||||
);
|
||||
|
||||
DeallocatingVector< NodeBasedEdge > edges_list;
|
||||
NodeBasedEdge edge;
|
||||
BOOST_FOREACH(const ImportEdge & import_edge, input_edge_list) {
|
||||
if(!import_edge.isForward()) {
|
||||
edge.source = import_edge.target();
|
||||
edge.target = import_edge.source();
|
||||
edge.data.backward = import_edge.isForward();
|
||||
edge.data.forward = import_edge.isBackward();
|
||||
} else {
|
||||
edge.source = import_edge.source();
|
||||
edge.target = import_edge.target();
|
||||
edge.data.forward = import_edge.isForward();
|
||||
edge.data.backward = import_edge.isBackward();
|
||||
}
|
||||
if(edge.source == edge.target) {
|
||||
continue;
|
||||
}
|
||||
edge.data.distance = (std::max)((int)import_edge.weight(), 1 );
|
||||
assert( edge.data.distance > 0 );
|
||||
edge.data.shortcut = false;
|
||||
edge.data.roundabout = import_edge.isRoundabout();
|
||||
edge.data.ignoreInGrid = import_edge.ignoreInGrid();
|
||||
edge.data.nameID = import_edge.name();
|
||||
edge.data.type = import_edge.type();
|
||||
edge.data.isAccessRestricted = import_edge.isAccessRestricted();
|
||||
edge.data.edgeBasedNodeID = edges_list.size();
|
||||
edge.data.contraFlow = import_edge.isContraFlow();
|
||||
edges_list.push_back( edge );
|
||||
if( edge.data.backward ) {
|
||||
std::swap( edge.source, edge.target );
|
||||
edge.data.forward = import_edge.isBackward();
|
||||
edge.data.backward = import_edge.isForward();
|
||||
edge.data.edgeBasedNodeID = edges_list.size();
|
||||
edges_list.push_back( edge );
|
||||
}
|
||||
}
|
||||
std::vector<ImportEdge>().swap(input_edge_list);
|
||||
std::sort( edges_list.begin(), edges_list.end() );
|
||||
m_node_based_graph = boost::make_shared<NodeBasedDynamicGraph>(
|
||||
number_of_nodes, edges_list
|
||||
);
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::GetEdgeBasedEdges(
|
||||
DeallocatingVector< EdgeBasedEdge >& output_edge_list
|
||||
) {
|
||||
BOOST_ASSERT_MSG(
|
||||
0 == output_edge_list.size(),
|
||||
"Vector is not empty"
|
||||
);
|
||||
m_edge_based_edge_list.swap(output_edge_list);
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::GetEdgeBasedNodes( std::vector<EdgeBasedNode> & nodes) {
|
||||
#ifndef NDEBUG
|
||||
BOOST_FOREACH(const EdgeBasedNode & node, m_edge_based_node_list){
|
||||
assert(node.lat1 != INT_MAX); assert(node.lon1 != INT_MAX);
|
||||
assert(node.lat2 != INT_MAX); assert(node.lon2 != INT_MAX);
|
||||
}
|
||||
#endif
|
||||
nodes.swap(m_edge_based_node_list);
|
||||
}
|
||||
|
||||
NodeID EdgeBasedGraphFactory::CheckForEmanatingIsOnlyTurn(
|
||||
const NodeID u,
|
||||
const NodeID v
|
||||
) const {
|
||||
const std::pair < NodeID, NodeID > restriction_source = std::make_pair(u, v);
|
||||
RestrictionMap::const_iterator restriction_iter = m_restriction_map.find(restriction_source);
|
||||
if (restriction_iter != m_restriction_map.end()) {
|
||||
const unsigned index = restriction_iter->second;
|
||||
BOOST_FOREACH(
|
||||
const RestrictionSource & restriction_target,
|
||||
m_restriction_bucket_list.at(index)
|
||||
) {
|
||||
if(restriction_target.second) {
|
||||
return restriction_target.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
bool 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.
|
||||
const std::pair < NodeID, NodeID > restriction_source = std::make_pair(u, v);
|
||||
RestrictionMap::const_iterator restriction_iter = m_restriction_map.find(restriction_source);
|
||||
if (restriction_iter != m_restriction_map.end()) {
|
||||
const unsigned index = restriction_iter->second;
|
||||
BOOST_FOREACH(
|
||||
const RestrictionTarget & restriction_target,
|
||||
m_restriction_bucket_list.at(index)
|
||||
) {
|
||||
if(w == restriction_target.first) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::InsertEdgeBasedNode(
|
||||
EdgeIterator e1,
|
||||
NodeIterator u,
|
||||
NodeIterator v,
|
||||
bool belongsToTinyComponent) {
|
||||
EdgeData & data = m_node_based_graph->GetEdgeData(e1);
|
||||
EdgeBasedNode currentNode;
|
||||
currentNode.nameID = data.nameID;
|
||||
currentNode.lat1 = m_node_info_list[u].lat;
|
||||
currentNode.lon1 = m_node_info_list[u].lon;
|
||||
currentNode.lat2 = m_node_info_list[v].lat;
|
||||
currentNode.lon2 = m_node_info_list[v].lon;
|
||||
currentNode.belongsToTinyComponent = belongsToTinyComponent;
|
||||
currentNode.id = data.edgeBasedNodeID;
|
||||
currentNode.ignoreInGrid = data.ignoreInGrid;
|
||||
currentNode.weight = data.distance;
|
||||
m_edge_based_node_list.push_back(currentNode);
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::Run(
|
||||
const char * original_edge_data_filename,
|
||||
lua_State *lua_state
|
||||
) {
|
||||
SimpleLogger().Write() << "Identifying components of the road network";
|
||||
|
||||
Percent p(m_node_based_graph->GetNumberOfNodes());
|
||||
unsigned skipped_turns_counter = 0;
|
||||
unsigned node_based_edge_counter = 0;
|
||||
unsigned original_edges_counter = 0;
|
||||
|
||||
std::ofstream edge_data_file(
|
||||
original_edge_data_filename,
|
||||
std::ios::binary
|
||||
);
|
||||
|
||||
//writes a dummy value that is updated later
|
||||
edge_data_file.write(
|
||||
(char*)&original_edges_counter,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
|
||||
unsigned current_component = 0, current_component_size = 0;
|
||||
//Run a BFS on the undirected graph and identify small components
|
||||
std::queue<std::pair<NodeID, NodeID> > bfs_queue;
|
||||
std::vector<unsigned> component_index_list(
|
||||
m_node_based_graph->GetNumberOfNodes(),
|
||||
UINT_MAX
|
||||
);
|
||||
|
||||
std::vector<NodeID> component_size_list;
|
||||
//put unexplorered node with parent pointer into queue
|
||||
for(
|
||||
NodeID node = 0,
|
||||
last_node = m_node_based_graph->GetNumberOfNodes();
|
||||
node < last_node;
|
||||
++node
|
||||
) {
|
||||
if(UINT_MAX == component_index_list[node]) {
|
||||
bfs_queue.push(std::make_pair(node, node));
|
||||
//mark node as read
|
||||
component_index_list[node] = current_component;
|
||||
p.printIncrement();
|
||||
while(!bfs_queue.empty()) {
|
||||
//fetch element from BFS queue
|
||||
std::pair<NodeID, NodeID> current_queue_item = bfs_queue.front();
|
||||
bfs_queue.pop();
|
||||
// SimpleLogger().Write() << "sizeof queue: " << bfs_queue.size() <<
|
||||
// ", current_component_sizes: " << current_component_size <<
|
||||
//", settled nodes: " << settledNodes++ << ", max: " << endNodes;
|
||||
const NodeID v = current_queue_item.first; //current node
|
||||
const NodeID u = current_queue_item.second; //parent
|
||||
//increment size counter of current component
|
||||
++current_component_size;
|
||||
const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
|
||||
if(!is_barrier_node) {
|
||||
const NodeID to_node_of_only_restriction = CheckForEmanatingIsOnlyTurn(u, v);
|
||||
|
||||
//relaxieren edge outgoing edge like below where edge-expanded graph
|
||||
for(
|
||||
EdgeIterator e2 = m_node_based_graph->BeginEdges(v);
|
||||
e2 < m_node_based_graph->EndEdges(v);
|
||||
++e2
|
||||
) {
|
||||
NodeIterator w = m_node_based_graph->GetTarget(e2);
|
||||
|
||||
if(
|
||||
to_node_of_only_restriction != UINT_MAX &&
|
||||
w != to_node_of_only_restriction
|
||||
) {
|
||||
//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
|
||||
//when it is at the end of a dead-end street.
|
||||
if (!CheckIfTurnIsRestricted(u, v, w) ) {
|
||||
//only add an edge if turn is not prohibited
|
||||
if(UINT_MAX == component_index_list[w]) {
|
||||
//insert next (node, parent) only if w has
|
||||
//not yet been explored
|
||||
//mark node as read
|
||||
component_index_list[w] = current_component;
|
||||
bfs_queue.push(std::make_pair(w,v));
|
||||
p.printIncrement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//push size into vector
|
||||
component_size_list.push_back(current_component_size);
|
||||
//reset counters;
|
||||
current_component_size = 0;
|
||||
++current_component;
|
||||
}
|
||||
}
|
||||
SimpleLogger().Write() <<
|
||||
"identified: " << component_size_list.size() << " many components";
|
||||
SimpleLogger().Write() <<
|
||||
"generating edge-expanded nodes";
|
||||
|
||||
p.reinit(m_node_based_graph->GetNumberOfNodes());
|
||||
//loop over all edges and generate new set of nodes.
|
||||
for(
|
||||
NodeIterator u = 0,
|
||||
number_of_nodes = m_node_based_graph->GetNumberOfNodes();
|
||||
u < number_of_nodes;
|
||||
++u
|
||||
) {
|
||||
p.printIncrement();
|
||||
for(
|
||||
EdgeIterator e1 = m_node_based_graph->BeginEdges(u),
|
||||
last_edge = m_node_based_graph->EndEdges(u);
|
||||
e1 < last_edge;
|
||||
++e1
|
||||
) {
|
||||
NodeIterator v = m_node_based_graph->GetTarget(e1);
|
||||
|
||||
if(m_node_based_graph->GetEdgeData(e1).type != SHRT_MAX) {
|
||||
BOOST_ASSERT_MSG(e1 != UINT_MAX, "edge id invalid");
|
||||
BOOST_ASSERT_MSG(u != UINT_MAX, "souce node invalid");
|
||||
BOOST_ASSERT_MSG(v != UINT_MAX, "target node invalid");
|
||||
//Note: edges that end on barrier nodes or on a turn restriction
|
||||
//may actually be in two distinct components. We choose the smallest
|
||||
const unsigned size_of_component = std::min(
|
||||
component_size_list[component_index_list[u]],
|
||||
component_size_list[component_index_list[v]]
|
||||
);
|
||||
|
||||
InsertEdgeBasedNode( e1, u, v, size_of_component < 1000 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleLogger().Write()
|
||||
<< "Generated " << m_edge_based_node_list.size() << " nodes in " <<
|
||||
"edge-expanded graph";
|
||||
SimpleLogger().Write() <<
|
||||
"generating edge-expanded edges";
|
||||
|
||||
std::vector<NodeID>().swap(component_size_list);
|
||||
BOOST_ASSERT_MSG(
|
||||
0 == component_size_list.capacity(),
|
||||
"component size vector not deallocated"
|
||||
);
|
||||
std::vector<NodeID>().swap(component_index_list);
|
||||
BOOST_ASSERT_MSG(
|
||||
0 == component_index_list.capacity(),
|
||||
"component index vector not deallocated"
|
||||
);
|
||||
std::vector<OriginalEdgeData> original_edge_data_vector;
|
||||
original_edge_data_vector.reserve(10000);
|
||||
|
||||
//Loop over all turns and generate new set of edges.
|
||||
//Three nested loop look super-linear, but we are dealing with a (kind of)
|
||||
//linear number of turns only.
|
||||
p.reinit(m_node_based_graph->GetNumberOfNodes());
|
||||
for(
|
||||
NodeIterator u = 0,
|
||||
last_node = m_node_based_graph->GetNumberOfNodes();
|
||||
u < last_node;
|
||||
++u
|
||||
) {
|
||||
for(
|
||||
EdgeIterator e1 = m_node_based_graph->BeginEdges(u),
|
||||
last_edge_u = m_node_based_graph->EndEdges(u);
|
||||
e1 < last_edge_u;
|
||||
++e1
|
||||
) {
|
||||
++node_based_edge_counter;
|
||||
NodeIterator v = m_node_based_graph->GetTarget(e1);
|
||||
bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
|
||||
NodeID to_node_of_only_restriction = CheckForEmanatingIsOnlyTurn(u, v);
|
||||
for(
|
||||
EdgeIterator e2 = m_node_based_graph->BeginEdges(v),
|
||||
last_edge_v = m_node_based_graph->EndEdges(v);
|
||||
e2 < last_edge_v;
|
||||
++e2
|
||||
) {
|
||||
const NodeIterator w = m_node_based_graph->GetTarget(e2);
|
||||
if(
|
||||
to_node_of_only_restriction != UINT_MAX &&
|
||||
w != to_node_of_only_restriction
|
||||
) {
|
||||
//We are at an only_-restriction but not at the right turn.
|
||||
++skipped_turns_counter;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(u == w && 1 != m_node_based_graph->GetOutDegree(v) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !is_barrier_node ) {
|
||||
//only add an edge if turn is not a U-turn except when it is
|
||||
//at the end of a dead-end street
|
||||
if (
|
||||
!CheckIfTurnIsRestricted(u, v, w) ||
|
||||
(to_node_of_only_restriction != UINT_MAX && w == to_node_of_only_restriction)
|
||||
) { //only add an edge if turn is not prohibited
|
||||
const EdgeData edge_data1 = m_node_based_graph->GetEdgeData(e1);
|
||||
const EdgeData edge_data2 = m_node_based_graph->GetEdgeData(e2);
|
||||
assert(edge_data1.edgeBasedNodeID < m_node_based_graph->GetNumberOfEdges());
|
||||
assert(edge_data2.edgeBasedNodeID < m_node_based_graph->GetNumberOfEdges());
|
||||
|
||||
if(!edge_data1.forward || !edge_data2.forward) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned distance = edge_data1.distance;
|
||||
if(m_traffic_lights.find(v) != m_traffic_lights.end()) {
|
||||
distance += speed_profile.trafficSignalPenalty;
|
||||
}
|
||||
const unsigned penalty =
|
||||
GetTurnPenalty(u, v, w, lua_state);
|
||||
TurnInstruction turnInstruction = AnalyzeTurn(u, v, w);
|
||||
if(turnInstruction == TurnInstructions.UTurn){
|
||||
distance += speed_profile.uTurnPenalty;
|
||||
}
|
||||
distance += penalty;
|
||||
|
||||
assert(edge_data1.edgeBasedNodeID != edge_data2.edgeBasedNodeID);
|
||||
original_edge_data_vector.push_back(
|
||||
OriginalEdgeData(
|
||||
v,
|
||||
edge_data2.nameID,
|
||||
turnInstruction
|
||||
)
|
||||
);
|
||||
++original_edges_counter;
|
||||
|
||||
if(original_edge_data_vector.size() > 100000) {
|
||||
edge_data_file.write(
|
||||
(char*)&(original_edge_data_vector[0]),
|
||||
original_edge_data_vector.size()*sizeof(OriginalEdgeData)
|
||||
);
|
||||
original_edge_data_vector.clear();
|
||||
}
|
||||
|
||||
m_edge_based_edge_list.push_back(
|
||||
EdgeBasedEdge(
|
||||
edge_data1.edgeBasedNodeID,
|
||||
edge_data2.edgeBasedNodeID,
|
||||
m_edge_based_edge_list.size(),
|
||||
distance,
|
||||
true,
|
||||
false
|
||||
)
|
||||
);
|
||||
} else {
|
||||
++skipped_turns_counter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p.printIncrement();
|
||||
}
|
||||
edge_data_file.write(
|
||||
(char*)&(original_edge_data_vector[0]),
|
||||
original_edge_data_vector.size()*sizeof(OriginalEdgeData)
|
||||
);
|
||||
edge_data_file.seekp(std::ios::beg);
|
||||
edge_data_file.write(
|
||||
(char*)&original_edges_counter,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
edge_data_file.close();
|
||||
|
||||
SimpleLogger().Write() <<
|
||||
"Generated " << m_edge_based_node_list.size() << " edge based nodes";
|
||||
SimpleLogger().Write() <<
|
||||
"Node-based graph contains " << node_based_edge_counter << " edges";
|
||||
SimpleLogger().Write() <<
|
||||
"Edge-expanded graph ...";
|
||||
SimpleLogger().Write() <<
|
||||
" contains " << m_edge_based_edge_list.size() << " edges";
|
||||
SimpleLogger().Write() <<
|
||||
" skips " << skipped_turns_counter << " turns, "
|
||||
"defined by " << m_turn_restrictions_count << " restrictions";
|
||||
}
|
||||
|
||||
int EdgeBasedGraphFactory::GetTurnPenalty(
|
||||
const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w,
|
||||
lua_State *lua_state
|
||||
) const {
|
||||
const double angle = GetAngleBetweenThreeFixedPointCoordinates (
|
||||
m_node_info_list[u],
|
||||
m_node_info_list[v],
|
||||
m_node_info_list[w]
|
||||
);
|
||||
|
||||
if( speed_profile.has_turn_penalty_function ) {
|
||||
try {
|
||||
//call lua profile to compute turn penalty
|
||||
return luabind::call_function<int>(
|
||||
lua_state,
|
||||
"turn_function",
|
||||
180.-angle
|
||||
);
|
||||
} catch (const luabind::error &er) {
|
||||
SimpleLogger().Write(logWARNING) << er.what();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(
|
||||
const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w
|
||||
) const {
|
||||
if(u == w) {
|
||||
return TurnInstructions.UTurn;
|
||||
}
|
||||
|
||||
EdgeIterator edge1 = m_node_based_graph->FindEdge(u, v);
|
||||
EdgeIterator edge2 = m_node_based_graph->FindEdge(v, w);
|
||||
|
||||
EdgeData & data1 = m_node_based_graph->GetEdgeData(edge1);
|
||||
EdgeData & data2 = m_node_based_graph->GetEdgeData(edge2);
|
||||
|
||||
if(!data1.contraFlow && data2.contraFlow) {
|
||||
return TurnInstructions.EnterAgainstAllowedDirection;
|
||||
}
|
||||
if(data1.contraFlow && !data2.contraFlow) {
|
||||
return TurnInstructions.LeaveAgainstAllowedDirection;
|
||||
}
|
||||
|
||||
//roundabouts need to be handled explicitely
|
||||
if(data1.roundabout && data2.roundabout) {
|
||||
//Is a turn possible? If yes, we stay on the roundabout!
|
||||
if( 1 == m_node_based_graph->GetOutDegree(v) ) {
|
||||
//No turn possible.
|
||||
return TurnInstructions.NoTurn;
|
||||
}
|
||||
return TurnInstructions.StayOnRoundAbout;
|
||||
}
|
||||
//Does turn start or end on roundabout?
|
||||
if(data1.roundabout || data2.roundabout) {
|
||||
//We are entering the roundabout
|
||||
if( (!data1.roundabout) && data2.roundabout) {
|
||||
return TurnInstructions.EnterRoundAbout;
|
||||
}
|
||||
//We are leaving the roundabout
|
||||
if(data1.roundabout && (!data2.roundabout) ) {
|
||||
return TurnInstructions.LeaveRoundAbout;
|
||||
}
|
||||
}
|
||||
|
||||
//If street names stay the same and if we are certain that it is not a
|
||||
//a segment of a roundabout, we skip it.
|
||||
if( data1.nameID == data2.nameID ) {
|
||||
//TODO: Here we should also do a small graph exploration to check for
|
||||
// more complex situations
|
||||
if( 0 != data1.nameID ) {
|
||||
return TurnInstructions.NoTurn;
|
||||
} else if (m_node_based_graph->GetOutDegree(v) <= 2) {
|
||||
return TurnInstructions.NoTurn;
|
||||
}
|
||||
}
|
||||
|
||||
const double angle = GetAngleBetweenThreeFixedPointCoordinates (
|
||||
m_node_info_list[u],
|
||||
m_node_info_list[v],
|
||||
m_node_info_list[w]
|
||||
);
|
||||
|
||||
return TurnInstructions.GetTurnDirectionOfInstruction(angle);
|
||||
}
|
||||
|
||||
unsigned EdgeBasedGraphFactory::GetNumberOfNodes() const {
|
||||
return m_node_based_graph->GetNumberOfEdges();
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// This class constructs the edge-expanded routing graph
|
||||
|
||||
#ifndef EDGEBASEDGRAPHFACTORY_H_
|
||||
#define EDGEBASEDGRAPHFACTORY_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../DataStructures/EdgeBasedNode.h"
|
||||
#include "../Extractor/ExtractorStructs.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/ImportEdge.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/LuaUtil.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
class EdgeBasedGraphFactory : boost::noncopyable {
|
||||
public:
|
||||
struct SpeedProfileProperties{
|
||||
SpeedProfileProperties() :
|
||||
trafficSignalPenalty(0),
|
||||
uTurnPenalty(0),
|
||||
has_turn_penalty_function(false)
|
||||
{ }
|
||||
|
||||
int trafficSignalPenalty;
|
||||
int uTurnPenalty;
|
||||
bool has_turn_penalty_function;
|
||||
} speed_profile;
|
||||
|
||||
explicit EdgeBasedGraphFactory(
|
||||
int number_of_nodes,
|
||||
std::vector<ImportEdge> & input_edge_list,
|
||||
std::vector<NodeID> & barrier_node_list,
|
||||
std::vector<NodeID> & traffic_light_node_list,
|
||||
std::vector<TurnRestriction> & input_restrictions_list,
|
||||
std::vector<NodeInfo> & m_node_info_list,
|
||||
SpeedProfileProperties speed_profile
|
||||
);
|
||||
|
||||
void Run(const char * originalEdgeDataFilename, lua_State *myLuaState);
|
||||
void GetEdgeBasedEdges( DeallocatingVector< EdgeBasedEdge >& edges );
|
||||
void GetEdgeBasedNodes( std::vector< EdgeBasedNode> & nodes);
|
||||
void GetOriginalEdgeData( std::vector<OriginalEdgeData> & originalEdgeData);
|
||||
TurnInstruction AnalyzeTurn(
|
||||
const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w
|
||||
) const;
|
||||
int GetTurnPenalty(
|
||||
const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w,
|
||||
lua_State *myLuaState
|
||||
) const;
|
||||
|
||||
unsigned GetNumberOfNodes() const;
|
||||
|
||||
private:
|
||||
struct NodeBasedEdgeData {
|
||||
int distance;
|
||||
unsigned edgeBasedNodeID;
|
||||
unsigned nameID;
|
||||
short type;
|
||||
bool isAccessRestricted:1;
|
||||
bool shortcut:1;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
bool roundabout:1;
|
||||
bool ignoreInGrid:1;
|
||||
bool contraFlow:1;
|
||||
};
|
||||
|
||||
struct _EdgeBasedEdgeData {
|
||||
int distance;
|
||||
unsigned via;
|
||||
unsigned nameID;
|
||||
bool forward;
|
||||
bool backward;
|
||||
TurnInstruction turnInstruction;
|
||||
};
|
||||
|
||||
unsigned m_turn_restrictions_count;
|
||||
|
||||
typedef DynamicGraph<NodeBasedEdgeData> NodeBasedDynamicGraph;
|
||||
typedef NodeBasedDynamicGraph::InputEdge NodeBasedEdge;
|
||||
typedef NodeBasedDynamicGraph::NodeIterator NodeIterator;
|
||||
typedef NodeBasedDynamicGraph::EdgeIterator EdgeIterator;
|
||||
typedef NodeBasedDynamicGraph::EdgeData EdgeData;
|
||||
typedef std::pair<NodeID, NodeID> RestrictionSource;
|
||||
typedef std::pair<NodeID, bool> RestrictionTarget;
|
||||
typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector;
|
||||
typedef boost::unordered_map<RestrictionSource, unsigned > RestrictionMap;
|
||||
|
||||
std::vector<NodeInfo> m_node_info_list;
|
||||
std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
|
||||
std::vector<EdgeBasedNode> m_edge_based_node_list;
|
||||
DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
|
||||
|
||||
boost::shared_ptr<NodeBasedDynamicGraph> m_node_based_graph;
|
||||
boost::unordered_set<NodeID> m_barrier_nodes;
|
||||
boost::unordered_set<NodeID> m_traffic_lights;
|
||||
|
||||
RestrictionMap m_restriction_map;
|
||||
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
#endif /* EDGEBASEDGRAPHFACTORY_H_ */
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "TemporaryStorage.h"
|
||||
|
||||
TemporaryStorage::TemporaryStorage() {
|
||||
tempDirectory = boost::filesystem::temp_directory_path();
|
||||
}
|
||||
|
||||
TemporaryStorage & TemporaryStorage::GetInstance(){
|
||||
static TemporaryStorage runningInstance;
|
||||
return runningInstance;
|
||||
}
|
||||
|
||||
TemporaryStorage::~TemporaryStorage() {
|
||||
removeAll();
|
||||
}
|
||||
|
||||
void TemporaryStorage::removeAll() {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
for(unsigned slot_id = 0; slot_id < vectorOfStreamDatas.size(); ++slot_id) {
|
||||
deallocateSlot(slot_id);
|
||||
}
|
||||
vectorOfStreamDatas.clear();
|
||||
}
|
||||
|
||||
int TemporaryStorage::allocateSlot() {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
try {
|
||||
vectorOfStreamDatas.push_back(StreamData());
|
||||
//SimpleLogger().Write() << "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();
|
||||
}
|
||||
|
||||
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);
|
||||
BOOST_ASSERT_MSG(
|
||||
data.writeMode,
|
||||
"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);
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
void TemporaryStorage::abort(boost::filesystem::filesystem_error& ) {
|
||||
removeAll();
|
||||
}
|
||||
|
||||
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);
|
||||
} catch(boost::filesystem::filesystem_error & e) {
|
||||
abort(e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TEMPORARYSTORAGE_H_
|
||||
#define TEMPORARYSTORAGE_H_
|
||||
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
//This is one big workaround for latest boost renaming woes.
|
||||
|
||||
#if BOOST_FILESYSTEM_VERSION < 3
|
||||
#warning Boost Installation with Filesystem3 missing, activating workaround
|
||||
#include <cstdio>
|
||||
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
|
||||
|
||||
#ifndef BOOST_FILESYSTEM_VERSION
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
#endif
|
||||
/**
|
||||
* 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()) {
|
||||
throw OSRMException("temporary file 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_ */
|
||||
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BINARYHEAP_H_INCLUDED
|
||||
#define BINARYHEAP_H_INCLUDED
|
||||
|
||||
//Not compatible with non contiguous node ids
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class ArrayStorage {
|
||||
public:
|
||||
|
||||
ArrayStorage( size_t size ) : positions( new Key[size] ) {
|
||||
memset(positions, 0, size*sizeof(Key));
|
||||
}
|
||||
|
||||
~ArrayStorage() {
|
||||
delete[] positions;
|
||||
}
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return positions[node];
|
||||
}
|
||||
|
||||
void Clear() {}
|
||||
|
||||
private:
|
||||
Key* positions;
|
||||
};
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class MapStorage {
|
||||
public:
|
||||
|
||||
MapStorage( size_t ) {}
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return nodes[node];
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::map< NodeID, Key > nodes;
|
||||
|
||||
};
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class UnorderedMapStorage {
|
||||
public:
|
||||
|
||||
UnorderedMapStorage( size_t ) {
|
||||
//hash table gets 1000 Buckets
|
||||
nodes.rehash(1000);
|
||||
}
|
||||
|
||||
Key &operator[]( const NodeID node ) {
|
||||
return nodes[node];
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::unordered_map< NodeID, Key > nodes;
|
||||
};
|
||||
|
||||
template<typename NodeID = unsigned>
|
||||
struct _SimpleHeapData {
|
||||
NodeID parent;
|
||||
_SimpleHeapData( NodeID p ) : parent(p) { }
|
||||
};
|
||||
|
||||
template < typename NodeID, typename Key, typename Weight, typename Data, typename IndexStorage = ArrayStorage<NodeID, NodeID> >
|
||||
class BinaryHeap {
|
||||
private:
|
||||
BinaryHeap( const BinaryHeap& right );
|
||||
void operator=( const BinaryHeap& right );
|
||||
public:
|
||||
typedef Weight WeightType;
|
||||
typedef Data DataType;
|
||||
|
||||
BinaryHeap( size_t maxID )
|
||||
: nodeIndex( maxID ) {
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
heap.resize( 1 );
|
||||
insertedNodes.clear();
|
||||
heap[0].weight = std::numeric_limits< Weight >::min();
|
||||
nodeIndex.Clear();
|
||||
}
|
||||
|
||||
Key Size() const {
|
||||
return static_cast<Key>( heap.size() - 1 );
|
||||
}
|
||||
|
||||
bool Empty() const {
|
||||
return 0 == Size();
|
||||
}
|
||||
|
||||
void Insert( NodeID node, Weight weight, const Data &data ) {
|
||||
HeapElement element;
|
||||
element.index = static_cast<NodeID>(insertedNodes.size());
|
||||
element.weight = weight;
|
||||
const Key key = static_cast<Key>(heap.size());
|
||||
heap.push_back( element );
|
||||
insertedNodes.push_back( HeapNode( node, key, weight, data ) );
|
||||
nodeIndex[node] = element.index;
|
||||
Upheap( key );
|
||||
CheckHeap();
|
||||
}
|
||||
|
||||
Data& GetData( NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].data;
|
||||
}
|
||||
|
||||
Weight& GetKey( NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].weight;
|
||||
}
|
||||
|
||||
bool WasRemoved( const NodeID node ) {
|
||||
BOOST_ASSERT( WasInserted( node ) );
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].key == 0;
|
||||
}
|
||||
|
||||
bool WasInserted( const NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
if ( index >= static_cast<Key> (insertedNodes.size()) )
|
||||
return false;
|
||||
return insertedNodes[index].node == node;
|
||||
}
|
||||
|
||||
NodeID Min() const {
|
||||
BOOST_ASSERT( heap.size() > 1 );
|
||||
return insertedNodes[heap[1].index].node;
|
||||
}
|
||||
|
||||
NodeID DeleteMin() {
|
||||
BOOST_ASSERT( heap.size() > 1 );
|
||||
const Key removedIndex = heap[1].index;
|
||||
heap[1] = heap[heap.size()-1];
|
||||
heap.pop_back();
|
||||
if ( heap.size() > 1 )
|
||||
Downheap( 1 );
|
||||
insertedNodes[removedIndex].key = 0;
|
||||
CheckHeap();
|
||||
return insertedNodes[removedIndex].node;
|
||||
}
|
||||
|
||||
void DeleteAll() {
|
||||
for ( typename std::vector< HeapElement >::iterator i = heap.begin() + 1, iend = heap.end(); i != iend; ++i )
|
||||
insertedNodes[i->index].key = 0;
|
||||
heap.resize( 1 );
|
||||
heap[0].weight = (std::numeric_limits< Weight >::min)();
|
||||
}
|
||||
|
||||
void DecreaseKey( NodeID node, Weight weight ) {
|
||||
BOOST_ASSERT( UINT_MAX != node );
|
||||
const Key & index = nodeIndex[node];
|
||||
Key & key = insertedNodes[index].key;
|
||||
BOOST_ASSERT ( key >= 0 );
|
||||
|
||||
insertedNodes[index].weight = weight;
|
||||
heap[key].weight = weight;
|
||||
Upheap( key );
|
||||
CheckHeap();
|
||||
}
|
||||
|
||||
private:
|
||||
class HeapNode {
|
||||
public:
|
||||
HeapNode() {
|
||||
}
|
||||
HeapNode( NodeID n, Key k, Weight w, Data d )
|
||||
: node( n ), key( k ), weight( w ), data( d ) {
|
||||
}
|
||||
|
||||
NodeID node;
|
||||
Key key;
|
||||
Weight weight;
|
||||
Data data;
|
||||
};
|
||||
struct HeapElement {
|
||||
Key index;
|
||||
Weight weight;
|
||||
};
|
||||
|
||||
std::vector< HeapNode > insertedNodes;
|
||||
std::vector< HeapElement > heap;
|
||||
IndexStorage nodeIndex;
|
||||
|
||||
void Downheap( Key key ) {
|
||||
const Key droppingIndex = heap[key].index;
|
||||
const Weight weight = heap[key].weight;
|
||||
Key nextKey = key << 1;
|
||||
while ( nextKey < static_cast<Key>( heap.size() ) ) {
|
||||
const Key nextKeyOther = nextKey + 1;
|
||||
if ( ( nextKeyOther < static_cast<Key> ( heap.size() ) )&& ( heap[nextKey].weight > heap[nextKeyOther].weight) )
|
||||
nextKey = nextKeyOther;
|
||||
|
||||
if ( weight <= heap[nextKey].weight )
|
||||
break;
|
||||
|
||||
heap[key] = heap[nextKey];
|
||||
insertedNodes[heap[key].index].key = key;
|
||||
key = nextKey;
|
||||
nextKey <<= 1;
|
||||
}
|
||||
heap[key].index = droppingIndex;
|
||||
heap[key].weight = weight;
|
||||
insertedNodes[droppingIndex].key = key;
|
||||
}
|
||||
|
||||
void Upheap( Key key ) {
|
||||
const Key risingIndex = heap[key].index;
|
||||
const Weight weight = heap[key].weight;
|
||||
Key nextKey = key >> 1;
|
||||
while ( heap[nextKey].weight > weight ) {
|
||||
BOOST_ASSERT( nextKey != 0 );
|
||||
heap[key] = heap[nextKey];
|
||||
insertedNodes[heap[key].index].key = key;
|
||||
key = nextKey;
|
||||
nextKey >>= 1;
|
||||
}
|
||||
heap[key].index = risingIndex;
|
||||
heap[key].weight = weight;
|
||||
insertedNodes[risingIndex].key = key;
|
||||
}
|
||||
|
||||
void CheckHeap() {
|
||||
#ifndef NDEBUG
|
||||
for ( Key i = 2; i < (Key) heap.size(); ++i ) {
|
||||
BOOST_ASSERT( heap[i].weight >= heap[i >> 1].weight );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#endif //#ifndef BINARYHEAP_H_INCLUDED
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CONCURRENTQUEUE_H_
|
||||
#define CONCURRENTQUEUE_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
template<typename Data>
|
||||
class ConcurrentQueue {
|
||||
|
||||
public:
|
||||
ConcurrentQueue(const size_t max_size) : m_internal_queue(max_size) { }
|
||||
|
||||
inline void push(const Data & data) {
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
m_not_full.wait(
|
||||
lock,
|
||||
boost::bind(&ConcurrentQueue<Data>::is_not_full, this)
|
||||
);
|
||||
m_internal_queue.push_back(data);
|
||||
lock.unlock();
|
||||
m_not_empty.notify_one();
|
||||
}
|
||||
|
||||
inline bool empty() const {
|
||||
return m_internal_queue.empty();
|
||||
}
|
||||
|
||||
inline void wait_and_pop(Data & popped_value) {
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
m_not_empty.wait(
|
||||
lock,
|
||||
boost::bind(&ConcurrentQueue<Data>::is_not_empty, this)
|
||||
);
|
||||
popped_value = m_internal_queue.front();
|
||||
m_internal_queue.pop_front();
|
||||
lock.unlock();
|
||||
m_not_full.notify_one();
|
||||
}
|
||||
|
||||
inline bool try_pop(Data& popped_value) {
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
if(m_internal_queue.empty()) {
|
||||
return false;
|
||||
}
|
||||
popped_value=m_internal_queue.front();
|
||||
m_internal_queue.pop_front();
|
||||
lock.unlock();
|
||||
m_not_full.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
inline bool is_not_empty() const {
|
||||
return !m_internal_queue.empty();
|
||||
}
|
||||
|
||||
inline bool is_not_full() const {
|
||||
return m_internal_queue.size() < m_internal_queue.capacity();
|
||||
}
|
||||
|
||||
boost::circular_buffer<Data> m_internal_queue;
|
||||
boost::mutex m_mutex;
|
||||
boost::condition m_not_empty;
|
||||
boost::condition m_not_full;
|
||||
};
|
||||
|
||||
#endif /* CONCURRENTQUEUE_H_ */
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FIXED_POINT_COORDINATE_H_
|
||||
#define FIXED_POINT_COORDINATE_H_
|
||||
|
||||
#include "../DataStructures/MercatorUtil.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <cmath>
|
||||
#include <climits>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
static const double COORDINATE_PRECISION = 1000000.;
|
||||
|
||||
struct FixedPointCoordinate {
|
||||
int lat;
|
||||
int lon;
|
||||
FixedPointCoordinate () : lat(INT_MIN), lon(INT_MIN) {}
|
||||
explicit FixedPointCoordinate (int lat, int lon) : lat(lat) , lon(lon) {}
|
||||
|
||||
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*COORDINATE_PRECISION ||
|
||||
lat < -90*COORDINATE_PRECISION ||
|
||||
lon > 180*COORDINATE_PRECISION ||
|
||||
lon < -180*COORDINATE_PRECISION
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool operator==(const FixedPointCoordinate & other) const {
|
||||
return lat == other.lat && lon == other.lon;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & out, const FixedPointCoordinate & c){
|
||||
out << "(" << c.lat << "," << c.lon << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
inline double ApproximateDistance( const int lat1, const int lon1, const int lat2, const int lon2 ) {
|
||||
BOOST_ASSERT(lat1 != INT_MIN);
|
||||
BOOST_ASSERT(lon1 != INT_MIN);
|
||||
BOOST_ASSERT(lat2 != INT_MIN);
|
||||
BOOST_ASSERT(lon2 != INT_MIN);
|
||||
double RAD = 0.017453292519943295769236907684886;
|
||||
double lt1 = lat1/COORDINATE_PRECISION;
|
||||
double ln1 = lon1/COORDINATE_PRECISION;
|
||||
double lt2 = lat2/COORDINATE_PRECISION;
|
||||
double ln2 = lon2/COORDINATE_PRECISION;
|
||||
double dlat1=lt1*(RAD);
|
||||
|
||||
double dlong1=ln1*(RAD);
|
||||
double dlat2=lt2*(RAD);
|
||||
double dlong2=ln2*(RAD);
|
||||
|
||||
double dLong=dlong1-dlong2;
|
||||
double dLat=dlat1-dlat2;
|
||||
|
||||
double aHarv= pow(sin(dLat/2.0),2.0)+cos(dlat1)*cos(dlat2)*pow(sin(dLong/2.),2);
|
||||
double cHarv=2.*atan2(sqrt(aHarv),sqrt(1.0-aHarv));
|
||||
//earth'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 FixedPointCoordinate &c1, const FixedPointCoordinate &c2) {
|
||||
return ApproximateDistance( c1.lat, c1.lon, c2.lat, c2.lon );
|
||||
}
|
||||
|
||||
inline double ApproximateEuclideanDistance(const FixedPointCoordinate &c1, const FixedPointCoordinate &c2) {
|
||||
BOOST_ASSERT(c1.lat != INT_MIN);
|
||||
BOOST_ASSERT(c1.lon != INT_MIN);
|
||||
BOOST_ASSERT(c2.lat != INT_MIN);
|
||||
BOOST_ASSERT(c2.lon != INT_MIN);
|
||||
const double RAD = 0.017453292519943295769236907684886;
|
||||
const double lat1 = (c1.lat/COORDINATE_PRECISION)*RAD;
|
||||
const double lon1 = (c1.lon/COORDINATE_PRECISION)*RAD;
|
||||
const double lat2 = (c2.lat/COORDINATE_PRECISION)*RAD;
|
||||
const double lon2 = (c2.lon/COORDINATE_PRECISION)*RAD;
|
||||
|
||||
const double x = (lon2-lon1) * cos((lat1+lat2)/2.);
|
||||
const double y = (lat2-lat1);
|
||||
const double earthRadius = 6372797.560856;
|
||||
const double d = sqrt(x*x + y*y) * earthRadius;
|
||||
return d;
|
||||
}
|
||||
|
||||
static inline void convertInternalLatLonToString(const int value, std::string & output) {
|
||||
char buffer[100];
|
||||
buffer[11] = 0; // zero termination
|
||||
char* string = printInt< 11, 6 >( buffer, value );
|
||||
output = string;
|
||||
}
|
||||
|
||||
static inline void convertInternalCoordinateToString(const FixedPointCoordinate & coord, std::string & output) {
|
||||
std::string tmp;
|
||||
convertInternalLatLonToString(coord.lon, tmp);
|
||||
output = tmp;
|
||||
output += ",";
|
||||
convertInternalLatLonToString(coord.lat, tmp);
|
||||
output += tmp;
|
||||
output += " ";
|
||||
}
|
||||
static inline void convertInternalReversedCoordinateToString(const FixedPointCoordinate & coord, std::string & output) {
|
||||
std::string tmp;
|
||||
convertInternalLatLonToString(coord.lat, tmp);
|
||||
output = tmp;
|
||||
output += ",";
|
||||
convertInternalLatLonToString(coord.lon, tmp);
|
||||
output += tmp;
|
||||
output += " ";
|
||||
}
|
||||
|
||||
|
||||
/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
|
||||
template<class CoordinateT>
|
||||
static inline double GetAngleBetweenThreeFixedPointCoordinates (
|
||||
const CoordinateT & A,
|
||||
const CoordinateT & C,
|
||||
const CoordinateT & B
|
||||
) {
|
||||
const double v1x = (A.lon - C.lon)/COORDINATE_PRECISION;
|
||||
const double v1y = lat2y(A.lat/COORDINATE_PRECISION) - lat2y(C.lat/COORDINATE_PRECISION);
|
||||
const double v2x = (B.lon - C.lon)/COORDINATE_PRECISION;
|
||||
const double v2y = lat2y(B.lat/COORDINATE_PRECISION) - lat2y(C.lat/COORDINATE_PRECISION);
|
||||
|
||||
double angle = (atan2(v2y,v2x) - atan2(v1y,v1x) )*180/M_PI;
|
||||
while(angle < 0)
|
||||
angle += 360;
|
||||
return angle;
|
||||
}
|
||||
#endif /* FIXED_POINT_COORDINATE_H_ */
|
||||
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DEALLOCATINGVECTOR_H_
|
||||
#define DEALLOCATINGVECTOR_H_
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#if __cplusplus > 199711L
|
||||
#define DEALLOCATION_VECTOR_NULL_PTR nullptr
|
||||
#else
|
||||
#define DEALLOCATION_VECTOR_NULL_PTR NULL
|
||||
#endif
|
||||
|
||||
|
||||
template<typename ElementT, std::size_t bucketSizeC = 8388608/sizeof(ElementT), bool DeallocateC = false>
|
||||
class DeallocatingVectorIterator : public std::iterator<std::random_access_iterator_tag, ElementT> {
|
||||
protected:
|
||||
|
||||
class DeallocatingVectorIteratorState {
|
||||
private:
|
||||
//make constructors explicit, so we do not mix random access and deallocation iterators.
|
||||
DeallocatingVectorIteratorState();
|
||||
public:
|
||||
explicit DeallocatingVectorIteratorState(const DeallocatingVectorIteratorState &r) : /*mData(r.mData),*/ mIndex(r.mIndex), mBucketList(r.mBucketList) {}
|
||||
explicit DeallocatingVectorIteratorState(const std::size_t idx, std::vector<ElementT *> & input_list) : /*mData(DEALLOCATION_VECTOR_NULL_PTR),*/ mIndex(idx), mBucketList(input_list) {
|
||||
}
|
||||
std::size_t mIndex;
|
||||
std::vector<ElementT *> & mBucketList;
|
||||
|
||||
inline bool operator!=(const DeallocatingVectorIteratorState &other) {
|
||||
return mIndex != other.mIndex;
|
||||
}
|
||||
|
||||
inline bool operator==(const DeallocatingVectorIteratorState &other) {
|
||||
return mIndex == other.mIndex;
|
||||
}
|
||||
|
||||
bool operator<(const DeallocatingVectorIteratorState &other) const {
|
||||
return mIndex < other.mIndex;
|
||||
}
|
||||
|
||||
bool operator>(const DeallocatingVectorIteratorState &other) const {
|
||||
return mIndex > other.mIndex;
|
||||
}
|
||||
|
||||
bool operator>=(const DeallocatingVectorIteratorState &other) const {
|
||||
return mIndex >= other.mIndex;
|
||||
}
|
||||
|
||||
//This is a hack to make assignment operator possible with reference member
|
||||
inline DeallocatingVectorIteratorState& operator= (const DeallocatingVectorIteratorState &a) {
|
||||
if (this != &a) {
|
||||
this->DeallocatingVectorIteratorState::~DeallocatingVectorIteratorState(); // explicit non-virtual destructor
|
||||
new (this) DeallocatingVectorIteratorState(a); // placement new
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
DeallocatingVectorIteratorState mState;
|
||||
|
||||
public:
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::value_type value_type;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::difference_type difference_type;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::reference reference;
|
||||
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::pointer pointer;
|
||||
|
||||
DeallocatingVectorIterator() {}
|
||||
|
||||
template<typename T2>
|
||||
DeallocatingVectorIterator(const DeallocatingVectorIterator<T2> & r) : mState(r.mState) {}
|
||||
|
||||
DeallocatingVectorIterator(std::size_t idx, 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) BOOST_ASSERT(false);
|
||||
mState = r.mState; return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator& operator++() { //prefix
|
||||
++mState.mIndex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator& operator--() { //prefix
|
||||
if(DeallocateC) BOOST_ASSERT(false);
|
||||
--mState.mIndex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator operator++(int) { //postfix
|
||||
DeallocatingVectorIteratorState _myState(mState);
|
||||
mState.mIndex++;
|
||||
return DeallocatingVectorIterator(_myState);
|
||||
}
|
||||
inline DeallocatingVectorIterator operator--(int) { //postfix
|
||||
if(DeallocateC) BOOST_ASSERT(false);
|
||||
DeallocatingVectorIteratorState _myState(mState);
|
||||
mState.mIndex--;
|
||||
return DeallocatingVectorIterator(_myState);
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator operator+(const difference_type& n) const {
|
||||
DeallocatingVectorIteratorState _myState(mState);
|
||||
_myState.mIndex+=n;
|
||||
return DeallocatingVectorIterator(_myState);
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator& operator+=(const difference_type& n) {
|
||||
mState.mIndex+=n; return *this;
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator operator-(const difference_type& n) const {
|
||||
if(DeallocateC) BOOST_ASSERT(false);
|
||||
DeallocatingVectorIteratorState _myState(mState);
|
||||
_myState.mIndex-=n;
|
||||
return DeallocatingVectorIterator(_myState);
|
||||
}
|
||||
|
||||
inline DeallocatingVectorIterator& operator-=(const difference_type &n) const {
|
||||
if(DeallocateC) BOOST_ASSERT(false);
|
||||
mState.mIndex-=n; return *this;
|
||||
}
|
||||
|
||||
inline reference operator*() const {
|
||||
std::size_t _bucket = mState.mIndex/bucketSizeC;
|
||||
std::size_t _index = mState.mIndex%bucketSizeC;
|
||||
return (mState.mBucketList[_bucket][_index]);
|
||||
}
|
||||
|
||||
inline pointer operator->() const {
|
||||
std::size_t _bucket = mState.mIndex/bucketSizeC;
|
||||
std::size_t _index = mState.mIndex%bucketSizeC;
|
||||
return &(mState.mBucketList[_bucket][_index]);
|
||||
}
|
||||
|
||||
inline bool operator!=(const DeallocatingVectorIterator & other) {
|
||||
return mState != other.mState;
|
||||
}
|
||||
|
||||
inline bool operator==(const DeallocatingVectorIterator & other) {
|
||||
return mState == other.mState;
|
||||
}
|
||||
|
||||
inline bool operator<(const DeallocatingVectorIterator & other) const {
|
||||
return mState < other.mState;
|
||||
}
|
||||
|
||||
inline bool operator>(const DeallocatingVectorIterator & other) const {
|
||||
return mState > other.mState;
|
||||
}
|
||||
|
||||
inline bool operator>=(const DeallocatingVectorIterator & other) const {
|
||||
return mState >= other.mState;
|
||||
}
|
||||
|
||||
difference_type operator-(const DeallocatingVectorIterator & other) {
|
||||
if(DeallocateC) BOOST_ASSERT(false);
|
||||
return mState.mIndex-other.mState.mIndex;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ElementT, std::size_t bucketSizeC = 8388608/sizeof(ElementT) >
|
||||
class DeallocatingVector {
|
||||
private:
|
||||
std::size_t mCurrentSize;
|
||||
std::vector<ElementT *> mBucketList;
|
||||
|
||||
public:
|
||||
typedef ElementT value_type;
|
||||
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> iterator;
|
||||
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> const_iterator;
|
||||
|
||||
//this iterator deallocates all buckets that have been visited. Iterators to visited objects become invalid.
|
||||
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, true> deallocation_iterator;
|
||||
|
||||
DeallocatingVector() : mCurrentSize(0) {
|
||||
//initial bucket
|
||||
mBucketList.push_back(new ElementT[bucketSizeC]);
|
||||
}
|
||||
|
||||
~DeallocatingVector() {
|
||||
clear();
|
||||
}
|
||||
|
||||
inline void swap(DeallocatingVector<ElementT, bucketSizeC> & other) {
|
||||
std::swap(mCurrentSize, other.mCurrentSize);
|
||||
mBucketList.swap(other.mBucketList);
|
||||
}
|
||||
|
||||
inline void clear() {
|
||||
//Delete[]'ing ptr's to all Buckets
|
||||
for(unsigned i = 0; i < mBucketList.size(); ++i) {
|
||||
if(DEALLOCATION_VECTOR_NULL_PTR != mBucketList[i]) {
|
||||
delete[] mBucketList[i];
|
||||
mBucketList[i] = DEALLOCATION_VECTOR_NULL_PTR;
|
||||
}
|
||||
}
|
||||
//Removing all ptrs from vector
|
||||
std::vector<ElementT *>().swap(mBucketList);
|
||||
mCurrentSize = 0;
|
||||
}
|
||||
|
||||
inline void push_back(const ElementT & element) {
|
||||
std::size_t _capacity = capacity();
|
||||
if(mCurrentSize == _capacity) {
|
||||
mBucketList.push_back(new ElementT[bucketSizeC]);
|
||||
}
|
||||
|
||||
std::size_t _index = size()%bucketSizeC;
|
||||
mBucketList.back()[_index] = element;
|
||||
++mCurrentSize;
|
||||
}
|
||||
|
||||
inline void reserve(const std::size_t) const {
|
||||
//don't do anything
|
||||
}
|
||||
|
||||
inline void resize(const std::size_t new_size) {
|
||||
if(new_size > mCurrentSize) {
|
||||
while(capacity() < new_size) {
|
||||
mBucketList.push_back(new ElementT[bucketSizeC]);
|
||||
}
|
||||
mCurrentSize = new_size;
|
||||
}
|
||||
if(new_size < mCurrentSize) {
|
||||
std::size_t number_of_necessary_buckets = 1+(new_size / bucketSizeC);
|
||||
|
||||
for(unsigned i = number_of_necessary_buckets; i < mBucketList.size(); ++i) {
|
||||
delete[] mBucketList[i];
|
||||
}
|
||||
mBucketList.resize(number_of_necessary_buckets);
|
||||
mCurrentSize = new_size;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::size_t size() const {
|
||||
return mCurrentSize;
|
||||
}
|
||||
|
||||
inline std::size_t capacity() const {
|
||||
return mBucketList.size() * bucketSizeC;
|
||||
}
|
||||
|
||||
inline iterator begin() {
|
||||
return iterator(static_cast<std::size_t>(0), mBucketList);
|
||||
}
|
||||
|
||||
inline iterator end() {
|
||||
return iterator(size(), mBucketList);
|
||||
}
|
||||
|
||||
inline deallocation_iterator dbegin() {
|
||||
return deallocation_iterator(static_cast<std::size_t>(0), mBucketList);
|
||||
}
|
||||
|
||||
inline deallocation_iterator dend() {
|
||||
return deallocation_iterator(size(), mBucketList);
|
||||
}
|
||||
|
||||
inline const_iterator begin() const {
|
||||
return const_iterator(static_cast<std::size_t>(0), mBucketList);
|
||||
}
|
||||
|
||||
inline const_iterator end() const {
|
||||
return const_iterator(size(), mBucketList);
|
||||
}
|
||||
|
||||
inline ElementT & operator[](const std::size_t index) {
|
||||
std::size_t _bucket = index / bucketSizeC;
|
||||
std::size_t _index = index % bucketSizeC;
|
||||
return (mBucketList[_bucket][_index]);
|
||||
}
|
||||
|
||||
const inline ElementT & operator[](const std::size_t index) const {
|
||||
std::size_t _bucket = index / bucketSizeC;
|
||||
std::size_t _index = index % bucketSizeC;
|
||||
return (mBucketList[_bucket][_index]);
|
||||
}
|
||||
|
||||
inline ElementT & back() {
|
||||
std::size_t _bucket = mCurrentSize / bucketSizeC;
|
||||
std::size_t _index = mCurrentSize % bucketSizeC;
|
||||
return (mBucketList[_bucket][_index]);
|
||||
}
|
||||
|
||||
const inline ElementT & back() const {
|
||||
std::size_t _bucket = mCurrentSize / bucketSizeC;
|
||||
std::size_t _index = mCurrentSize % bucketSizeC;
|
||||
return (mBucketList[_bucket][_index]);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DEALLOCATINGVECTOR_H_ */
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DYNAMICGRAPH_H_INCLUDED
|
||||
#define DYNAMICGRAPH_H_INCLUDED
|
||||
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/integer.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
template< typename EdgeDataT>
|
||||
class DynamicGraph {
|
||||
public:
|
||||
typedef EdgeDataT EdgeData;
|
||||
typedef uint32_t NodeIterator;
|
||||
typedef uint32_t EdgeIterator;
|
||||
|
||||
class InputEdge {
|
||||
public:
|
||||
NodeIterator source;
|
||||
NodeIterator target;
|
||||
EdgeDataT data;
|
||||
bool operator<( const InputEdge& right ) const {
|
||||
if ( source != right.source )
|
||||
return source < right.source;
|
||||
return target < right.target;
|
||||
}
|
||||
};
|
||||
|
||||
//Constructs an empty graph with a given number of nodes.
|
||||
DynamicGraph( int32_t nodes ) : m_numNodes(nodes), m_numEdges(0) {
|
||||
m_nodes.reserve( m_numNodes );
|
||||
m_nodes.resize( m_numNodes );
|
||||
|
||||
m_edges.reserve( m_numNodes * 1.1 );
|
||||
m_edges.resize( m_numNodes );
|
||||
}
|
||||
|
||||
template<class ContainerT>
|
||||
DynamicGraph( const int32_t nodes, const ContainerT &graph ) {
|
||||
m_numNodes = nodes;
|
||||
m_numEdges = ( EdgeIterator ) graph.size();
|
||||
m_nodes.reserve( m_numNodes +1);
|
||||
m_nodes.resize( m_numNodes +1);
|
||||
EdgeIterator edge = 0;
|
||||
EdgeIterator position = 0;
|
||||
for ( NodeIterator node = 0; node < m_numNodes; ++node ) {
|
||||
EdgeIterator lastEdge = edge;
|
||||
while ( edge < m_numEdges && graph[edge].source == node ) {
|
||||
++edge;
|
||||
}
|
||||
m_nodes[node].firstEdge = position;
|
||||
m_nodes[node].edges = edge - lastEdge;
|
||||
position += m_nodes[node].edges;
|
||||
}
|
||||
m_nodes.back().firstEdge = position;
|
||||
m_edges.reserve( position * 1.1 );
|
||||
m_edges.resize( position );
|
||||
edge = 0;
|
||||
for ( NodeIterator node = 0; node < m_numNodes; ++node ) {
|
||||
for ( EdgeIterator i = m_nodes[node].firstEdge, e = m_nodes[node].firstEdge + m_nodes[node].edges; i != e; ++i ) {
|
||||
m_edges[i].target = graph[edge].target;
|
||||
m_edges[i].data = graph[edge].data;
|
||||
BOOST_ASSERT_MSG(
|
||||
graph[edge].data.distance > 0,
|
||||
"edge distance invalid"
|
||||
);
|
||||
++edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~DynamicGraph(){ }
|
||||
|
||||
uint32_t GetNumberOfNodes() const {
|
||||
return m_numNodes;
|
||||
}
|
||||
|
||||
uint32_t GetNumberOfEdges() const {
|
||||
return m_numEdges;
|
||||
}
|
||||
|
||||
uint32_t GetOutDegree( const NodeIterator n ) const {
|
||||
return m_nodes[n].edges;
|
||||
}
|
||||
|
||||
NodeIterator GetTarget( const EdgeIterator e ) const {
|
||||
return NodeIterator( m_edges[e].target );
|
||||
}
|
||||
|
||||
EdgeDataT &GetEdgeData( const EdgeIterator e ) {
|
||||
return m_edges[e].data;
|
||||
}
|
||||
|
||||
const EdgeDataT &GetEdgeData( const EdgeIterator e ) const {
|
||||
return m_edges[e].data;
|
||||
}
|
||||
|
||||
EdgeIterator BeginEdges( const NodeIterator n ) const {
|
||||
return EdgeIterator( m_nodes[n].firstEdge );
|
||||
}
|
||||
|
||||
EdgeIterator EndEdges( const NodeIterator n ) const {
|
||||
return EdgeIterator( m_nodes[n].firstEdge + m_nodes[n].edges );
|
||||
}
|
||||
|
||||
//adds an edge. Invalidates edge iterators for the source node
|
||||
EdgeIterator InsertEdge( const NodeIterator from, const NodeIterator to, const EdgeDataT &data ) {
|
||||
Node &node = m_nodes[from];
|
||||
EdgeIterator newFirstEdge = node.edges + node.firstEdge;
|
||||
if ( newFirstEdge >= m_edges.size() || !isDummy( newFirstEdge ) ) {
|
||||
if ( node.firstEdge != 0 && isDummy( node.firstEdge - 1 ) ) {
|
||||
node.firstEdge--;
|
||||
m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges];
|
||||
} else {
|
||||
EdgeIterator newFirstEdge = ( EdgeIterator ) m_edges.size();
|
||||
uint32_t newSize = node.edges * 1.1 + 2;
|
||||
EdgeIterator requiredCapacity = newSize + m_edges.size();
|
||||
EdgeIterator oldCapacity = m_edges.capacity();
|
||||
if ( requiredCapacity >= oldCapacity ) {
|
||||
m_edges.reserve( requiredCapacity * 1.1 );
|
||||
}
|
||||
m_edges.resize( m_edges.size() + newSize );
|
||||
for ( EdgeIterator i = 0; i < node.edges; ++i ) {
|
||||
m_edges[newFirstEdge + i ] = m_edges[node.firstEdge + i];
|
||||
makeDummy( node.firstEdge + i );
|
||||
}
|
||||
for ( EdgeIterator i = node.edges + 1; i < newSize; ++i )
|
||||
makeDummy( newFirstEdge + i );
|
||||
node.firstEdge = newFirstEdge;
|
||||
}
|
||||
}
|
||||
Edge &edge = m_edges[node.firstEdge + node.edges];
|
||||
edge.target = to;
|
||||
edge.data = data;
|
||||
++m_numEdges;
|
||||
++node.edges;
|
||||
return EdgeIterator( node.firstEdge + node.edges );
|
||||
}
|
||||
|
||||
//removes an edge. Invalidates edge iterators for the source node
|
||||
void DeleteEdge( const NodeIterator source, const EdgeIterator e ) {
|
||||
Node &node = m_nodes[source];
|
||||
--m_numEdges;
|
||||
--node.edges;
|
||||
const uint32_t last = node.firstEdge + node.edges;
|
||||
//swap with last edge
|
||||
m_edges[e] = m_edges[last];
|
||||
makeDummy( last );
|
||||
}
|
||||
|
||||
//removes all edges (source,target)
|
||||
int32_t DeleteEdgesTo( const NodeIterator source, const NodeIterator target ) {
|
||||
int32_t deleted = 0;
|
||||
for ( EdgeIterator i = BeginEdges( source ), iend = EndEdges( source ); i < iend - deleted; ++i ) {
|
||||
if ( m_edges[i].target == target ) {
|
||||
do {
|
||||
deleted++;
|
||||
m_edges[i] = m_edges[iend - deleted];
|
||||
makeDummy( iend - deleted );
|
||||
} while ( i < iend - deleted && m_edges[i].target == target );
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp atomic
|
||||
m_numEdges -= deleted;
|
||||
m_nodes[source].edges -= deleted;
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
//searches for a specific edge
|
||||
EdgeIterator FindEdge( const NodeIterator from, const NodeIterator to ) const {
|
||||
for ( EdgeIterator i = BeginEdges( from ), iend = EndEdges( from ); i != iend; ++i ) {
|
||||
if ( to == m_edges[i].target ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return EndEdges( from );
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool isDummy( const EdgeIterator edge ) const {
|
||||
return m_edges[edge].target == (std::numeric_limits< NodeIterator >::max)();
|
||||
}
|
||||
|
||||
void makeDummy( const EdgeIterator edge ) {
|
||||
m_edges[edge].target = (std::numeric_limits< NodeIterator >::max)();
|
||||
}
|
||||
|
||||
struct Node {
|
||||
//index of the first edge
|
||||
EdgeIterator firstEdge;
|
||||
//amount of edges
|
||||
uint32_t edges;
|
||||
};
|
||||
|
||||
struct Edge {
|
||||
NodeIterator target;
|
||||
EdgeDataT data;
|
||||
};
|
||||
|
||||
NodeIterator m_numNodes;
|
||||
EdgeIterator m_numEdges;
|
||||
|
||||
std::vector< Node > m_nodes;
|
||||
DeallocatingVector< Edge > m_edges;
|
||||
};
|
||||
|
||||
#endif // DYNAMICGRAPH_H_INCLUDED
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef EDGE_BASED_NODE_H
|
||||
#define EDGE_BASED_NODE_H
|
||||
|
||||
#include "Coordinate.h"
|
||||
|
||||
struct EdgeBasedNode {
|
||||
EdgeBasedNode() :
|
||||
id(INT_MAX),
|
||||
lat1(INT_MAX),
|
||||
lat2(INT_MAX),
|
||||
lon1(INT_MAX),
|
||||
lon2(INT_MAX >> 1),
|
||||
belongsToTinyComponent(false),
|
||||
nameID(UINT_MAX),
|
||||
weight(UINT_MAX >> 1),
|
||||
ignoreInGrid(false)
|
||||
{ }
|
||||
|
||||
bool operator<(const EdgeBasedNode & other) const {
|
||||
return other.id < id;
|
||||
}
|
||||
|
||||
bool operator==(const EdgeBasedNode & other) const {
|
||||
return id == other.id;
|
||||
}
|
||||
|
||||
inline FixedPointCoordinate Centroid() const {
|
||||
FixedPointCoordinate centroid;
|
||||
//The coordinates of the midpoint are given by:
|
||||
//x = (x1 + x2) /2 and y = (y1 + y2) /2.
|
||||
centroid.lon = (std::min(lon1, lon2) + std::max(lon1, lon2))/2;
|
||||
centroid.lat = (std::min(lat1, lat2) + std::max(lat1, lat2))/2;
|
||||
return centroid;
|
||||
}
|
||||
|
||||
inline bool isIgnored() const {
|
||||
return ignoreInGrid;
|
||||
}
|
||||
|
||||
NodeID id;
|
||||
int lat1;
|
||||
int lat2;
|
||||
int lon1;
|
||||
int lon2:31;
|
||||
bool belongsToTinyComponent:1;
|
||||
NodeID nameID;
|
||||
unsigned weight:31;
|
||||
bool ignoreInGrid:1;
|
||||
};
|
||||
|
||||
#endif //EDGE_BASED_NODE_H
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HASHTABLE_H_
|
||||
#define HASHTABLE_H_
|
||||
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
template<typename keyT, typename valueT>
|
||||
class HashTable : public boost::unordered_map<keyT, valueT> {
|
||||
private:
|
||||
typedef boost::unordered_map<keyT, valueT> super;
|
||||
public:
|
||||
HashTable() : super() { }
|
||||
|
||||
HashTable(const unsigned size) : super(size) { }
|
||||
|
||||
HashTable &operator=(const HashTable &other) {
|
||||
super::operator = (other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void Add(const keyT& key, const valueT& value){
|
||||
super::insert(std::make_pair(key, value));
|
||||
}
|
||||
|
||||
inline valueT Find(const keyT& key) const {
|
||||
if(super::find(key) == super::end()) {
|
||||
return valueT();
|
||||
}
|
||||
return boost::ref(super::find(key)->second);
|
||||
}
|
||||
|
||||
inline bool Holds(const keyT& key) const {
|
||||
if(super::find(key) == super::end()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* HASHTABLE_H_ */
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HILBERTVALUE_H_
|
||||
#define HILBERTVALUE_H_
|
||||
|
||||
#include "Coordinate.h"
|
||||
|
||||
#include <boost/integer.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
// computes a 64 bit value that corresponds to the hilbert space filling curve
|
||||
|
||||
class HilbertCode : boost::noncopyable {
|
||||
public:
|
||||
static uint64_t GetHilbertNumberForCoordinate(
|
||||
const FixedPointCoordinate & current_coordinate
|
||||
) {
|
||||
unsigned location[2];
|
||||
location[0] = current_coordinate.lat+( 90*COORDINATE_PRECISION);
|
||||
location[1] = current_coordinate.lon+(180*COORDINATE_PRECISION);
|
||||
|
||||
TransposeCoordinate(location);
|
||||
const uint64_t result = BitInterleaving(location[0], location[1]);
|
||||
return result;
|
||||
}
|
||||
private:
|
||||
static inline uint64_t BitInterleaving(const uint32_t a, const uint32_t b) {
|
||||
uint64_t result = 0;
|
||||
for(int8_t index = 31; index >= 0; --index){
|
||||
result |= (a >> index) & 1;
|
||||
result <<= 1;
|
||||
result |= (b >> index) & 1;
|
||||
if(0 != index){
|
||||
result <<= 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void TransposeCoordinate( uint32_t * X) {
|
||||
uint32_t M = 1 << (32-1), P, Q, t;
|
||||
int i;
|
||||
// Inverse undo
|
||||
for( Q = M; Q > 1; Q >>= 1 ) {
|
||||
P=Q-1;
|
||||
for( i = 0; i < 2; ++i ) {
|
||||
if( X[i] & Q ) {
|
||||
X[0] ^= P; // invert
|
||||
} else {
|
||||
t = (X[0]^X[i]) & P;
|
||||
X[0] ^= t;
|
||||
X[i] ^= t;
|
||||
}
|
||||
} // exchange
|
||||
}
|
||||
// Gray encode
|
||||
for( i = 1; i < 2; ++i ) {
|
||||
X[i] ^= X[i-1];
|
||||
}
|
||||
t=0;
|
||||
for( Q = M; Q > 1; Q >>= 1 ) {
|
||||
if( X[2-1] & Q ) {
|
||||
t ^= Q-1;
|
||||
}
|
||||
} //check if this for loop is wrong
|
||||
for( i = 0; i < 2; ++i ) {
|
||||
X[i] ^= t;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* HILBERTVALUE_H_ */
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef IMPORT_EDGE_H
|
||||
#define IMPORT_EDGE_H
|
||||
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
class NodeBasedEdge {
|
||||
|
||||
public:
|
||||
bool operator< (const NodeBasedEdge& e) const {
|
||||
if (source() == e.source()) {
|
||||
if (target() == e.target()) {
|
||||
if (weight() == e.weight()) {
|
||||
return (isForward() && isBackward() &&
|
||||
((! e.isForward()) || (! e.isBackward())));
|
||||
}
|
||||
return (weight() < e.weight());
|
||||
}
|
||||
return (target() < e.target());
|
||||
}
|
||||
return (source() < e.source());
|
||||
}
|
||||
|
||||
explicit NodeBasedEdge(
|
||||
NodeID s,
|
||||
NodeID t,
|
||||
NodeID n,
|
||||
EdgeWeight w,
|
||||
bool f,
|
||||
bool b,
|
||||
short ty,
|
||||
bool ra,
|
||||
bool ig,
|
||||
bool ar,
|
||||
bool cf
|
||||
) : _source(s),
|
||||
_target(t),
|
||||
_name(n),
|
||||
_weight(w),
|
||||
_type(ty),
|
||||
forward(f),
|
||||
backward(b),
|
||||
_roundabout(ra),
|
||||
_ignoreInGrid(ig),
|
||||
_accessRestricted(ar),
|
||||
_contraFlow(cf)
|
||||
{
|
||||
if(ty < 0) {
|
||||
throw OSRMException("negative edge type");
|
||||
}
|
||||
}
|
||||
|
||||
NodeID target() const {return _target; }
|
||||
NodeID source() const {return _source; }
|
||||
NodeID name() const { return _name; }
|
||||
EdgeWeight weight() const {return _weight; }
|
||||
short type() const {
|
||||
BOOST_ASSERT_MSG(_type >= 0, "type of ImportEdge invalid");
|
||||
return _type; }
|
||||
bool isBackward() const { return backward; }
|
||||
bool isForward() const { return forward; }
|
||||
bool isLocatable() const { return _type != 14; }
|
||||
bool isRoundabout() const { return _roundabout; }
|
||||
bool ignoreInGrid() const { return _ignoreInGrid; }
|
||||
bool isAccessRestricted() const { return _accessRestricted; }
|
||||
bool isContraFlow() const { return _contraFlow; }
|
||||
|
||||
//TODO: names need to be fixed.
|
||||
NodeID _source;
|
||||
NodeID _target;
|
||||
NodeID _name;
|
||||
EdgeWeight _weight;
|
||||
short _type;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
bool _roundabout:1;
|
||||
bool _ignoreInGrid:1;
|
||||
bool _accessRestricted:1;
|
||||
bool _contraFlow:1;
|
||||
|
||||
private:
|
||||
NodeBasedEdge() { }
|
||||
};
|
||||
|
||||
class EdgeBasedEdge {
|
||||
|
||||
public:
|
||||
bool operator< (const EdgeBasedEdge& e) const {
|
||||
if (source() == e.source()) {
|
||||
if (target() == e.target()) {
|
||||
if (weight() == e.weight()) {
|
||||
return (isForward() && isBackward() &&
|
||||
((! e.isForward()) || (! e.isBackward())));
|
||||
}
|
||||
return (weight() < e.weight());
|
||||
}
|
||||
return (target() < e.target());
|
||||
}
|
||||
return (source() < e.source());
|
||||
}
|
||||
|
||||
template<class EdgeT>
|
||||
EdgeBasedEdge(const EdgeT & myEdge ) :
|
||||
m_source(myEdge.source),
|
||||
m_target(myEdge.target),
|
||||
m_edgeID(myEdge.data.via),
|
||||
m_weight(myEdge.data.distance),
|
||||
m_forward(myEdge.data.forward),
|
||||
m_backward(myEdge.data.backward)
|
||||
{ }
|
||||
|
||||
/** Default constructor. target and weight are set to 0.*/
|
||||
EdgeBasedEdge() :
|
||||
m_source(0),
|
||||
m_target(0),
|
||||
m_edgeID(0),
|
||||
m_weight(0),
|
||||
m_forward(false),
|
||||
m_backward(false)
|
||||
{ }
|
||||
|
||||
explicit EdgeBasedEdge(
|
||||
const NodeID s,
|
||||
const NodeID t,
|
||||
const NodeID v,
|
||||
const EdgeWeight w,
|
||||
const bool f,
|
||||
const bool b
|
||||
) :
|
||||
m_source(s),
|
||||
m_target(t),
|
||||
m_edgeID(v),
|
||||
m_weight(w),
|
||||
m_forward(f),
|
||||
m_backward(b)
|
||||
{}
|
||||
|
||||
NodeID target() const { return m_target; }
|
||||
NodeID source() const { return m_source; }
|
||||
EdgeWeight weight() const { return m_weight; }
|
||||
NodeID id() const { return m_edgeID; }
|
||||
bool isBackward() const { return m_backward; }
|
||||
bool isForward() const { return m_forward; }
|
||||
|
||||
private:
|
||||
NodeID m_source;
|
||||
NodeID m_target;
|
||||
NodeID m_edgeID;
|
||||
EdgeWeight m_weight:30;
|
||||
bool m_forward:1;
|
||||
bool m_backward:1;
|
||||
};
|
||||
|
||||
typedef NodeBasedEdge ImportEdge;
|
||||
|
||||
#endif /* IMPORT_EDGE_H */
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef IMPORTNODE_H_
|
||||
#define IMPORTNODE_H_
|
||||
|
||||
#include "QueryNode.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
|
||||
|
||||
struct ExternalMemoryNode : NodeInfo {
|
||||
ExternalMemoryNode(
|
||||
int lat,
|
||||
int lon,
|
||||
unsigned int id,
|
||||
bool bollard,
|
||||
bool traffic_light
|
||||
) :
|
||||
NodeInfo(lat, lon, id),
|
||||
bollard(bollard),
|
||||
trafficLight(traffic_light)
|
||||
{ }
|
||||
ExternalMemoryNode() : bollard(false), trafficLight(false) {}
|
||||
|
||||
static ExternalMemoryNode min_value() {
|
||||
return ExternalMemoryNode(0,0,0, false, false);
|
||||
}
|
||||
static ExternalMemoryNode max_value() {
|
||||
return ExternalMemoryNode(
|
||||
std::numeric_limits<int>::max(),
|
||||
std::numeric_limits<int>::max(),
|
||||
std::numeric_limits<unsigned>::max(),
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
NodeID key() const {
|
||||
return id;
|
||||
}
|
||||
bool bollard;
|
||||
bool trafficLight;
|
||||
};
|
||||
|
||||
struct ImportNode : public ExternalMemoryNode {
|
||||
HashTable<std::string, std::string> keyVals;
|
||||
|
||||
inline void Clear() {
|
||||
keyVals.clear();
|
||||
lat = 0; lon = 0; id = 0; bollard = false; trafficLight = false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* IMPORTNODE_H_ */
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INPUTREADERFACTORY_H
|
||||
#define INPUTREADERFACTORY_H
|
||||
|
||||
#include <bzlib.h>
|
||||
#include <libxml/xmlreader.h>
|
||||
|
||||
struct BZ2Context {
|
||||
FILE* file;
|
||||
BZFILE* bz2;
|
||||
int error;
|
||||
int nUnused;
|
||||
char unused[BZ_MAX_UNUSED];
|
||||
};
|
||||
|
||||
int readFromBz2Stream( void* pointer, char* buffer, int len ) {
|
||||
void *unusedTmpVoid=NULL;
|
||||
char *unusedTmp=NULL;
|
||||
BZ2Context* context = (BZ2Context*) pointer;
|
||||
int read = 0;
|
||||
while(0 == read && !(BZ_STREAM_END == context->error && 0 == context->nUnused && feof(context->file))) {
|
||||
read = BZ2_bzRead(&context->error, context->bz2, buffer, len);
|
||||
if(BZ_OK == context->error) {
|
||||
return read;
|
||||
} else if(BZ_STREAM_END == context->error) {
|
||||
BZ2_bzReadGetUnused(&context->error, context->bz2, &unusedTmpVoid, &context->nUnused);
|
||||
if(BZ_OK != context->error) {std::cerr << "Could not BZ2_bzReadGetUnused" <<std::endl; exit(-1);};
|
||||
unusedTmp = (char*)unusedTmpVoid;
|
||||
for(int i=0;i<context->nUnused;i++) {
|
||||
context->unused[i] = unusedTmp[i];
|
||||
}
|
||||
BZ2_bzReadClose(&context->error, context->bz2);
|
||||
if(BZ_OK != context->error) {std::cerr << "Could not BZ2_bzReadClose" <<std::endl; exit(-1);};
|
||||
context->error = BZ_STREAM_END; // set to the stream end for next call to this function
|
||||
if(0 == context->nUnused && feof(context->file)) {
|
||||
return read;
|
||||
} else {
|
||||
context->bz2 = BZ2_bzReadOpen(&context->error, context->file, 0, 0, context->unused, context->nUnused);
|
||||
if(NULL == context->bz2){std::cerr << "Could not open file" <<std::endl; exit(-1);};
|
||||
}
|
||||
} else { std::cerr << "Could not read bz2 file" << std::endl; exit(-1); }
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
int closeBz2Stream( void *pointer )
|
||||
{
|
||||
BZ2Context* context = (BZ2Context*) pointer;
|
||||
fclose( context->file );
|
||||
delete context;
|
||||
return 0;
|
||||
}
|
||||
|
||||
xmlTextReaderPtr inputReaderFactory( const char* name )
|
||||
{
|
||||
std::string inputName(name);
|
||||
|
||||
if(inputName.find(".osm.bz2")!=std::string::npos)
|
||||
{
|
||||
BZ2Context* context = new BZ2Context();
|
||||
context->error = false;
|
||||
context->file = fopen( name, "r" );
|
||||
int error;
|
||||
context->bz2 = BZ2_bzReadOpen( &error, context->file, 0, 0, context->unused, context->nUnused );
|
||||
if ( context->bz2 == NULL || context->file == NULL ) {
|
||||
delete context;
|
||||
return NULL;
|
||||
}
|
||||
return xmlReaderForIO( readFromBz2Stream, closeBz2Stream, (void*) context, NULL, NULL, 0 );
|
||||
} else {
|
||||
return xmlNewTextReaderFilename(name);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // INPUTREADERFACTORY_H
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef LRUCACHE_H
|
||||
#define LRUCACHE_H
|
||||
|
||||
#include <list>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
template<typename KeyT, typename ValueT>
|
||||
class LRUCache {
|
||||
private:
|
||||
struct CacheEntry {
|
||||
CacheEntry(KeyT k, ValueT v) : key(k), value(v) {}
|
||||
KeyT key;
|
||||
ValueT value;
|
||||
};
|
||||
unsigned capacity;
|
||||
std::list<CacheEntry> itemsInCache;
|
||||
boost::unordered_map<KeyT, typename std::list<CacheEntry>::iterator > positionMap;
|
||||
public:
|
||||
LRUCache(unsigned c) : capacity(c) {}
|
||||
|
||||
bool Holds(KeyT key) {
|
||||
if(positionMap.find(key) != positionMap.end()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Insert(const KeyT key, ValueT &value) {
|
||||
itemsInCache.push_front(CacheEntry(key, value));
|
||||
positionMap.insert(std::make_pair(key, itemsInCache.begin()));
|
||||
if(itemsInCache.size() > capacity) {
|
||||
positionMap.erase(itemsInCache.back().key);
|
||||
itemsInCache.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void Insert(const KeyT key, ValueT value) {
|
||||
itemsInCache.push_front(CacheEntry(key, value));
|
||||
positionMap.insert(std::make_pair(key, itemsInCache.begin()));
|
||||
if(itemsInCache.size() > capacity) {
|
||||
positionMap.erase(itemsInCache.back().key);
|
||||
itemsInCache.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
bool Fetch(const KeyT key, ValueT& result) {
|
||||
if(Holds(key)) {
|
||||
CacheEntry e = *(positionMap.find(key)->second);
|
||||
result = e.value;
|
||||
|
||||
//move to front
|
||||
itemsInCache.splice(positionMap.find(key)->second, itemsInCache, itemsInCache.begin());
|
||||
positionMap.find(key)->second = itemsInCache.begin();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
unsigned Size() const {
|
||||
return itemsInCache.size();
|
||||
}
|
||||
};
|
||||
#endif //LRUCACHE_H
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MERCATORUTIL_H_
|
||||
#define MERCATORUTIL_H_
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
inline double y2lat(double a) {
|
||||
return 180./M_PI * (2. * atan(exp(a*M_PI/180.)) - M_PI/2.);
|
||||
}
|
||||
|
||||
inline double lat2y(double a) {
|
||||
return 180./M_PI * log(tan(M_PI/4.+a*(M_PI/180.)/2.));
|
||||
}
|
||||
|
||||
#endif /* MERCATORUTIL_H_ */
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PERCENT_H
|
||||
#define PERCENT_H
|
||||
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include <iostream>
|
||||
|
||||
class Percent {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param maxValue the value that corresponds to 100%
|
||||
* @param step the progress is shown in steps of 'step' percent
|
||||
*/
|
||||
Percent(unsigned maxValue, unsigned step = 5) {
|
||||
reinit(maxValue, step);
|
||||
}
|
||||
|
||||
/** Reinitializes this object. */
|
||||
void reinit(unsigned maxValue, unsigned step = 5) {
|
||||
_maxValue = maxValue;
|
||||
_current_value = 0;
|
||||
_intervalPercent = _maxValue / 100;
|
||||
_nextThreshold = _intervalPercent;
|
||||
_lastPercent = 0;
|
||||
_step = step;
|
||||
}
|
||||
|
||||
/** If there has been significant progress, display it. */
|
||||
void printStatus(unsigned currentValue) {
|
||||
if (currentValue >= _nextThreshold) {
|
||||
_nextThreshold += _intervalPercent;
|
||||
printPercent( currentValue / (double)_maxValue * 100 );
|
||||
}
|
||||
if (currentValue + 1 == _maxValue)
|
||||
std::cout << " 100%" << std::endl;
|
||||
}
|
||||
|
||||
void printIncrement() {
|
||||
#pragma omp atomic
|
||||
++_current_value;
|
||||
printStatus(_current_value);
|
||||
}
|
||||
|
||||
void printAddition(const unsigned addition) {
|
||||
#pragma omp atomic
|
||||
_current_value += addition;
|
||||
printStatus(_current_value);
|
||||
}
|
||||
private:
|
||||
unsigned _current_value;
|
||||
unsigned _maxValue;
|
||||
unsigned _intervalPercent;
|
||||
unsigned _nextThreshold;
|
||||
unsigned _lastPercent;
|
||||
unsigned _step;
|
||||
|
||||
/** Displays the new progress. */
|
||||
void printPercent(double percent) {
|
||||
while (percent >= _lastPercent+_step) {
|
||||
_lastPercent+=_step;
|
||||
if (_lastPercent % 10 == 0) {
|
||||
std::cout << " " << _lastPercent << "% ";
|
||||
}
|
||||
else {
|
||||
std::cout << ".";
|
||||
}
|
||||
std::cout.flush();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // PERCENT_H
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PHANTOMNODES_H_
|
||||
#define PHANTOMNODES_H_
|
||||
|
||||
#include "Coordinate.h"
|
||||
|
||||
struct PhantomNode {
|
||||
PhantomNode() :
|
||||
edgeBasedNode(UINT_MAX),
|
||||
nodeBasedEdgeNameID(UINT_MAX),
|
||||
weight1(INT_MAX),
|
||||
weight2(INT_MAX),
|
||||
ratio(0.)
|
||||
{ }
|
||||
|
||||
NodeID edgeBasedNode;
|
||||
unsigned nodeBasedEdgeNameID;
|
||||
int weight1;
|
||||
int weight2;
|
||||
double ratio;
|
||||
FixedPointCoordinate location;
|
||||
void Reset() {
|
||||
edgeBasedNode = UINT_MAX;
|
||||
nodeBasedEdgeNameID = UINT_MAX;
|
||||
weight1 = INT_MAX;
|
||||
weight2 = INT_MAX;
|
||||
ratio = 0.;
|
||||
location.Reset();
|
||||
}
|
||||
bool isBidirected() const {
|
||||
return weight2 != INT_MAX;
|
||||
}
|
||||
bool isValid(const unsigned numberOfNodes) const {
|
||||
return location.isValid() && (edgeBasedNode < numberOfNodes) && (weight1 != INT_MAX) && (ratio >= 0.) && (ratio <= 1.) && (nodeBasedEdgeNameID != UINT_MAX);
|
||||
}
|
||||
|
||||
bool operator==(const PhantomNode & other) const {
|
||||
return location == other.location;
|
||||
}
|
||||
};
|
||||
|
||||
struct PhantomNodes {
|
||||
PhantomNode startPhantom;
|
||||
PhantomNode targetPhantom;
|
||||
void Reset() {
|
||||
startPhantom.Reset();
|
||||
targetPhantom.Reset();
|
||||
}
|
||||
|
||||
bool PhantomsAreOnSameNodeBasedEdge() const {
|
||||
return (startPhantom.edgeBasedNode == targetPhantom.edgeBasedNode);
|
||||
}
|
||||
|
||||
bool AtLeastOnePhantomNodeIsUINTMAX() const {
|
||||
return !(startPhantom.edgeBasedNode == UINT_MAX || targetPhantom.edgeBasedNode == UINT_MAX);
|
||||
}
|
||||
|
||||
bool PhantomNodesHaveEqualLocation() const {
|
||||
return startPhantom == targetPhantom;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn){
|
||||
out << "Node1: " << pn.startPhantom.edgeBasedNode << std::endl;
|
||||
out << "Node2: " << pn.targetPhantom.edgeBasedNode << std::endl;
|
||||
out << "startCoord: " << pn.startPhantom.location << std::endl;
|
||||
out << "targetCoord: " << pn.targetPhantom.location << std::endl;
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream &out, const PhantomNode & pn){
|
||||
out << "node: " << pn.edgeBasedNode << ", name: " << pn.nodeBasedEdgeNameID << ", w1: " << pn.weight1 << ", w2: " << pn.weight2 << ", ratio: " << pn.ratio << ", loc: " << pn.location;
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif /* PHANTOMNODES_H_ */
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef QUERYEDGE_H_
|
||||
#define QUERYEDGE_H_
|
||||
|
||||
#include "TurnInstructions.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
struct OriginalEdgeData{
|
||||
explicit OriginalEdgeData(
|
||||
NodeID viaNode,
|
||||
unsigned nameID,
|
||||
TurnInstruction turnInstruction
|
||||
) : viaNode(viaNode), nameID(nameID), turnInstruction(turnInstruction) {}
|
||||
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;
|
||||
bool shortcut:1;
|
||||
int distance:30;
|
||||
bool forward:1;
|
||||
bool backward:1;
|
||||
} data;
|
||||
|
||||
bool operator<( const QueryEdge& right ) const {
|
||||
if ( source != right.source ) {
|
||||
return source < right.source;
|
||||
}
|
||||
return target < right.target;
|
||||
}
|
||||
|
||||
bool operator== ( const QueryEdge& right ) const {
|
||||
return ( source == right.source && target == right.target && data.distance == right.data.distance &&
|
||||
data.shortcut == right.data.shortcut && data.forward == right.data.forward && data.backward == right.data.backward
|
||||
&& data.id == right.data.id
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* QUERYEDGE_H_ */
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _NODE_COORDS_H
|
||||
#define _NODE_COORDS_H
|
||||
|
||||
#include "Coordinate.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <climits>
|
||||
|
||||
#include <limits>
|
||||
|
||||
struct NodeInfo {
|
||||
typedef NodeID key_type; //type of NodeID
|
||||
typedef int value_type; //type of lat,lons
|
||||
|
||||
NodeInfo(int _lat, int _lon, NodeID _id) : lat(_lat), lon(_lon), id(_id) {}
|
||||
NodeInfo() : lat(INT_MAX), lon(INT_MAX), id(UINT_MAX) {}
|
||||
int lat;
|
||||
int lon;
|
||||
NodeID id;
|
||||
|
||||
static NodeInfo min_value() {
|
||||
return NodeInfo(
|
||||
-90*COORDINATE_PRECISION,
|
||||
-180*COORDINATE_PRECISION,
|
||||
std::numeric_limits<NodeID>::min()
|
||||
);
|
||||
}
|
||||
|
||||
static NodeInfo max_value() {
|
||||
return NodeInfo(
|
||||
90*COORDINATE_PRECISION,
|
||||
180*COORDINATE_PRECISION,
|
||||
std::numeric_limits<NodeID>::max()
|
||||
);
|
||||
}
|
||||
|
||||
value_type operator[](const std::size_t n) const {
|
||||
switch(n) {
|
||||
case 1:
|
||||
return lat;
|
||||
break;
|
||||
case 0:
|
||||
return lon;
|
||||
break;
|
||||
default:
|
||||
BOOST_ASSERT_MSG(false, "should not happen");
|
||||
return UINT_MAX;
|
||||
break;
|
||||
}
|
||||
BOOST_ASSERT_MSG(false, "should not happen");
|
||||
return UINT_MAX;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //_NODE_COORDS_H
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef RAWROUTEDATA_H_
|
||||
#define RAWROUTEDATA_H_
|
||||
|
||||
#include "../DataStructures/Coordinate.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct _PathData {
|
||||
_PathData(NodeID no, unsigned na, unsigned tu, unsigned dur) : node(no), nameID(na), durationOfSegment(dur), turnInstruction(tu) { }
|
||||
NodeID node;
|
||||
unsigned nameID;
|
||||
unsigned durationOfSegment;
|
||||
short turnInstruction;
|
||||
};
|
||||
|
||||
struct RawRouteData {
|
||||
std::vector< _PathData > computedShortestPath;
|
||||
std::vector< _PathData > computedAlternativePath;
|
||||
std::vector< PhantomNodes > segmentEndCoordinates;
|
||||
std::vector< FixedPointCoordinate > rawViaNodeCoordinates;
|
||||
unsigned checkSum;
|
||||
int lengthOfShortestPath;
|
||||
int lengthOfAlternativePath;
|
||||
RawRouteData() : checkSum(UINT_MAX), lengthOfShortestPath(INT_MAX), lengthOfAlternativePath(INT_MAX) {}
|
||||
};
|
||||
|
||||
#endif /* RAWROUTEDATA_H_ */
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef RESTRICTION_H_
|
||||
#define RESTRICTION_H_
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include <climits>
|
||||
|
||||
struct TurnRestriction {
|
||||
NodeID viaNode;
|
||||
NodeID fromNode;
|
||||
NodeID toNode;
|
||||
struct Bits { //mostly unused
|
||||
Bits()
|
||||
:
|
||||
isOnly(false),
|
||||
unused1(false),
|
||||
unused2(false),
|
||||
unused3(false),
|
||||
unused4(false),
|
||||
unused5(false),
|
||||
unused6(false),
|
||||
unused7(false)
|
||||
{ }
|
||||
|
||||
bool isOnly:1;
|
||||
bool unused1:1;
|
||||
bool unused2:1;
|
||||
bool unused3:1;
|
||||
bool unused4:1;
|
||||
bool unused5:1;
|
||||
bool unused6:1;
|
||||
bool unused7:1;
|
||||
} flags;
|
||||
|
||||
TurnRestriction(NodeID viaNode) :
|
||||
viaNode(viaNode),
|
||||
fromNode(UINT_MAX),
|
||||
toNode(UINT_MAX) {
|
||||
|
||||
}
|
||||
|
||||
TurnRestriction(const bool isOnly = false) :
|
||||
viaNode(UINT_MAX),
|
||||
fromNode(UINT_MAX),
|
||||
toNode(UINT_MAX) {
|
||||
flags.isOnly = isOnly;
|
||||
}
|
||||
};
|
||||
|
||||
struct InputRestrictionContainer {
|
||||
EdgeID fromWay;
|
||||
EdgeID toWay;
|
||||
unsigned viaNode;
|
||||
TurnRestriction restriction;
|
||||
|
||||
InputRestrictionContainer(
|
||||
EdgeID fromWay,
|
||||
EdgeID toWay,
|
||||
NodeID vn,
|
||||
unsigned vw
|
||||
) :
|
||||
fromWay(fromWay),
|
||||
toWay(toWay),
|
||||
viaNode(vw)
|
||||
{
|
||||
restriction.viaNode = vn;
|
||||
}
|
||||
InputRestrictionContainer(
|
||||
bool isOnly = false
|
||||
) :
|
||||
fromWay(UINT_MAX),
|
||||
toWay(UINT_MAX),
|
||||
viaNode(UINT_MAX)
|
||||
{
|
||||
restriction.flags.isOnly = isOnly;
|
||||
}
|
||||
|
||||
static InputRestrictionContainer min_value() {
|
||||
return InputRestrictionContainer(0, 0, 0, 0);
|
||||
}
|
||||
static InputRestrictionContainer max_value() {
|
||||
return InputRestrictionContainer(UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX);
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpRestrictionContainerByFrom :
|
||||
public std::binary_function<InputRestrictionContainer, InputRestrictionContainer, bool>
|
||||
{
|
||||
typedef InputRestrictionContainer value_type;
|
||||
inline bool operator()(
|
||||
const InputRestrictionContainer & a,
|
||||
const InputRestrictionContainer & b
|
||||
) const {
|
||||
return a.fromWay < b.fromWay;
|
||||
}
|
||||
inline value_type max_value() const {
|
||||
return InputRestrictionContainer::max_value();
|
||||
}
|
||||
inline value_type min_value() const {
|
||||
return InputRestrictionContainer::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpRestrictionContainerByTo: public std::binary_function<InputRestrictionContainer, InputRestrictionContainer, bool> {
|
||||
typedef InputRestrictionContainer value_type;
|
||||
inline bool operator ()(
|
||||
const InputRestrictionContainer & a,
|
||||
const InputRestrictionContainer & b
|
||||
) const {
|
||||
return a.toWay < b.toWay;
|
||||
}
|
||||
value_type max_value() const {
|
||||
return InputRestrictionContainer::max_value();
|
||||
}
|
||||
value_type min_value() const {
|
||||
return InputRestrictionContainer::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* RESTRICTION_H_ */
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SEARCHENGINE_H
|
||||
#define SEARCHENGINE_H
|
||||
|
||||
#include "Coordinate.h"
|
||||
#include "SearchEngineData.h"
|
||||
#include "PhantomNodes.h"
|
||||
#include "QueryEdge.h"
|
||||
#include "../RoutingAlgorithms/AlternativePathRouting.h"
|
||||
#include "../RoutingAlgorithms/ShortestPathRouting.h"
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <climits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template<class DataFacadeT>
|
||||
class SearchEngine {
|
||||
private:
|
||||
DataFacadeT * facade;
|
||||
SearchEngineData engine_working_data;
|
||||
public:
|
||||
ShortestPathRouting<DataFacadeT> shortest_path;
|
||||
AlternativeRouting <DataFacadeT> alternative_path;
|
||||
|
||||
SearchEngine( DataFacadeT * facade )
|
||||
:
|
||||
facade (facade),
|
||||
shortest_path (facade, engine_working_data),
|
||||
alternative_path (facade, engine_working_data)
|
||||
{}
|
||||
|
||||
~SearchEngine() {}
|
||||
|
||||
};
|
||||
|
||||
#endif // SEARCHENGINE_H
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "SearchEngineData.h"
|
||||
|
||||
void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes) {
|
||||
if(!forwardHeap.get()) {
|
||||
forwardHeap.reset(new QueryHeap(number_of_nodes));
|
||||
} else {
|
||||
forwardHeap->Clear();
|
||||
}
|
||||
if(!backwardHeap.get()) {
|
||||
backwardHeap.reset(new QueryHeap(number_of_nodes));
|
||||
} else {
|
||||
backwardHeap->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void SearchEngineData::InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes) {
|
||||
if(!forwardHeap2.get()) {
|
||||
forwardHeap2.reset(new QueryHeap(number_of_nodes));
|
||||
} else {
|
||||
forwardHeap2->Clear();
|
||||
}
|
||||
if(!backwardHeap2.get()) {
|
||||
backwardHeap2.reset(new QueryHeap(number_of_nodes));
|
||||
} else {
|
||||
backwardHeap2->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void SearchEngineData::InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes) {
|
||||
if(!forwardHeap3.get()) {
|
||||
forwardHeap3.reset(new QueryHeap(number_of_nodes));
|
||||
} else {
|
||||
forwardHeap3->Clear();
|
||||
}
|
||||
if(!backwardHeap3.get()) {
|
||||
backwardHeap3.reset(new QueryHeap(number_of_nodes));
|
||||
} else {
|
||||
backwardHeap3->Clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SEARCH_ENGINE_DATA_H
|
||||
#define SEARCH_ENGINE_DATA_H
|
||||
|
||||
#include "BinaryHeap.h"
|
||||
#include "QueryEdge.h"
|
||||
#include "StaticGraph.h"
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct _HeapData {
|
||||
NodeID parent;
|
||||
_HeapData( NodeID p ) : parent(p) { }
|
||||
};
|
||||
|
||||
// typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;
|
||||
|
||||
struct SearchEngineData {
|
||||
typedef BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> > QueryHeap;
|
||||
typedef boost::thread_specific_ptr<QueryHeap> SearchEngineHeapPtr;
|
||||
|
||||
static SearchEngineHeapPtr forwardHeap;
|
||||
static SearchEngineHeapPtr backwardHeap;
|
||||
static SearchEngineHeapPtr forwardHeap2;
|
||||
static SearchEngineHeapPtr backwardHeap2;
|
||||
static SearchEngineHeapPtr forwardHeap3;
|
||||
static SearchEngineHeapPtr backwardHeap3;
|
||||
|
||||
void InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes);
|
||||
|
||||
void InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes);
|
||||
|
||||
void InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes);
|
||||
};
|
||||
|
||||
#endif // SEARCH_ENGINE_DATA_H
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SEGMENTINFORMATION_H_
|
||||
#define SEGMENTINFORMATION_H_
|
||||
|
||||
#include "Coordinate.h"
|
||||
#include "TurnInstructions.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
struct SegmentInformation {
|
||||
FixedPointCoordinate location;
|
||||
NodeID nameID;
|
||||
double length;
|
||||
unsigned duration;
|
||||
double bearing;
|
||||
TurnInstruction turnInstruction;
|
||||
bool necessary;
|
||||
SegmentInformation(const FixedPointCoordinate & loc, const NodeID nam, const double len, const unsigned dur, const TurnInstruction tInstr, const bool nec) :
|
||||
location(loc), nameID(nam), length(len), duration(dur), bearing(0.), turnInstruction(tInstr), necessary(nec) {}
|
||||
SegmentInformation(const FixedPointCoordinate & loc, const NodeID nam, const double len, const unsigned dur, const TurnInstruction tInstr) :
|
||||
location(loc), nameID(nam), length(len), duration(dur), bearing(0.), turnInstruction(tInstr), necessary(tInstr != 0) {}
|
||||
};
|
||||
|
||||
#endif /* SEGMENTINFORMATION_H_ */
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHARED_MEMORY_FACTORY_H
|
||||
#define SHARED_MEMORY_FACTORY_H
|
||||
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/integer.hpp>
|
||||
#include <boost/interprocess/mapped_region.hpp>
|
||||
#include <boost/interprocess/xsi_shared_memory.hpp>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
|
||||
struct OSRMLockFile {
|
||||
boost::filesystem::path operator()() {
|
||||
boost::filesystem::path temp_dir =
|
||||
boost::filesystem::temp_directory_path();
|
||||
boost::filesystem::path lock_file = temp_dir / "osrm.lock";
|
||||
return lock_file;
|
||||
}
|
||||
};
|
||||
|
||||
class SharedMemory : boost::noncopyable {
|
||||
|
||||
//Remove shared memory on destruction
|
||||
class shm_remove : boost::noncopyable {
|
||||
private:
|
||||
int m_shmid;
|
||||
bool m_initialized;
|
||||
public:
|
||||
void SetID(int shmid) {
|
||||
m_shmid = shmid;
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
shm_remove() : m_shmid(INT_MIN), m_initialized(false) {}
|
||||
|
||||
~shm_remove(){
|
||||
if(m_initialized) {
|
||||
SimpleLogger().Write(logDEBUG) <<
|
||||
"automatic memory deallocation";
|
||||
if(!boost::interprocess::xsi_shared_memory::remove(m_shmid)) {
|
||||
SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
void * Ptr() const {
|
||||
return region.get_address();
|
||||
}
|
||||
|
||||
template<typename IdentifierT >
|
||||
SharedMemory(
|
||||
const boost::filesystem::path & lock_file,
|
||||
const IdentifierT id,
|
||||
const uint64_t size = 0,
|
||||
bool read_write = false,
|
||||
bool remove_prev = true
|
||||
) : key(
|
||||
lock_file.string().c_str(),
|
||||
id
|
||||
) {
|
||||
if( 0 == size ){ //read_only
|
||||
shm = boost::interprocess::xsi_shared_memory (
|
||||
boost::interprocess::open_only,
|
||||
key
|
||||
);
|
||||
|
||||
region = boost::interprocess::mapped_region (
|
||||
shm,
|
||||
(
|
||||
read_write ?
|
||||
boost::interprocess::read_write :
|
||||
boost::interprocess::read_only
|
||||
)
|
||||
);
|
||||
} else { //writeable pointer
|
||||
//remove previously allocated mem
|
||||
if( remove_prev ) {
|
||||
Remove(key);
|
||||
}
|
||||
shm = boost::interprocess::xsi_shared_memory (
|
||||
boost::interprocess::open_or_create,
|
||||
key,
|
||||
size
|
||||
);
|
||||
#ifdef __linux__
|
||||
if( -1 == shmctl(shm.get_shmid(), SHM_LOCK, 0) ) {
|
||||
if( ENOMEM == errno ) {
|
||||
SimpleLogger().Write(logWARNING) <<
|
||||
"could not lock shared memory to RAM";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
region = boost::interprocess::mapped_region (
|
||||
shm,
|
||||
boost::interprocess::read_write
|
||||
);
|
||||
|
||||
remover.SetID( shm.get_shmid() );
|
||||
SimpleLogger().Write(logDEBUG) <<
|
||||
"writeable memory allocated " << size << " bytes";
|
||||
}
|
||||
}
|
||||
|
||||
template<typename IdentifierT >
|
||||
static bool RegionExists(
|
||||
const IdentifierT id
|
||||
) {
|
||||
bool result = true;
|
||||
try {
|
||||
OSRMLockFile lock_file;
|
||||
boost::interprocess::xsi_key key( lock_file().string().c_str(), id );
|
||||
result = RegionExists(key);
|
||||
} catch(...) {
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename IdentifierT >
|
||||
static bool Remove(
|
||||
const IdentifierT id
|
||||
) {
|
||||
OSRMLockFile lock_file;
|
||||
boost::interprocess::xsi_key key( lock_file().string().c_str(), id );
|
||||
return Remove(key);
|
||||
}
|
||||
|
||||
private:
|
||||
static bool RegionExists( const boost::interprocess::xsi_key &key ) {
|
||||
bool result = true;
|
||||
try {
|
||||
boost::interprocess::xsi_shared_memory shm(
|
||||
boost::interprocess::open_only,
|
||||
key
|
||||
);
|
||||
} catch(...) {
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool Remove(
|
||||
const boost::interprocess::xsi_key &key
|
||||
) {
|
||||
bool ret = false;
|
||||
try{
|
||||
SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
|
||||
boost::interprocess::xsi_shared_memory xsi(
|
||||
boost::interprocess::open_only,
|
||||
key
|
||||
);
|
||||
ret = boost::interprocess::xsi_shared_memory::remove(xsi.get_shmid());
|
||||
} catch(const boost::interprocess::interprocess_exception &e){
|
||||
if(e.get_error_code() != boost::interprocess::not_found_error) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
boost::interprocess::xsi_key key;
|
||||
boost::interprocess::xsi_shared_memory shm;
|
||||
boost::interprocess::mapped_region region;
|
||||
shm_remove remover;
|
||||
};
|
||||
|
||||
template<class LockFileT = OSRMLockFile>
|
||||
class SharedMemoryFactory_tmpl : boost::noncopyable {
|
||||
public:
|
||||
|
||||
template<typename IdentifierT >
|
||||
static SharedMemory * Get(
|
||||
const IdentifierT & id,
|
||||
const uint64_t size = 0,
|
||||
bool read_write = false,
|
||||
bool remove_prev = true
|
||||
) {
|
||||
try {
|
||||
LockFileT lock_file;
|
||||
if(!boost::filesystem::exists(lock_file()) ) {
|
||||
if( 0 == size ) {
|
||||
throw OSRMException("lock file does not exist, exiting");
|
||||
} else {
|
||||
boost::filesystem::ofstream ofs(lock_file());
|
||||
ofs.close();
|
||||
}
|
||||
}
|
||||
return new SharedMemory(
|
||||
lock_file(),
|
||||
id,
|
||||
size,
|
||||
read_write,
|
||||
remove_prev
|
||||
);
|
||||
} catch(const boost::interprocess::interprocess_exception &e){
|
||||
SimpleLogger().Write(logWARNING) <<
|
||||
"caught exception: " << e.what() <<
|
||||
", code " << e.get_error_code();
|
||||
throw OSRMException(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SharedMemoryFactory_tmpl() {}
|
||||
};
|
||||
|
||||
typedef SharedMemoryFactory_tmpl<> SharedMemoryFactory;
|
||||
|
||||
#endif /* SHARED_MEMORY_POINTER_FACTORY_H */
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHARED_MEMORY_VECTOR_WRAPPER_H
|
||||
#define SHARED_MEMORY_VECTOR_WRAPPER_H
|
||||
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
template<typename DataT>
|
||||
class ShMemIterator : public std::iterator<std::input_iterator_tag, DataT> {
|
||||
DataT * p;
|
||||
public:
|
||||
ShMemIterator(DataT * x) : p(x) {}
|
||||
ShMemIterator(const ShMemIterator & mit) : p(mit.p) {}
|
||||
ShMemIterator& operator++() {
|
||||
++p;
|
||||
return *this;
|
||||
}
|
||||
ShMemIterator operator++(int) {
|
||||
ShMemIterator tmp(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
ShMemIterator operator+(std::ptrdiff_t diff) {
|
||||
ShMemIterator tmp(p+diff);
|
||||
return tmp;
|
||||
}
|
||||
bool operator==(const ShMemIterator& rhs) {
|
||||
return p==rhs.p;
|
||||
}
|
||||
bool operator!=(const ShMemIterator& rhs) {
|
||||
return p!=rhs.p;
|
||||
}
|
||||
DataT& operator*() {
|
||||
return *p;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename DataT>
|
||||
class SharedMemoryWrapper {
|
||||
private:
|
||||
DataT * m_ptr;
|
||||
std::size_t m_size;
|
||||
|
||||
public:
|
||||
SharedMemoryWrapper() :
|
||||
m_ptr(NULL),
|
||||
m_size(0)
|
||||
{ }
|
||||
|
||||
SharedMemoryWrapper(DataT * ptr, std::size_t size) :
|
||||
m_ptr(ptr),
|
||||
m_size(size)
|
||||
{ }
|
||||
|
||||
void swap( SharedMemoryWrapper<DataT> & other ) {
|
||||
BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
|
||||
std::swap( m_size, other.m_size);
|
||||
std::swap( m_ptr , other.m_ptr );
|
||||
}
|
||||
|
||||
// void SetData(const DataT * ptr, const std::size_t size) {
|
||||
// BOOST_ASSERT_MSG( 0 == m_size, "vector not empty");
|
||||
// BOOST_ASSERT_MSG( 0 < size , "new vector empty");
|
||||
// m_ptr.reset(ptr);
|
||||
// m_size = size;
|
||||
// }
|
||||
|
||||
DataT & at(const std::size_t index) {
|
||||
return m_ptr[index];
|
||||
}
|
||||
|
||||
const DataT & at(const std::size_t index) const {
|
||||
return m_ptr[index];
|
||||
}
|
||||
|
||||
ShMemIterator<DataT> begin() const {
|
||||
return ShMemIterator<DataT>(m_ptr);
|
||||
}
|
||||
|
||||
ShMemIterator<DataT> end() const {
|
||||
return ShMemIterator<DataT>(m_ptr+m_size);
|
||||
}
|
||||
|
||||
std::size_t size() const { return m_size; }
|
||||
|
||||
DataT & operator[](const unsigned index) {
|
||||
BOOST_ASSERT_MSG(index < m_size, "invalid size");
|
||||
return m_ptr[index];
|
||||
}
|
||||
|
||||
const DataT & operator[](const unsigned index) const {
|
||||
BOOST_ASSERT_MSG(index < m_size, "invalid size");
|
||||
return m_ptr[index];
|
||||
}
|
||||
};
|
||||
|
||||
template<typename DataT, bool UseSharedMemory>
|
||||
struct ShM {
|
||||
typedef typename boost::conditional<
|
||||
UseSharedMemory,
|
||||
SharedMemoryWrapper<DataT>,
|
||||
std::vector<DataT>
|
||||
>::type vector;
|
||||
};
|
||||
|
||||
|
||||
#endif //SHARED_MEMORY_VECTOR_WRAPPER_H
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef STATICGRAPH_H_INCLUDED
|
||||
#define STATICGRAPH_H_INCLUDED
|
||||
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/SharedMemoryVectorWrapper.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
template< typename EdgeDataT, bool UseSharedMemory = false>
|
||||
class StaticGraph {
|
||||
public:
|
||||
typedef NodeID NodeIterator;
|
||||
typedef NodeID EdgeIterator;
|
||||
typedef EdgeDataT EdgeData;
|
||||
class InputEdge {
|
||||
public:
|
||||
EdgeDataT data;
|
||||
NodeIterator source;
|
||||
NodeIterator target;
|
||||
bool operator<( const InputEdge& right ) const {
|
||||
if ( source != right.source ) {
|
||||
return source < right.source;
|
||||
}
|
||||
return target < right.target;
|
||||
}
|
||||
};
|
||||
|
||||
struct _StrNode {
|
||||
//index of the first edge
|
||||
EdgeIterator firstEdge;
|
||||
};
|
||||
|
||||
struct _StrEdge {
|
||||
NodeID target;
|
||||
EdgeDataT data;
|
||||
};
|
||||
|
||||
StaticGraph( const int nodes, std::vector< InputEdge > &graph ) {
|
||||
std::sort( graph.begin(), graph.end() );
|
||||
_numNodes = nodes;
|
||||
_numEdges = ( EdgeIterator ) graph.size();
|
||||
_nodes.resize( _numNodes + 1);
|
||||
EdgeIterator edge = 0;
|
||||
EdgeIterator position = 0;
|
||||
for ( NodeIterator node = 0; node <= _numNodes; ++node ) {
|
||||
EdgeIterator lastEdge = edge;
|
||||
while ( edge < _numEdges && graph[edge].source == node )
|
||||
++edge;
|
||||
_nodes[node].firstEdge = position; //=edge
|
||||
position += edge - lastEdge; //remove
|
||||
}
|
||||
_edges.resize( position ); //(edge)
|
||||
edge = 0;
|
||||
for ( NodeIterator node = 0; node < _numNodes; ++node ) {
|
||||
for ( EdgeIterator i = _nodes[node].firstEdge, e = _nodes[node+1].firstEdge; i != e; ++i ) {
|
||||
_edges[i].target = graph[edge].target;
|
||||
_edges[i].data = graph[edge].data;
|
||||
assert(_edges[i].data.distance > 0);
|
||||
edge++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StaticGraph(
|
||||
typename ShM<_StrNode, UseSharedMemory>::vector & nodes,
|
||||
typename ShM<_StrEdge, UseSharedMemory>::vector & edges
|
||||
) {
|
||||
_numNodes = nodes.size()-1;
|
||||
_numEdges = edges.size();
|
||||
|
||||
_nodes.swap(nodes);
|
||||
_edges.swap(edges);
|
||||
|
||||
#ifndef NDEBUG
|
||||
Percent p(GetNumberOfNodes());
|
||||
for(unsigned u = 0; u < GetNumberOfNodes(); ++u) {
|
||||
for(unsigned eid = BeginEdges(u); eid < EndEdges(u); ++eid) {
|
||||
unsigned v = GetTarget(eid);
|
||||
EdgeData & data = GetEdgeData(eid);
|
||||
if(data.shortcut) {
|
||||
unsigned eid2 = FindEdgeInEitherDirection(u, data.id);
|
||||
if(eid2 == UINT_MAX) {
|
||||
SimpleLogger().Write(logWARNING) <<
|
||||
"cannot find first segment of edge (" <<
|
||||
u << "," << data.id << "," << v << ")";
|
||||
|
||||
data.shortcut = false;
|
||||
}
|
||||
eid2 = FindEdgeInEitherDirection(data.id, v);
|
||||
if(eid2 == UINT_MAX) {
|
||||
SimpleLogger().Write(logWARNING) <<
|
||||
"cannot find second segment of edge (" <<
|
||||
u << "," << data.id << "," << v << ")";
|
||||
data.shortcut = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
p.printIncrement();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned GetNumberOfNodes() const {
|
||||
return _numNodes;
|
||||
}
|
||||
|
||||
unsigned GetNumberOfEdges() const {
|
||||
return _numEdges;
|
||||
}
|
||||
|
||||
unsigned GetOutDegree( const NodeIterator n ) const {
|
||||
return BeginEdges(n)-EndEdges(n) - 1;
|
||||
}
|
||||
|
||||
inline NodeIterator GetTarget( const EdgeIterator e ) const {
|
||||
return NodeIterator( _edges[e].target );
|
||||
}
|
||||
|
||||
inline EdgeDataT &GetEdgeData( const EdgeIterator e ) {
|
||||
return _edges[e].data;
|
||||
}
|
||||
|
||||
const EdgeDataT &GetEdgeData( const EdgeIterator e ) const {
|
||||
return _edges[e].data;
|
||||
}
|
||||
|
||||
EdgeIterator BeginEdges( const NodeIterator n ) const {
|
||||
return EdgeIterator( _nodes[n].firstEdge );
|
||||
}
|
||||
|
||||
EdgeIterator EndEdges( const NodeIterator n ) const {
|
||||
return EdgeIterator( _nodes[n+1].firstEdge );
|
||||
}
|
||||
|
||||
//searches for a specific edge
|
||||
EdgeIterator FindEdge( const NodeIterator from, const NodeIterator to ) const {
|
||||
EdgeIterator smallestEdge = SPECIAL_EDGEID;
|
||||
EdgeWeight smallestWeight = UINT_MAX;
|
||||
for ( EdgeIterator edge = BeginEdges( from ); edge < EndEdges(from); edge++ ) {
|
||||
const NodeID target = GetTarget(edge);
|
||||
const EdgeWeight weight = GetEdgeData(edge).distance;
|
||||
if(target == to && weight < smallestWeight) {
|
||||
smallestEdge = edge; smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
return smallestEdge;
|
||||
}
|
||||
|
||||
EdgeIterator FindEdgeInEitherDirection( const NodeIterator from, const NodeIterator to ) const {
|
||||
EdgeIterator tmp = FindEdge( from, to );
|
||||
return (UINT_MAX != tmp ? tmp : FindEdge( to, from ));
|
||||
}
|
||||
|
||||
EdgeIterator FindEdgeIndicateIfReverse( const NodeIterator from, const NodeIterator to, bool & result ) const {
|
||||
EdgeIterator tmp = FindEdge( from, to );
|
||||
if(UINT_MAX == tmp) {
|
||||
tmp = FindEdge( to, from );
|
||||
if(UINT_MAX != tmp) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
NodeIterator _numNodes;
|
||||
EdgeIterator _numEdges;
|
||||
|
||||
typename ShM< _StrNode, UseSharedMemory >::vector _nodes;
|
||||
typename ShM< _StrEdge, UseSharedMemory >::vector _edges;
|
||||
};
|
||||
|
||||
#endif // STATICGRAPH_H_INCLUDED
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// KD Tree coded by Christian Vetter, Monav Project
|
||||
|
||||
#ifndef STATICKDTREE_H_INCLUDED
|
||||
#define STATICKDTREE_H_INCLUDED
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stack>
|
||||
#include <limits>
|
||||
|
||||
namespace KDTree {
|
||||
|
||||
#define KDTREE_BASESIZE (8)
|
||||
|
||||
template< unsigned k, typename T >
|
||||
class BoundingBox {
|
||||
public:
|
||||
BoundingBox() {
|
||||
for ( unsigned dim = 0; dim < k; ++dim ) {
|
||||
min[dim] = std::numeric_limits< T >::min();
|
||||
max[dim] = std::numeric_limits< T >::max();
|
||||
}
|
||||
}
|
||||
|
||||
T min[k];
|
||||
T max[k];
|
||||
};
|
||||
|
||||
struct NoData {};
|
||||
|
||||
template< unsigned k, typename T >
|
||||
class EuclidianMetric {
|
||||
public:
|
||||
double operator() ( const T left[k], const T right[k] ) {
|
||||
double result = 0;
|
||||
for ( unsigned i = 0; i < k; ++i ) {
|
||||
double temp = (double)left[i] - (double)right[i];
|
||||
result += temp * temp;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double operator() ( const BoundingBox< k, T > &box, const T point[k] ) {
|
||||
T nearest[k];
|
||||
for ( unsigned dim = 0; dim < k; ++dim ) {
|
||||
if ( point[dim] < box.min[dim] )
|
||||
nearest[dim] = box.min[dim];
|
||||
else if ( point[dim] > box.max[dim] )
|
||||
nearest[dim] = box.max[dim];
|
||||
else
|
||||
nearest[dim] = point[dim];
|
||||
}
|
||||
return operator() ( point, nearest );
|
||||
}
|
||||
};
|
||||
|
||||
template < unsigned k, typename T, typename Data = NoData, typename Metric = EuclidianMetric< k, T > >
|
||||
class StaticKDTree {
|
||||
public:
|
||||
|
||||
struct InputPoint {
|
||||
T coordinates[k];
|
||||
Data data;
|
||||
bool operator==( const InputPoint& right )
|
||||
{
|
||||
for ( int i = 0; i < k; i++ ) {
|
||||
if ( coordinates[i] != right.coordinates[i] )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
StaticKDTree( std::vector< InputPoint > * points ){
|
||||
BOOST_ASSERT( k > 0 );
|
||||
BOOST_ASSERT ( points->size() > 0 );
|
||||
size = points->size();
|
||||
kdtree = new InputPoint[size];
|
||||
for ( Iterator i = 0; i != size; ++i ) {
|
||||
kdtree[i] = points->at(i);
|
||||
for ( unsigned dim = 0; dim < k; ++dim ) {
|
||||
if ( kdtree[i].coordinates[dim] < boundingBox.min[dim] )
|
||||
boundingBox.min[dim] = kdtree[i].coordinates[dim];
|
||||
if ( kdtree[i].coordinates[dim] > boundingBox.max[dim] )
|
||||
boundingBox.max[dim] = kdtree[i].coordinates[dim];
|
||||
}
|
||||
}
|
||||
std::stack< Tree > s;
|
||||
s.push ( Tree ( 0, size, 0 ) );
|
||||
while ( !s.empty() ) {
|
||||
Tree tree = s.top();
|
||||
s.pop();
|
||||
|
||||
if ( tree.right - tree.left < KDTREE_BASESIZE )
|
||||
continue;
|
||||
|
||||
Iterator middle = tree.left + ( tree.right - tree.left ) / 2;
|
||||
std::nth_element( kdtree + tree.left, kdtree + middle, kdtree + tree.right, Less( tree.dimension ) );
|
||||
s.push( Tree( tree.left, middle, ( tree.dimension + 1 ) % k ) );
|
||||
s.push( Tree( middle + 1, tree.right, ( tree.dimension + 1 ) % k ) );
|
||||
}
|
||||
}
|
||||
|
||||
~StaticKDTree(){
|
||||
delete[] kdtree;
|
||||
}
|
||||
|
||||
bool NearestNeighbor( InputPoint* result, const InputPoint& point ) {
|
||||
Metric distance;
|
||||
bool found = false;
|
||||
double nearestDistance = std::numeric_limits< T >::max();
|
||||
std::stack< NNTree > s;
|
||||
s.push ( NNTree ( 0, size, 0, boundingBox ) );
|
||||
while ( !s.empty() ) {
|
||||
NNTree tree = s.top();
|
||||
s.pop();
|
||||
|
||||
if ( distance( tree.box, point.coordinates ) >= nearestDistance )
|
||||
continue;
|
||||
|
||||
if ( tree.right - tree.left < KDTREE_BASESIZE ) {
|
||||
for ( unsigned i = tree.left; i < tree.right; i++ ) {
|
||||
double newDistance = distance( kdtree[i].coordinates, point.coordinates );
|
||||
if ( newDistance < nearestDistance ) {
|
||||
nearestDistance = newDistance;
|
||||
*result = kdtree[i];
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Iterator middle = tree.left + ( tree.right - tree.left ) / 2;
|
||||
|
||||
double newDistance = distance( kdtree[middle].coordinates, point.coordinates );
|
||||
if ( newDistance < nearestDistance ) {
|
||||
nearestDistance = newDistance;
|
||||
*result = kdtree[middle];
|
||||
found = true;
|
||||
}
|
||||
|
||||
Less comperator( tree.dimension );
|
||||
if ( !comperator( point, kdtree[middle] ) ) {
|
||||
NNTree first( middle + 1, tree.right, ( tree.dimension + 1 ) % k, tree.box );
|
||||
NNTree second( tree.left, middle, ( tree.dimension + 1 ) % k, tree.box );
|
||||
first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
|
||||
second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
|
||||
s.push( second );
|
||||
s.push( first );
|
||||
}
|
||||
else {
|
||||
NNTree first( middle + 1, tree.right, ( tree.dimension + 1 ) % k, tree.box );
|
||||
NNTree second( tree.left, middle, ( tree.dimension + 1 ) % k, tree.box );
|
||||
first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
|
||||
second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
|
||||
s.push( first );
|
||||
s.push( second );
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef unsigned Iterator;
|
||||
struct Tree {
|
||||
Iterator left;
|
||||
Iterator right;
|
||||
unsigned dimension;
|
||||
Tree() {}
|
||||
Tree( Iterator l, Iterator r, unsigned d ): left( l ), right( r ), dimension( d ) {}
|
||||
};
|
||||
struct NNTree {
|
||||
Iterator left;
|
||||
Iterator right;
|
||||
unsigned dimension;
|
||||
BoundingBox< k, T > box;
|
||||
NNTree() {}
|
||||
NNTree( Iterator l, Iterator r, unsigned d, const BoundingBox< k, T >& b ): left( l ), right( r ), dimension( d ), box ( b ) {}
|
||||
};
|
||||
class Less {
|
||||
public:
|
||||
Less( unsigned d ) {
|
||||
dimension = d;
|
||||
BOOST_ASSERT( dimension < k );
|
||||
}
|
||||
|
||||
bool operator() ( const InputPoint& left, const InputPoint& right ) {
|
||||
BOOST_ASSERT( dimension < k );
|
||||
return left.coordinates[dimension] < right.coordinates[dimension];
|
||||
}
|
||||
private:
|
||||
unsigned dimension;
|
||||
};
|
||||
|
||||
BoundingBox< k, T > boundingBox;
|
||||
InputPoint* kdtree;
|
||||
Iterator size;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // STATICKDTREE_H_INCLUDED
|
||||
@@ -0,0 +1,975 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef STATICRTREE_H_
|
||||
#define STATICRTREE_H_
|
||||
|
||||
#include "Coordinate.h"
|
||||
#include "DeallocatingVector.h"
|
||||
#include "HilbertValue.h"
|
||||
#include "MercatorUtil.h"
|
||||
#include "PhantomNodes.h"
|
||||
#include "SharedMemoryFactory.h"
|
||||
#include "SharedMemoryVectorWrapper.h"
|
||||
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/algorithm/minmax.hpp>
|
||||
#include <boost/algorithm/minmax_element.hpp>
|
||||
#include <boost/range/algorithm_ext/erase.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
//tuning parameters
|
||||
const static uint32_t RTREE_BRANCHING_FACTOR = 50;
|
||||
const static uint32_t RTREE_LEAF_NODE_SIZE = 1170;
|
||||
|
||||
// Implements a static, i.e. packed, R-tree
|
||||
|
||||
static boost::thread_specific_ptr<boost::filesystem::ifstream> thread_local_rtree_stream;
|
||||
|
||||
template<class DataT, bool UseSharedMemory = false>
|
||||
class StaticRTree : boost::noncopyable {
|
||||
public:
|
||||
struct RectangleInt2D {
|
||||
RectangleInt2D() :
|
||||
min_lon(INT_MAX),
|
||||
max_lon(INT_MIN),
|
||||
min_lat(INT_MAX),
|
||||
max_lat(INT_MIN) {}
|
||||
|
||||
int32_t min_lon, max_lon;
|
||||
int32_t min_lat, max_lat;
|
||||
|
||||
inline void InitializeMBRectangle(
|
||||
const DataT * objects,
|
||||
const uint32_t element_count
|
||||
) {
|
||||
for(uint32_t i = 0; i < element_count; ++i) {
|
||||
min_lon = std::min(
|
||||
min_lon, std::min(objects[i].lon1, objects[i].lon2)
|
||||
);
|
||||
max_lon = std::max(
|
||||
max_lon, std::max(objects[i].lon1, objects[i].lon2)
|
||||
);
|
||||
|
||||
min_lat = std::min(
|
||||
min_lat, std::min(objects[i].lat1, objects[i].lat2)
|
||||
);
|
||||
max_lat = std::max(
|
||||
max_lat, std::max(objects[i].lat1, objects[i].lat2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
inline void AugmentMBRectangle(const RectangleInt2D & other) {
|
||||
min_lon = std::min(min_lon, other.min_lon);
|
||||
max_lon = std::max(max_lon, other.max_lon);
|
||||
min_lat = std::min(min_lat, other.min_lat);
|
||||
max_lat = std::max(max_lat, other.max_lat);
|
||||
}
|
||||
|
||||
inline FixedPointCoordinate Centroid() const {
|
||||
FixedPointCoordinate centroid;
|
||||
//The coordinates of the midpoints are given by:
|
||||
//x = (x1 + x2) /2 and y = (y1 + y2) /2.
|
||||
centroid.lon = (min_lon + max_lon)/2;
|
||||
centroid.lat = (min_lat + max_lat)/2;
|
||||
return centroid;
|
||||
}
|
||||
|
||||
inline bool Intersects(const RectangleInt2D & other) const {
|
||||
FixedPointCoordinate upper_left (other.max_lat, other.min_lon);
|
||||
FixedPointCoordinate upper_right(other.max_lat, other.max_lon);
|
||||
FixedPointCoordinate lower_right(other.min_lat, other.max_lon);
|
||||
FixedPointCoordinate lower_left (other.min_lat, other.min_lon);
|
||||
|
||||
return (
|
||||
Contains(upper_left)
|
||||
|| Contains(upper_right)
|
||||
|| Contains(lower_right)
|
||||
|| Contains(lower_left)
|
||||
);
|
||||
}
|
||||
|
||||
inline double GetMinDist(const FixedPointCoordinate & location) const {
|
||||
bool is_contained = Contains(location);
|
||||
if (is_contained) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
min_dist = std::min(
|
||||
min_dist,
|
||||
ApproximateDistance(
|
||||
location.lat,
|
||||
location.lon,
|
||||
max_lat,
|
||||
min_lon
|
||||
)
|
||||
);
|
||||
min_dist = std::min(
|
||||
min_dist,
|
||||
ApproximateDistance(
|
||||
location.lat,
|
||||
location.lon,
|
||||
max_lat,
|
||||
max_lon
|
||||
)
|
||||
);
|
||||
min_dist = std::min(
|
||||
min_dist,
|
||||
ApproximateDistance(
|
||||
location.lat,
|
||||
location.lon,
|
||||
min_lat,
|
||||
max_lon
|
||||
)
|
||||
);
|
||||
min_dist = std::min(
|
||||
min_dist,
|
||||
ApproximateDistance(
|
||||
location.lat,
|
||||
location.lon,
|
||||
min_lat,
|
||||
min_lon
|
||||
)
|
||||
);
|
||||
return min_dist;
|
||||
}
|
||||
|
||||
inline double GetMinMaxDist(const FixedPointCoordinate & location) const {
|
||||
double min_max_dist = std::numeric_limits<double>::max();
|
||||
//Get minmax distance to each of the four sides
|
||||
FixedPointCoordinate upper_left (max_lat, min_lon);
|
||||
FixedPointCoordinate upper_right(max_lat, max_lon);
|
||||
FixedPointCoordinate lower_right(min_lat, max_lon);
|
||||
FixedPointCoordinate lower_left (min_lat, min_lon);
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
ApproximateDistance(location, upper_left ),
|
||||
ApproximateDistance(location, upper_right)
|
||||
)
|
||||
);
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
ApproximateDistance(location, upper_right),
|
||||
ApproximateDistance(location, lower_right)
|
||||
)
|
||||
);
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
ApproximateDistance(location, lower_right),
|
||||
ApproximateDistance(location, lower_left )
|
||||
)
|
||||
);
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
ApproximateDistance(location, lower_left ),
|
||||
ApproximateDistance(location, upper_left )
|
||||
)
|
||||
);
|
||||
return min_max_dist;
|
||||
}
|
||||
|
||||
inline bool Contains(const FixedPointCoordinate & location) const {
|
||||
bool lats_contained =
|
||||
(location.lat > min_lat) && (location.lat < max_lat);
|
||||
bool lons_contained =
|
||||
(location.lon > min_lon) && (location.lon < max_lon);
|
||||
return lats_contained && lons_contained;
|
||||
}
|
||||
|
||||
inline friend std::ostream & operator<< (
|
||||
std::ostream & out,
|
||||
const RectangleInt2D & rect
|
||||
) {
|
||||
out << rect.min_lat/COORDINATE_PRECISION << ","
|
||||
<< rect.min_lon/COORDINATE_PRECISION << " "
|
||||
<< rect.max_lat/COORDINATE_PRECISION << ","
|
||||
<< rect.max_lon/COORDINATE_PRECISION;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
typedef RectangleInt2D RectangleT;
|
||||
|
||||
struct TreeNode {
|
||||
TreeNode() : child_count(0), child_is_on_disk(false) {}
|
||||
RectangleT minimum_bounding_rectangle;
|
||||
uint32_t child_count:31;
|
||||
bool child_is_on_disk:1;
|
||||
uint32_t children[RTREE_BRANCHING_FACTOR];
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
struct WrappedInputElement {
|
||||
explicit WrappedInputElement(
|
||||
const uint32_t _array_index,
|
||||
const uint64_t _hilbert_value
|
||||
) : m_array_index(_array_index), m_hilbert_value(_hilbert_value) {}
|
||||
|
||||
WrappedInputElement() : m_array_index(UINT_MAX), m_hilbert_value(0) {}
|
||||
|
||||
uint32_t m_array_index;
|
||||
uint64_t m_hilbert_value;
|
||||
|
||||
inline bool operator<(const WrappedInputElement & other) const {
|
||||
return m_hilbert_value < other.m_hilbert_value;
|
||||
}
|
||||
};
|
||||
|
||||
struct LeafNode {
|
||||
LeafNode() : object_count(0) {}
|
||||
uint32_t object_count;
|
||||
DataT objects[RTREE_LEAF_NODE_SIZE];
|
||||
};
|
||||
|
||||
struct QueryCandidate {
|
||||
explicit QueryCandidate(
|
||||
const uint32_t n_id,
|
||||
const double dist
|
||||
) : node_id(n_id), min_dist(dist) {}
|
||||
QueryCandidate() : node_id(UINT_MAX), min_dist(std::numeric_limits<double>::max()) {}
|
||||
uint32_t node_id;
|
||||
double min_dist;
|
||||
inline bool operator<(const QueryCandidate & other) const {
|
||||
return min_dist < other.min_dist;
|
||||
}
|
||||
};
|
||||
|
||||
typename ShM<TreeNode, UseSharedMemory>::vector m_search_tree;
|
||||
uint64_t m_element_count;
|
||||
|
||||
const std::string m_leaf_node_filename;
|
||||
public:
|
||||
//Construct a packed Hilbert-R-Tree with Kamel-Faloutsos algorithm [1]
|
||||
explicit StaticRTree(
|
||||
std::vector<DataT> & input_data_vector,
|
||||
const std::string tree_node_filename,
|
||||
const std::string leaf_node_filename
|
||||
)
|
||||
: m_element_count(input_data_vector.size()),
|
||||
m_leaf_node_filename(leaf_node_filename)
|
||||
{
|
||||
SimpleLogger().Write() <<
|
||||
"constructing r-tree of " << m_element_count <<
|
||||
" elements";
|
||||
|
||||
double time1 = get_timestamp();
|
||||
std::vector<WrappedInputElement> input_wrapper_vector(m_element_count);
|
||||
|
||||
//generate auxiliary vector of hilbert-values
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for(uint64_t element_counter = 0; element_counter < m_element_count; ++element_counter) {
|
||||
input_wrapper_vector[element_counter].m_array_index = element_counter;
|
||||
//Get Hilbert-Value for centroid in mercartor projection
|
||||
DataT & current_element = input_data_vector[element_counter];
|
||||
FixedPointCoordinate current_centroid = current_element.Centroid();
|
||||
current_centroid.lat = COORDINATE_PRECISION*lat2y(current_centroid.lat/COORDINATE_PRECISION);
|
||||
|
||||
uint64_t current_hilbert_value = HilbertCode::GetHilbertNumberForCoordinate(current_centroid);
|
||||
input_wrapper_vector[element_counter].m_hilbert_value = current_hilbert_value;
|
||||
|
||||
}
|
||||
//open leaf file
|
||||
boost::filesystem::ofstream leaf_node_file(leaf_node_filename, std::ios::binary);
|
||||
leaf_node_file.write((char*) &m_element_count, sizeof(uint64_t));
|
||||
|
||||
//sort the hilbert-value representatives
|
||||
std::sort(input_wrapper_vector.begin(), input_wrapper_vector.end());
|
||||
std::vector<TreeNode> tree_nodes_in_level;
|
||||
|
||||
//pack M elements into leaf node and write to leaf file
|
||||
uint64_t processed_objects_count = 0;
|
||||
while(processed_objects_count < m_element_count) {
|
||||
|
||||
LeafNode current_leaf;
|
||||
TreeNode current_node;
|
||||
for(uint32_t current_element_index = 0; RTREE_LEAF_NODE_SIZE > current_element_index; ++current_element_index) {
|
||||
if(m_element_count > (processed_objects_count + current_element_index)) {
|
||||
uint32_t index_of_next_object = input_wrapper_vector[processed_objects_count + current_element_index].m_array_index;
|
||||
current_leaf.objects[current_element_index] = input_data_vector[index_of_next_object];
|
||||
++current_leaf.object_count;
|
||||
}
|
||||
}
|
||||
|
||||
//generate tree node that resemble the objects in leaf and store it for next level
|
||||
current_node.minimum_bounding_rectangle.InitializeMBRectangle(current_leaf.objects, current_leaf.object_count);
|
||||
current_node.child_is_on_disk = true;
|
||||
current_node.children[0] = tree_nodes_in_level.size();
|
||||
tree_nodes_in_level.push_back(current_node);
|
||||
|
||||
//write leaf_node to leaf node file
|
||||
leaf_node_file.write((char*)¤t_leaf, sizeof(current_leaf));
|
||||
processed_objects_count += current_leaf.object_count;
|
||||
}
|
||||
|
||||
//close leaf file
|
||||
leaf_node_file.close();
|
||||
|
||||
uint32_t processing_level = 0;
|
||||
while(1 < tree_nodes_in_level.size()) {
|
||||
std::vector<TreeNode> tree_nodes_in_next_level;
|
||||
uint32_t processed_tree_nodes_in_level = 0;
|
||||
while(processed_tree_nodes_in_level < tree_nodes_in_level.size()) {
|
||||
TreeNode parent_node;
|
||||
//pack RTREE_BRANCHING_FACTOR elements into tree_nodes each
|
||||
for(
|
||||
uint32_t current_child_node_index = 0;
|
||||
RTREE_BRANCHING_FACTOR > current_child_node_index;
|
||||
++current_child_node_index
|
||||
) {
|
||||
if(processed_tree_nodes_in_level < tree_nodes_in_level.size()) {
|
||||
TreeNode & current_child_node = tree_nodes_in_level[processed_tree_nodes_in_level];
|
||||
//add tree node to parent entry
|
||||
parent_node.children[current_child_node_index] = m_search_tree.size();
|
||||
m_search_tree.push_back(current_child_node);
|
||||
//augment MBR of parent
|
||||
parent_node.minimum_bounding_rectangle.AugmentMBRectangle(current_child_node.minimum_bounding_rectangle);
|
||||
//increase counters
|
||||
++parent_node.child_count;
|
||||
++processed_tree_nodes_in_level;
|
||||
}
|
||||
}
|
||||
tree_nodes_in_next_level.push_back(parent_node);
|
||||
}
|
||||
tree_nodes_in_level.swap(tree_nodes_in_next_level);
|
||||
++processing_level;
|
||||
}
|
||||
BOOST_ASSERT_MSG(1 == tree_nodes_in_level.size(), "tree broken, more than one root node");
|
||||
//last remaining entry is the root node, store it
|
||||
m_search_tree.push_back(tree_nodes_in_level[0]);
|
||||
|
||||
//reverse and renumber tree to have root at index 0
|
||||
std::reverse(m_search_tree.begin(), m_search_tree.end());
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for(uint32_t i = 0; i < m_search_tree.size(); ++i) {
|
||||
TreeNode & current_tree_node = m_search_tree[i];
|
||||
for(uint32_t j = 0; j < current_tree_node.child_count; ++j) {
|
||||
const uint32_t old_id = current_tree_node.children[j];
|
||||
const uint32_t new_id = m_search_tree.size() - old_id - 1;
|
||||
current_tree_node.children[j] = new_id;
|
||||
}
|
||||
}
|
||||
|
||||
//open tree file
|
||||
boost::filesystem::ofstream tree_node_file(
|
||||
tree_node_filename,
|
||||
std::ios::binary
|
||||
);
|
||||
|
||||
uint32_t size_of_tree = m_search_tree.size();
|
||||
BOOST_ASSERT_MSG(0 < size_of_tree, "tree empty");
|
||||
tree_node_file.write((char *)&size_of_tree, sizeof(uint32_t));
|
||||
tree_node_file.write((char *)&m_search_tree[0], sizeof(TreeNode)*size_of_tree);
|
||||
//close tree node file.
|
||||
tree_node_file.close();
|
||||
double time2 = get_timestamp();
|
||||
SimpleLogger().Write() <<
|
||||
"finished r-tree construction in " << (time2-time1) << " seconds";
|
||||
}
|
||||
|
||||
//Read-only operation for queries
|
||||
explicit StaticRTree(
|
||||
const boost::filesystem::path & node_file,
|
||||
const boost::filesystem::path & leaf_file
|
||||
) : m_leaf_node_filename(leaf_file.string()) {
|
||||
//open tree node file and load into RAM.
|
||||
|
||||
if ( !boost::filesystem::exists( node_file ) ) {
|
||||
throw OSRMException("ram index file does not exist");
|
||||
}
|
||||
if ( 0 == boost::filesystem::file_size( node_file ) ) {
|
||||
throw OSRMException("ram index file is empty");
|
||||
}
|
||||
boost::filesystem::ifstream tree_node_file( node_file, std::ios::binary );
|
||||
|
||||
uint32_t tree_size = 0;
|
||||
tree_node_file.read((char*)&tree_size, sizeof(uint32_t));
|
||||
//SimpleLogger().Write() << "reading " << tree_size << " tree nodes in " << (sizeof(TreeNode)*tree_size) << " bytes";
|
||||
m_search_tree.resize(tree_size);
|
||||
tree_node_file.read((char*)&m_search_tree[0], sizeof(TreeNode)*tree_size);
|
||||
tree_node_file.close();
|
||||
//open leaf node file and store thread specific pointer
|
||||
if ( !boost::filesystem::exists( leaf_file ) ) {
|
||||
throw OSRMException("mem index file does not exist");
|
||||
}
|
||||
if ( 0 == boost::filesystem::file_size( leaf_file ) ) {
|
||||
throw OSRMException("mem index file is empty");
|
||||
}
|
||||
|
||||
boost::filesystem::ifstream leaf_node_file( leaf_file, std::ios::binary );
|
||||
leaf_node_file.read((char*)&m_element_count, sizeof(uint64_t));
|
||||
leaf_node_file.close();
|
||||
|
||||
//SimpleLogger().Write() << tree_size << " nodes in search tree";
|
||||
//SimpleLogger().Write() << m_element_count << " elements in leafs";
|
||||
}
|
||||
|
||||
explicit StaticRTree(
|
||||
TreeNode * tree_node_ptr,
|
||||
const uint32_t number_of_nodes,
|
||||
const boost::filesystem::path & leaf_file
|
||||
) : m_search_tree(tree_node_ptr, number_of_nodes),
|
||||
m_leaf_node_filename(leaf_file.string())
|
||||
{
|
||||
//open leaf node file and store thread specific pointer
|
||||
if ( !boost::filesystem::exists( leaf_file ) ) {
|
||||
throw OSRMException("mem index file does not exist");
|
||||
}
|
||||
if ( 0 == boost::filesystem::file_size( leaf_file ) ) {
|
||||
throw OSRMException("mem index file is empty");
|
||||
}
|
||||
|
||||
boost::filesystem::ifstream leaf_node_file( leaf_file, std::ios::binary );
|
||||
leaf_node_file.read((char*)&m_element_count, sizeof(uint64_t));
|
||||
leaf_node_file.close();
|
||||
|
||||
if( thread_local_rtree_stream.get() ) {
|
||||
thread_local_rtree_stream->close();
|
||||
}
|
||||
|
||||
//SimpleLogger().Write() << tree_size << " nodes in search tree";
|
||||
//SimpleLogger().Write() << m_element_count << " elements in leafs";
|
||||
}
|
||||
//Read-only operation for queries
|
||||
/*
|
||||
inline void FindKNearestPhantomNodesForCoordinate(
|
||||
const FixedPointCoordinate & location,
|
||||
const unsigned zoom_level,
|
||||
const unsigned candidate_count,
|
||||
std::vector<std::pair<PhantomNode, double> > & result_vector
|
||||
) const {
|
||||
|
||||
bool ignore_tiny_components = (zoom_level <= 14);
|
||||
DataT nearest_edge;
|
||||
|
||||
uint32_t io_count = 0;
|
||||
uint32_t explored_tree_nodes_count = 0;
|
||||
SimpleLogger().Write() << "searching for coordinate " << input_coordinate;
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
double min_max_dist = std::numeric_limits<double>::max();
|
||||
bool found_a_nearest_edge = false;
|
||||
|
||||
FixedPointCoordinate nearest, current_start_coordinate, current_end_coordinate;
|
||||
|
||||
//initialize queue with root element
|
||||
std::priority_queue<QueryCandidate> traversal_queue;
|
||||
traversal_queue.push(QueryCandidate(0, m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate)));
|
||||
BOOST_ASSERT_MSG(std::numberic_limits<double>::epsilon() > (0. - traversal_queue.top().min_dist), "Root element in NN Search has min dist != 0.");
|
||||
|
||||
while(!traversal_queue.empty()) {
|
||||
const QueryCandidate current_query_node = traversal_queue.top(); traversal_queue.pop();
|
||||
|
||||
++explored_tree_nodes_count;
|
||||
bool prune_downward = (current_query_node.min_dist >= min_max_dist);
|
||||
bool prune_upward = (current_query_node.min_dist >= min_dist);
|
||||
if( !prune_downward && !prune_upward ) { //downward pruning
|
||||
TreeNode & current_tree_node = m_search_tree[current_query_node.node_id];
|
||||
if (current_tree_node.child_is_on_disk) {
|
||||
LeafNode current_leaf_node;
|
||||
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
|
||||
++io_count;
|
||||
for(uint32_t i = 0; i < current_leaf_node.object_count; ++i) {
|
||||
DataT & current_edge = current_leaf_node.objects[i];
|
||||
if(ignore_tiny_components && current_edge.belongsToTinyComponent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double current_ratio = 0.;
|
||||
double current_perpendicular_distance = ComputePerpendicularDistance(
|
||||
input_coordinate,
|
||||
FixedPointCoordinate(current_edge.lat1, current_edge.lon1),
|
||||
FixedPointCoordinate(current_edge.lat2, current_edge.lon2),
|
||||
nearest,
|
||||
¤t_ratio
|
||||
);
|
||||
|
||||
if(
|
||||
current_perpendicular_distance < min_dist
|
||||
&& !DoubleEpsilonCompare(
|
||||
current_perpendicular_distance,
|
||||
min_dist
|
||||
)
|
||||
) { //found a new minimum
|
||||
min_dist = current_perpendicular_distance;
|
||||
result_phantom_node.edgeBasedNode = current_edge.id;
|
||||
result_phantom_node.nodeBasedEdgeNameID = current_edge.nameID;
|
||||
result_phantom_node.weight1 = current_edge.weight;
|
||||
result_phantom_node.weight2 = INT_MAX;
|
||||
result_phantom_node.location = nearest;
|
||||
current_start_coordinate.lat = current_edge.lat1;
|
||||
current_start_coordinate.lon = current_edge.lon1;
|
||||
current_end_coordinate.lat = current_edge.lat2;
|
||||
current_end_coordinate.lon = current_edge.lon2;
|
||||
nearest_edge = current_edge;
|
||||
found_a_nearest_edge = true;
|
||||
} else if(
|
||||
DoubleEpsilonCompare(current_perpendicular_distance, min_dist) &&
|
||||
1 == abs(current_edge.id - result_phantom_node.edgeBasedNode )
|
||||
&& CoordinatesAreEquivalent(
|
||||
current_start_coordinate,
|
||||
FixedPointCoordinate(
|
||||
current_edge.lat1,
|
||||
current_edge.lon1
|
||||
),
|
||||
FixedPointCoordinate(
|
||||
current_edge.lat2,
|
||||
current_edge.lon2
|
||||
),
|
||||
current_end_coordinate
|
||||
)
|
||||
) {
|
||||
result_phantom_node.edgeBasedNode = std::min(current_edge.id, result_phantom_node.edgeBasedNode);
|
||||
result_phantom_node.weight2 = current_edge.weight;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//traverse children, prune if global mindist is smaller than local one
|
||||
for (uint32_t i = 0; i < current_tree_node.child_count; ++i) {
|
||||
const int32_t child_id = current_tree_node.children[i];
|
||||
TreeNode & child_tree_node = m_search_tree[child_id];
|
||||
RectangleT & child_rectangle = child_tree_node.minimum_bounding_rectangle;
|
||||
const double current_min_dist = child_rectangle.GetMinDist(input_coordinate);
|
||||
const double current_min_max_dist = child_rectangle.GetMinMaxDist(input_coordinate);
|
||||
if( current_min_max_dist < min_max_dist ) {
|
||||
min_max_dist = current_min_max_dist;
|
||||
}
|
||||
if (current_min_dist > min_max_dist) {
|
||||
continue;
|
||||
}
|
||||
if (current_min_dist > min_dist) { //upward pruning
|
||||
continue;
|
||||
}
|
||||
traversal_queue.push(QueryCandidate(child_id, current_min_dist));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const double distance_to_edge =
|
||||
ApproximateDistance (
|
||||
FixedPointCoordinate(nearest_edge.lat1, nearest_edge.lon1),
|
||||
result_phantom_node.location
|
||||
);
|
||||
|
||||
const double length_of_edge =
|
||||
ApproximateDistance(
|
||||
FixedPointCoordinate(nearest_edge.lat1, nearest_edge.lon1),
|
||||
FixedPointCoordinate(nearest_edge.lat2, nearest_edge.lon2)
|
||||
);
|
||||
|
||||
const double ratio = (found_a_nearest_edge ?
|
||||
std::min(1., distance_to_edge/ length_of_edge ) : 0 );
|
||||
result_phantom_node.weight1 *= ratio;
|
||||
if(INT_MAX != result_phantom_node.weight2) {
|
||||
result_phantom_node.weight2 *= (1.-ratio);
|
||||
}
|
||||
result_phantom_node.ratio = ratio;
|
||||
|
||||
//Hack to fix rounding errors and wandering via nodes.
|
||||
if(std::abs(input_coordinate.lon - result_phantom_node.location.lon) == 1) {
|
||||
result_phantom_node.location.lon = input_coordinate.lon;
|
||||
}
|
||||
if(std::abs(input_coordinate.lat - result_phantom_node.location.lat) == 1) {
|
||||
result_phantom_node.location.lat = input_coordinate.lat;
|
||||
}
|
||||
|
||||
SimpleLogger().Write() << "mindist: " << min_distphantom_node.isBidirected() ? "yes" : "no");
|
||||
return found_a_nearest_edge;
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
bool LocateClosestEndPointForCoordinate(
|
||||
const FixedPointCoordinate & input_coordinate,
|
||||
FixedPointCoordinate & result_coordinate,
|
||||
const unsigned zoom_level
|
||||
) {
|
||||
bool ignore_tiny_components = (zoom_level <= 14);
|
||||
DataT nearest_edge;
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
double min_max_dist = std::numeric_limits<double>::max();
|
||||
bool found_a_nearest_edge = false;
|
||||
|
||||
//initialize queue with root element
|
||||
std::priority_queue<QueryCandidate> traversal_queue;
|
||||
double current_min_dist = m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate);
|
||||
traversal_queue.push(
|
||||
QueryCandidate(0, current_min_dist)
|
||||
);
|
||||
|
||||
BOOST_ASSERT_MSG(
|
||||
std::numeric_limits<double>::epsilon() > (0. - traversal_queue.top().min_dist),
|
||||
"Root element in NN Search has min dist != 0."
|
||||
);
|
||||
|
||||
while(!traversal_queue.empty()) {
|
||||
const QueryCandidate current_query_node = traversal_queue.top();
|
||||
traversal_queue.pop();
|
||||
|
||||
const bool prune_downward = (current_query_node.min_dist >= min_max_dist);
|
||||
const bool prune_upward = (current_query_node.min_dist >= min_dist);
|
||||
if( !prune_downward && !prune_upward ) { //downward pruning
|
||||
TreeNode & current_tree_node = m_search_tree[current_query_node.node_id];
|
||||
if (current_tree_node.child_is_on_disk) {
|
||||
LeafNode current_leaf_node;
|
||||
LoadLeafFromDisk(
|
||||
current_tree_node.children[0],
|
||||
current_leaf_node
|
||||
);
|
||||
for(uint32_t i = 0; i < current_leaf_node.object_count; ++i) {
|
||||
const DataT & current_edge = current_leaf_node.objects[i];
|
||||
if(
|
||||
ignore_tiny_components &&
|
||||
current_edge.belongsToTinyComponent
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if(current_edge.isIgnored()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double current_minimum_distance = ApproximateDistance(
|
||||
input_coordinate.lat,
|
||||
input_coordinate.lon,
|
||||
current_edge.lat1,
|
||||
current_edge.lon1
|
||||
);
|
||||
if( current_minimum_distance < min_dist ) {
|
||||
//found a new minimum
|
||||
min_dist = current_minimum_distance;
|
||||
result_coordinate.lat = current_edge.lat1;
|
||||
result_coordinate.lon = current_edge.lon1;
|
||||
found_a_nearest_edge = true;
|
||||
}
|
||||
|
||||
current_minimum_distance = ApproximateDistance(
|
||||
input_coordinate.lat,
|
||||
input_coordinate.lon,
|
||||
current_edge.lat2,
|
||||
current_edge.lon2
|
||||
);
|
||||
|
||||
if( current_minimum_distance < min_dist ) {
|
||||
//found a new minimum
|
||||
min_dist = current_minimum_distance;
|
||||
result_coordinate.lat = current_edge.lat2;
|
||||
result_coordinate.lon = current_edge.lon2;
|
||||
found_a_nearest_edge = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//traverse children, prune if global mindist is smaller than local one
|
||||
for (uint32_t i = 0; i < current_tree_node.child_count; ++i) {
|
||||
const int32_t child_id = current_tree_node.children[i];
|
||||
const TreeNode & child_tree_node = m_search_tree[child_id];
|
||||
const RectangleT & child_rectangle = child_tree_node.minimum_bounding_rectangle;
|
||||
const double current_min_dist = child_rectangle.GetMinDist(input_coordinate);
|
||||
const double current_min_max_dist = child_rectangle.GetMinMaxDist(input_coordinate);
|
||||
if( current_min_max_dist < min_max_dist ) {
|
||||
min_max_dist = current_min_max_dist;
|
||||
}
|
||||
if (current_min_dist > min_max_dist) {
|
||||
continue;
|
||||
}
|
||||
if (current_min_dist > min_dist) { //upward pruning
|
||||
continue;
|
||||
}
|
||||
traversal_queue.push(
|
||||
QueryCandidate(child_id, current_min_dist)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found_a_nearest_edge;
|
||||
}
|
||||
|
||||
|
||||
bool FindPhantomNodeForCoordinate(
|
||||
const FixedPointCoordinate & input_coordinate,
|
||||
PhantomNode & result_phantom_node,
|
||||
const unsigned zoom_level
|
||||
) {
|
||||
|
||||
bool ignore_tiny_components = (zoom_level <= 14);
|
||||
DataT nearest_edge;
|
||||
|
||||
uint32_t io_count = 0;
|
||||
uint32_t explored_tree_nodes_count = 0;
|
||||
//SimpleLogger().Write() << "searching for coordinate " << input_coordinate;
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
double min_max_dist = std::numeric_limits<double>::max();
|
||||
bool found_a_nearest_edge = false;
|
||||
|
||||
FixedPointCoordinate nearest, current_start_coordinate, current_end_coordinate;
|
||||
|
||||
//initialize queue with root element
|
||||
std::priority_queue<QueryCandidate> traversal_queue;
|
||||
double current_min_dist = m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate);
|
||||
traversal_queue.push(
|
||||
QueryCandidate(0, current_min_dist)
|
||||
);
|
||||
|
||||
BOOST_ASSERT_MSG(
|
||||
std::numeric_limits<double>::epsilon() > (0. - traversal_queue.top().min_dist),
|
||||
"Root element in NN Search has min dist != 0."
|
||||
);
|
||||
|
||||
while(!traversal_queue.empty()) {
|
||||
const QueryCandidate current_query_node = traversal_queue.top(); traversal_queue.pop();
|
||||
|
||||
++explored_tree_nodes_count;
|
||||
bool prune_downward = (current_query_node.min_dist >= min_max_dist);
|
||||
bool prune_upward = (current_query_node.min_dist >= min_dist);
|
||||
if( !prune_downward && !prune_upward ) { //downward pruning
|
||||
TreeNode & current_tree_node = m_search_tree[current_query_node.node_id];
|
||||
if (current_tree_node.child_is_on_disk) {
|
||||
LeafNode current_leaf_node;
|
||||
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
|
||||
++io_count;
|
||||
for(uint32_t i = 0; i < current_leaf_node.object_count; ++i) {
|
||||
DataT & current_edge = current_leaf_node.objects[i];
|
||||
if(ignore_tiny_components && current_edge.belongsToTinyComponent) {
|
||||
continue;
|
||||
}
|
||||
if(current_edge.isIgnored()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double current_ratio = 0.;
|
||||
double current_perpendicular_distance = ComputePerpendicularDistance(
|
||||
input_coordinate,
|
||||
FixedPointCoordinate(current_edge.lat1, current_edge.lon1),
|
||||
FixedPointCoordinate(current_edge.lat2, current_edge.lon2),
|
||||
nearest,
|
||||
¤t_ratio
|
||||
);
|
||||
|
||||
if(
|
||||
current_perpendicular_distance < min_dist
|
||||
&& !DoubleEpsilonCompare(
|
||||
current_perpendicular_distance,
|
||||
min_dist
|
||||
)
|
||||
) { //found a new minimum
|
||||
min_dist = current_perpendicular_distance;
|
||||
result_phantom_node.edgeBasedNode = current_edge.id;
|
||||
result_phantom_node.nodeBasedEdgeNameID = current_edge.nameID;
|
||||
result_phantom_node.weight1 = current_edge.weight;
|
||||
result_phantom_node.weight2 = INT_MAX;
|
||||
result_phantom_node.location = nearest;
|
||||
current_start_coordinate.lat = current_edge.lat1;
|
||||
current_start_coordinate.lon = current_edge.lon1;
|
||||
current_end_coordinate.lat = current_edge.lat2;
|
||||
current_end_coordinate.lon = current_edge.lon2;
|
||||
nearest_edge = current_edge;
|
||||
found_a_nearest_edge = true;
|
||||
} else if(
|
||||
DoubleEpsilonCompare(current_perpendicular_distance, min_dist) &&
|
||||
1 == abs(current_edge.id - result_phantom_node.edgeBasedNode )
|
||||
&& CoordinatesAreEquivalent(
|
||||
current_start_coordinate,
|
||||
FixedPointCoordinate(
|
||||
current_edge.lat1,
|
||||
current_edge.lon1
|
||||
),
|
||||
FixedPointCoordinate(
|
||||
current_edge.lat2,
|
||||
current_edge.lon2
|
||||
),
|
||||
current_end_coordinate
|
||||
)
|
||||
) {
|
||||
|
||||
BOOST_ASSERT_MSG(current_edge.id != result_phantom_node.edgeBasedNode, "IDs not different");
|
||||
result_phantom_node.weight2 = current_edge.weight;
|
||||
if(current_edge.id < result_phantom_node.edgeBasedNode) {
|
||||
result_phantom_node.edgeBasedNode = current_edge.id;
|
||||
std::swap(result_phantom_node.weight1, result_phantom_node.weight2);
|
||||
std::swap(current_end_coordinate, current_start_coordinate);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//traverse children, prune if global mindist is smaller than local one
|
||||
for (uint32_t i = 0; i < current_tree_node.child_count; ++i) {
|
||||
const int32_t child_id = current_tree_node.children[i];
|
||||
TreeNode & child_tree_node = m_search_tree[child_id];
|
||||
RectangleT & child_rectangle = child_tree_node.minimum_bounding_rectangle;
|
||||
const double current_min_dist = child_rectangle.GetMinDist(input_coordinate);
|
||||
const double current_min_max_dist = child_rectangle.GetMinMaxDist(input_coordinate);
|
||||
if( current_min_max_dist < min_max_dist ) {
|
||||
min_max_dist = current_min_max_dist;
|
||||
}
|
||||
if (current_min_dist > min_max_dist) {
|
||||
continue;
|
||||
}
|
||||
if (current_min_dist > min_dist) { //upward pruning
|
||||
continue;
|
||||
}
|
||||
traversal_queue.push(QueryCandidate(child_id, current_min_dist));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const double ratio = (found_a_nearest_edge ?
|
||||
std::min(1., ApproximateDistance(current_start_coordinate,
|
||||
result_phantom_node.location)/ApproximateDistance(current_start_coordinate, current_end_coordinate)
|
||||
) : 0
|
||||
);
|
||||
result_phantom_node.weight1 *= ratio;
|
||||
if(INT_MAX != result_phantom_node.weight2) {
|
||||
result_phantom_node.weight2 *= (1.-ratio);
|
||||
}
|
||||
result_phantom_node.ratio = ratio;
|
||||
|
||||
//Hack to fix rounding errors and wandering via nodes.
|
||||
if(std::abs(input_coordinate.lon - result_phantom_node.location.lon) == 1) {
|
||||
result_phantom_node.location.lon = input_coordinate.lon;
|
||||
}
|
||||
if(std::abs(input_coordinate.lat - result_phantom_node.location.lat) == 1) {
|
||||
result_phantom_node.location.lat = input_coordinate.lat;
|
||||
}
|
||||
|
||||
return found_a_nearest_edge;
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
inline void LoadLeafFromDisk(const uint32_t leaf_id, LeafNode& result_node) {
|
||||
if(
|
||||
!thread_local_rtree_stream.get() ||
|
||||
!thread_local_rtree_stream->is_open()
|
||||
) {
|
||||
thread_local_rtree_stream.reset(
|
||||
new boost::filesystem::ifstream(
|
||||
m_leaf_node_filename,
|
||||
std::ios::in | std::ios::binary
|
||||
)
|
||||
);
|
||||
}
|
||||
if(!thread_local_rtree_stream->good()) {
|
||||
thread_local_rtree_stream->clear(std::ios::goodbit);
|
||||
SimpleLogger().Write(logDEBUG) << "Resetting stale filestream";
|
||||
}
|
||||
uint64_t seek_pos = sizeof(uint64_t) + leaf_id*sizeof(LeafNode);
|
||||
thread_local_rtree_stream->seekg(seek_pos);
|
||||
thread_local_rtree_stream->read((char *)&result_node, sizeof(LeafNode));
|
||||
}
|
||||
|
||||
inline double ComputePerpendicularDistance(
|
||||
const FixedPointCoordinate& inputPoint,
|
||||
const FixedPointCoordinate& source,
|
||||
const FixedPointCoordinate& target,
|
||||
FixedPointCoordinate& nearest, double *r) const {
|
||||
const double x = inputPoint.lat/COORDINATE_PRECISION;
|
||||
const double y = inputPoint.lon/COORDINATE_PRECISION;
|
||||
const double a = source.lat/COORDINATE_PRECISION;
|
||||
const double b = source.lon/COORDINATE_PRECISION;
|
||||
const double c = target.lat/COORDINATE_PRECISION;
|
||||
const double d = target.lon/COORDINATE_PRECISION;
|
||||
double p,q,mX,nY;
|
||||
if(std::fabs(a-c) > std::numeric_limits<double>::epsilon() ){
|
||||
const double m = (d-b)/(c-a); // slope
|
||||
// Projection of (x,y) on line joining (a,b) and (c,d)
|
||||
p = ((x + (m*y)) + (m*m*a - m*b))/(1. + m*m);
|
||||
q = b + m*(p - a);
|
||||
} else {
|
||||
p = c;
|
||||
q = y;
|
||||
}
|
||||
nY = (d*p - c*q)/(a*d - b*c);
|
||||
mX = (p - nY*a)/c;// These values are actually n/m+n and m/m+n , we need
|
||||
// not calculate the explicit values of m an n as we
|
||||
// are just interested in the ratio
|
||||
if(std::isnan(mX)) {
|
||||
*r = (target == inputPoint) ? 1. : 0.;
|
||||
} else {
|
||||
*r = mX;
|
||||
}
|
||||
if(*r<=0.){
|
||||
nearest.lat = source.lat;
|
||||
nearest.lon = source.lon;
|
||||
return ((b - y)*(b - y) + (a - x)*(a - x));
|
||||
// return std::sqrt(((b - y)*(b - y) + (a - x)*(a - x)));
|
||||
} else if(*r >= 1.){
|
||||
nearest.lat = target.lat;
|
||||
nearest.lon = target.lon;
|
||||
return ((d - y)*(d - y) + (c - x)*(c - x));
|
||||
// return std::sqrt(((d - y)*(d - y) + (c - x)*(c - x)));
|
||||
}
|
||||
// point lies in between
|
||||
nearest.lat = p*COORDINATE_PRECISION;
|
||||
nearest.lon = q*COORDINATE_PRECISION;
|
||||
// return std::sqrt((p-x)*(p-x) + (q-y)*(q-y));
|
||||
return (p-x)*(p-x) + (q-y)*(q-y);
|
||||
}
|
||||
|
||||
inline bool CoordinatesAreEquivalent(const FixedPointCoordinate & a, const FixedPointCoordinate & b, const FixedPointCoordinate & c, const FixedPointCoordinate & d) const {
|
||||
return (a == b && c == d) || (a == c && b == d) || (a == d && b == c);
|
||||
}
|
||||
|
||||
inline bool DoubleEpsilonCompare(const double d1, const double d2) const {
|
||||
return (std::fabs(d1 - d2) < std::numeric_limits<double>::epsilon() );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//[1] "On Packing R-Trees"; I. Kamel, C. Faloutsos; 1993; DOI: 10.1145/170088.170403
|
||||
//[2] "Nearest Neighbor Queries", N. Roussopulos et al; 1995; DOI: 10.1145/223784.223794
|
||||
|
||||
|
||||
#endif /* STATICRTREE_H_ */
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TURNINSTRUCTIONS_H_
|
||||
#define TURNINSTRUCTIONS_H_
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
typedef unsigned char TurnInstruction;
|
||||
|
||||
//This is a hack until c++0x is available enough to use scoped enums
|
||||
struct TurnInstructionsClass : boost::noncopyable {
|
||||
|
||||
const static TurnInstruction NoTurn = 0; //Give no instruction at all
|
||||
const static TurnInstruction GoStraight = 1; //Tell user to go straight!
|
||||
const static TurnInstruction TurnSlightRight = 2;
|
||||
const static TurnInstruction TurnRight = 3;
|
||||
const static TurnInstruction TurnSharpRight = 4;
|
||||
const static TurnInstruction UTurn = 5;
|
||||
const static TurnInstruction TurnSharpLeft = 6;
|
||||
const static TurnInstruction TurnLeft = 7;
|
||||
const static TurnInstruction TurnSlightLeft = 8;
|
||||
const static TurnInstruction ReachViaPoint = 9;
|
||||
const static TurnInstruction HeadOn = 10;
|
||||
const static TurnInstruction EnterRoundAbout = 11;
|
||||
const static TurnInstruction LeaveRoundAbout = 12;
|
||||
const static TurnInstruction StayOnRoundAbout = 13;
|
||||
const static TurnInstruction StartAtEndOfStreet = 14;
|
||||
const static TurnInstruction ReachedYourDestination = 15;
|
||||
const static TurnInstruction EnterAgainstAllowedDirection = 16;
|
||||
const static TurnInstruction LeaveAgainstAllowedDirection = 17;
|
||||
|
||||
const static TurnInstruction AccessRestrictionFlag = 128;
|
||||
const static TurnInstruction InverseAccessRestrictionFlag = 0x7f; // ~128 does not work without a warning.
|
||||
|
||||
const static int AccessRestrictionPenalty = 1 << 15; //unrelated to the bit set in the restriction flag
|
||||
|
||||
static inline TurnInstruction GetTurnDirectionOfInstruction( const double angle ) {
|
||||
if(angle >= 23 && angle < 67) {
|
||||
return TurnSharpRight;
|
||||
}
|
||||
if (angle >= 67 && angle < 113) {
|
||||
return TurnRight;
|
||||
}
|
||||
if (angle >= 113 && angle < 158) {
|
||||
return TurnSlightRight;
|
||||
}
|
||||
if (angle >= 158 && angle < 202) {
|
||||
return GoStraight;
|
||||
}
|
||||
if (angle >= 202 && angle < 248) {
|
||||
return TurnSlightLeft;
|
||||
}
|
||||
if (angle >= 248 && angle < 292) {
|
||||
return TurnLeft;
|
||||
}
|
||||
if (angle >= 292 && angle < 336) {
|
||||
return TurnSharpLeft;
|
||||
}
|
||||
return UTurn;
|
||||
}
|
||||
|
||||
static inline bool TurnIsNecessary ( const short turnInstruction ) {
|
||||
if(NoTurn == turnInstruction || StayOnRoundAbout == turnInstruction)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static TurnInstructionsClass TurnInstructions;
|
||||
|
||||
#endif /* TURNINSTRUCTIONS_H_ */
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FASTXORHASH_H_
|
||||
#define FASTXORHASH_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
This is an implementation of Tabulation hashing, which has suprising properties like universality.
|
||||
The space requirement is 2*2^16 = 256 kb of memory, which fits into L2 cache.
|
||||
Evaluation boils down to 10 or less assembly instruction on any recent X86 CPU:
|
||||
|
||||
1: movq table2(%rip), %rdx
|
||||
2: movl %edi, %eax
|
||||
3: movzwl %di, %edi
|
||||
4: shrl $16, %eax
|
||||
5: movzwl %ax, %eax
|
||||
6: movzbl (%rdx,%rax), %eax
|
||||
7: movq table1(%rip), %rdx
|
||||
8: xorb (%rdx,%rdi), %al
|
||||
9: movzbl %al, %eax
|
||||
10: ret
|
||||
|
||||
*/
|
||||
class XORFastHash { //65k entries
|
||||
std::vector<unsigned short> table1;
|
||||
std::vector<unsigned short> table2;
|
||||
public:
|
||||
XORFastHash() {
|
||||
table1.resize(2 << 16);
|
||||
table2.resize(2 << 16);
|
||||
for(unsigned i = 0; i < (2 << 16); ++i) {
|
||||
table1[i] = i; table2[i] = i;
|
||||
}
|
||||
std::random_shuffle(table1.begin(), table1.end());
|
||||
std::random_shuffle(table2.begin(), table2.end());
|
||||
}
|
||||
|
||||
inline unsigned short operator()(const unsigned originalValue) const {
|
||||
unsigned short lsb = ((originalValue) & 0xffff);
|
||||
unsigned short msb = (((originalValue) >> 16) & 0xffff);
|
||||
return table1[lsb] ^ table2[msb];
|
||||
}
|
||||
};
|
||||
|
||||
class XORMiniHash { //256 entries
|
||||
std::vector<unsigned char> table1;
|
||||
std::vector<unsigned char> table2;
|
||||
std::vector<unsigned char> table3;
|
||||
std::vector<unsigned char> table4;
|
||||
|
||||
public:
|
||||
XORMiniHash() {
|
||||
table1.resize(1 << 8);
|
||||
table2.resize(1 << 8);
|
||||
table3.resize(1 << 8);
|
||||
table4.resize(1 << 8);
|
||||
for(unsigned i = 0; i < (1 << 8); ++i) {
|
||||
table1[i] = i; table2[i] = i;
|
||||
table3[i] = i; table4[i] = i;
|
||||
}
|
||||
std::random_shuffle(table1.begin(), table1.end());
|
||||
std::random_shuffle(table2.begin(), table2.end());
|
||||
std::random_shuffle(table3.begin(), table3.end());
|
||||
std::random_shuffle(table4.begin(), table4.end());
|
||||
}
|
||||
unsigned char operator()(const unsigned originalValue) const {
|
||||
unsigned char byte1 = ((originalValue) & 0xff);
|
||||
unsigned char byte2 = ((originalValue >> 8) & 0xff);
|
||||
unsigned char byte3 = ((originalValue >> 16) & 0xff);
|
||||
unsigned char byte4 = ((originalValue >> 24) & 0xff);
|
||||
return table1[byte1] ^ table2[byte2] ^ table3[byte3] ^ table4[byte4];
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FASTXORHASH_H_ */
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef XORFASTHASHSTORAGE_H_
|
||||
#define XORFASTHASHSTORAGE_H_
|
||||
|
||||
#include "XORFastHash.h"
|
||||
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class XORFastHashStorage {
|
||||
public:
|
||||
struct HashCell{
|
||||
Key key;
|
||||
NodeID id;
|
||||
unsigned time;
|
||||
HashCell() : key(UINT_MAX), id(UINT_MAX), time(UINT_MAX) {}
|
||||
|
||||
HashCell(const HashCell & other) : key(other.key), id(other.id), time(other.time) { }
|
||||
|
||||
inline operator Key() const {
|
||||
return key;
|
||||
}
|
||||
|
||||
inline void operator=(const Key & keyToInsert) {
|
||||
key = keyToInsert;
|
||||
}
|
||||
};
|
||||
|
||||
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_ */
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BASE_DESCRIPTOR_H_
|
||||
#define BASE_DESCRIPTOR_H_
|
||||
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../DataStructures/RawRouteData.h"
|
||||
#include "../Server/Http/Reply.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct DescriptorConfig {
|
||||
DescriptorConfig() :
|
||||
instructions(true),
|
||||
geometry(true),
|
||||
encode_geometry(true),
|
||||
zoom_level(18)
|
||||
{ }
|
||||
bool instructions;
|
||||
bool geometry;
|
||||
bool encode_geometry;
|
||||
unsigned short zoom_level;
|
||||
};
|
||||
|
||||
template<class DataFacadeT>
|
||||
class BaseDescriptor {
|
||||
public:
|
||||
BaseDescriptor() { }
|
||||
//Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BaseDescriptor() { }
|
||||
virtual void Run(
|
||||
http::Reply & reply,
|
||||
const RawRouteData &rawRoute,
|
||||
PhantomNodes &phantomNodes,
|
||||
const DataFacadeT * facade
|
||||
) = 0;
|
||||
virtual void SetConfig(const DescriptorConfig & config) = 0;
|
||||
};
|
||||
|
||||
#endif /* BASE_DESCRIPTOR_H_ */
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "DescriptionFactory.h"
|
||||
|
||||
DescriptionFactory::DescriptionFactory() : entireLength(0) { }
|
||||
|
||||
DescriptionFactory::~DescriptionFactory() { }
|
||||
|
||||
inline double DescriptionFactory::DegreeToRadian(const double degree) const {
|
||||
return degree * (M_PI/180);
|
||||
}
|
||||
|
||||
inline double DescriptionFactory::RadianToDegree(const double radian) const {
|
||||
return radian * (180/M_PI);
|
||||
}
|
||||
|
||||
double DescriptionFactory::GetBearing(
|
||||
const FixedPointCoordinate & A,
|
||||
const FixedPointCoordinate & B
|
||||
) const {
|
||||
double deltaLong = DegreeToRadian(B.lon/COORDINATE_PRECISION - A.lon/COORDINATE_PRECISION);
|
||||
|
||||
const double lat1 = DegreeToRadian(A.lat/COORDINATE_PRECISION);
|
||||
const double lat2 = DegreeToRadian(B.lat/COORDINATE_PRECISION);
|
||||
|
||||
const double y = sin(deltaLong) * cos(lat2);
|
||||
const 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 & sph) {
|
||||
start_phantom = sph;
|
||||
AppendSegment(
|
||||
sph.location,
|
||||
_PathData(0, sph.nodeBasedEdgeNameID, 10, sph.weight1)
|
||||
);
|
||||
}
|
||||
|
||||
void DescriptionFactory::SetEndSegment(const PhantomNode & tph) {
|
||||
target_phantom = tph;
|
||||
pathDescription.push_back(
|
||||
SegmentInformation(
|
||||
tph.location,
|
||||
tph.nodeBasedEdgeNameID,
|
||||
0,
|
||||
tph.weight1,
|
||||
0,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendSegment(
|
||||
const FixedPointCoordinate & coordinate,
|
||||
const _PathData & data
|
||||
) {
|
||||
if(1 == pathDescription.size() && pathDescription.back().location == coordinate) {
|
||||
pathDescription.back().nameID = data.nameID;
|
||||
} else {
|
||||
pathDescription.push_back(SegmentInformation(coordinate, data.nameID, 0, data.durationOfSegment, data.turnInstruction) );
|
||||
}
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendEncodedPolylineString(
|
||||
const bool return_encoded,
|
||||
std::vector<std::string> & output
|
||||
) {
|
||||
std::string temp;
|
||||
if(return_encoded) {
|
||||
polyline_compressor.printEncodedString(pathDescription, temp);
|
||||
} else {
|
||||
polyline_compressor.printUnencodedString(pathDescription, temp);
|
||||
}
|
||||
output.push_back(temp);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendEncodedPolylineString(
|
||||
std::vector<std::string> &output
|
||||
) const {
|
||||
std::string temp;
|
||||
polyline_compressor.printEncodedString(pathDescription, temp);
|
||||
output.push_back(temp);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendUnencodedPolylineString(
|
||||
std::vector<std::string>& output
|
||||
) const {
|
||||
std::string temp;
|
||||
polyline_compressor.printUnencodedString(pathDescription, temp);
|
||||
output.push_back(temp);
|
||||
}
|
||||
|
||||
// void DescriptionFactory::Run(const SearchEngine &sEngine, const unsigned zoomLevel) {
|
||||
|
||||
// if(0 == pathDescription.size())
|
||||
// return;
|
||||
|
||||
// // unsigned entireLength = 0;
|
||||
// /** starts at index 1 */
|
||||
// pathDescription[0].length = 0;
|
||||
// for(unsigned i = 1; i < pathDescription.size(); ++i) {
|
||||
// pathDescription[i].length = ApproximateEuclideanDistance(pathDescription[i-1].location, pathDescription[i].location);
|
||||
// }
|
||||
|
||||
// double lengthOfSegment = 0;
|
||||
// unsigned durationOfSegment = 0;
|
||||
// unsigned indexOfSegmentBegin = 0;
|
||||
|
||||
// std::string string0 = sEngine.GetEscapedNameForNameID(pathDescription[0].nameID);
|
||||
// std::string string1;
|
||||
|
||||
|
||||
// /*Simplify turn instructions
|
||||
// Input :
|
||||
// 10. Turn left on B 36 for 20 km
|
||||
// 11. Continue on B 35; B 36 for 2 km
|
||||
// 12. Continue on B 36 for 13 km
|
||||
|
||||
// becomes:
|
||||
// 10. Turn left on B 36 for 35 km
|
||||
// */
|
||||
// //TODO: rework to check only end and start of string.
|
||||
// // stl string is way to expensive
|
||||
|
||||
// // unsigned lastTurn = 0;
|
||||
// // for(unsigned i = 1; i < pathDescription.size(); ++i) {
|
||||
// // string1 = sEngine.GetEscapedNameForNameID(pathDescription[i].nameID);
|
||||
// // if(TurnInstructionsClass::GoStraight == pathDescription[i].turnInstruction) {
|
||||
// // if(std::string::npos != string0.find(string1+";")
|
||||
// // || std::string::npos != string0.find(";"+string1)
|
||||
// // || std::string::npos != string0.find(string1+" ;")
|
||||
// // || std::string::npos != string0.find("; "+string1)
|
||||
// // ){
|
||||
// // SimpleLogger().Write() << "->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)
|
||||
// // ){
|
||||
// // SimpleLogger().Write() << "->prev correct: " << string1 << " contains " << string0;
|
||||
// // pathDescription[i].nameID = pathDescription[i-1].nameID;
|
||||
// // pathDescription[i].turnInstruction = TurnInstructionsClass::NoTurn;
|
||||
// // }
|
||||
// // }
|
||||
// // if (TurnInstructionsClass::NoTurn != pathDescription[i].turnInstruction) {
|
||||
// // lastTurn = i;
|
||||
// // }
|
||||
// // string0 = string1;
|
||||
// // }
|
||||
|
||||
|
||||
// for(unsigned i = 1; i < pathDescription.size(); ++i) {
|
||||
// entireLength += pathDescription[i].length;
|
||||
// lengthOfSegment += pathDescription[i].length;
|
||||
// durationOfSegment += pathDescription[i].duration;
|
||||
// pathDescription[indexOfSegmentBegin].length = lengthOfSegment;
|
||||
// pathDescription[indexOfSegmentBegin].duration = durationOfSegment;
|
||||
|
||||
|
||||
// if(TurnInstructionsClass::NoTurn != pathDescription[i].turnInstruction) {
|
||||
// //SimpleLogger().Write() << "Turn after " << lengthOfSegment << "m into way with name id " << segment.nameID;
|
||||
// assert(pathDescription[i].necessary);
|
||||
// lengthOfSegment = 0;
|
||||
// durationOfSegment = 0;
|
||||
// indexOfSegmentBegin = i;
|
||||
// }
|
||||
// }
|
||||
// // SimpleLogger().Write() << "#segs: " << pathDescription.size();
|
||||
|
||||
// //Post-processing to remove empty or nearly empty path segments
|
||||
// if(FLT_EPSILON > pathDescription.back().length) {
|
||||
// // SimpleLogger().Write() << "#segs: " << pathDescription.size() << ", last ratio: " << target_phantom.ratio << ", length: " << pathDescription.back().length;
|
||||
// if(pathDescription.size() > 2){
|
||||
// pathDescription.pop_back();
|
||||
// pathDescription.back().necessary = true;
|
||||
// pathDescription.back().turnInstruction = TurnInstructions.NoTurn;
|
||||
// target_phantom.nodeBasedEdgeNameID = (pathDescription.end()-2)->nameID;
|
||||
// // SimpleLogger().Write() << "Deleting last turn instruction";
|
||||
// }
|
||||
// } else {
|
||||
// pathDescription[indexOfSegmentBegin].duration *= (1.-target_phantom.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;
|
||||
// start_phantom.nodeBasedEdgeNameID = pathDescription[0].nameID;
|
||||
// // SimpleLogger().Write() << "Deleting first turn instruction, ratio: " << start_phantom.ratio << ", length: " << pathDescription[0].length;
|
||||
// }
|
||||
// } else {
|
||||
// pathDescription[0].duration *= start_phantom.ratio;
|
||||
// }
|
||||
|
||||
// //Generalize poly line
|
||||
// dp.Run(pathDescription, zoomLevel);
|
||||
|
||||
// //fix what needs to be fixed else
|
||||
// for(unsigned i = 0; i < pathDescription.size()-1 && pathDescription.size() >= 2; ++i){
|
||||
// if(pathDescription[i].necessary) {
|
||||
// double angle = GetBearing(pathDescription[i].location, pathDescription[i+1].location);
|
||||
// pathDescription[i].bearing = angle;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // BuildRouteSummary(entireLength, duration);
|
||||
// return;
|
||||
// }
|
||||
|
||||
void DescriptionFactory::BuildRouteSummary(
|
||||
const double distance,
|
||||
const unsigned time
|
||||
) {
|
||||
summary.startName = start_phantom.nodeBasedEdgeNameID;
|
||||
summary.destName = target_phantom.nodeBasedEdgeNameID;
|
||||
summary.BuildDurationAndLengthStrings(distance, time);
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DESCRIPTIONFACTORY_H_
|
||||
#define DESCRIPTIONFACTORY_H_
|
||||
|
||||
#include "../Algorithms/DouglasPeucker.h"
|
||||
#include "../Algorithms/PolylineCompressor.h"
|
||||
#include "../DataStructures/Coordinate.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../DataStructures/RawRouteData.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
/* This class is fed with all way segments in consecutive order
|
||||
* and produces the description plus the encoded polyline */
|
||||
|
||||
class DescriptionFactory {
|
||||
DouglasPeucker polyline_generalizer;
|
||||
PolylineCompressor polyline_compressor;
|
||||
PhantomNode start_phantom, target_phantom;
|
||||
|
||||
double DegreeToRadian(const double degree) const;
|
||||
double RadianToDegree(const double degree) const;
|
||||
public:
|
||||
struct RouteSummary {
|
||||
std::string lengthString;
|
||||
std::string durationString;
|
||||
unsigned startName;
|
||||
unsigned destName;
|
||||
RouteSummary() :
|
||||
lengthString("0"),
|
||||
durationString("0"),
|
||||
startName(0),
|
||||
destName(0)
|
||||
{}
|
||||
|
||||
void BuildDurationAndLengthStrings(
|
||||
const double distance,
|
||||
const unsigned time
|
||||
) {
|
||||
//compute distance/duration for route summary
|
||||
intToString(round(distance), lengthString);
|
||||
int travelTime = time/10 + 1;
|
||||
intToString(travelTime, durationString);
|
||||
}
|
||||
} summary;
|
||||
|
||||
double entireLength;
|
||||
|
||||
//I know, declaring this public is considered bad. I'm lazy
|
||||
std::vector <SegmentInformation> pathDescription;
|
||||
DescriptionFactory();
|
||||
virtual ~DescriptionFactory();
|
||||
double GetBearing(const FixedPointCoordinate& C, const FixedPointCoordinate& B) const;
|
||||
void AppendEncodedPolylineString(std::vector<std::string> &output) const;
|
||||
void AppendUnencodedPolylineString(std::vector<std::string> &output) const;
|
||||
void AppendSegment(const FixedPointCoordinate & coordinate, const _PathData & data);
|
||||
void BuildRouteSummary(const double distance, const unsigned time);
|
||||
void SetStartSegment(const PhantomNode & start_phantom);
|
||||
void SetEndSegment(const PhantomNode & start_phantom);
|
||||
void AppendEncodedPolylineString(
|
||||
const bool return_encoded,
|
||||
std::vector<std::string> & output
|
||||
);
|
||||
|
||||
template<class DataFacadeT>
|
||||
void Run(const DataFacadeT * facade, const unsigned zoomLevel) {
|
||||
|
||||
if( pathDescription.empty() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// unsigned entireLength = 0;
|
||||
/** starts at index 1 */
|
||||
pathDescription[0].length = 0;
|
||||
for(unsigned i = 1; i < pathDescription.size(); ++i) {
|
||||
pathDescription[i].length = ApproximateEuclideanDistance(pathDescription[i-1].location, pathDescription[i].location);
|
||||
}
|
||||
|
||||
double lengthOfSegment = 0;
|
||||
unsigned durationOfSegment = 0;
|
||||
unsigned indexOfSegmentBegin = 0;
|
||||
|
||||
// std::string string0 = facade->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)
|
||||
// ){
|
||||
// SimpleLogger().Write() << "->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)
|
||||
// ){
|
||||
// SimpleLogger().Write() << "->prev correct: " << string1 << " contains " << string0;
|
||||
// pathDescription[i].nameID = pathDescription[i-1].nameID;
|
||||
// pathDescription[i].turnInstruction = TurnInstructionsClass::NoTurn;
|
||||
// }
|
||||
// }
|
||||
// if (TurnInstructionsClass::NoTurn != pathDescription[i].turnInstruction) {
|
||||
// lastTurn = i;
|
||||
// }
|
||||
// string0 = string1;
|
||||
// }
|
||||
|
||||
|
||||
for(unsigned i = 1; i < pathDescription.size(); ++i) {
|
||||
entireLength += pathDescription[i].length;
|
||||
lengthOfSegment += pathDescription[i].length;
|
||||
durationOfSegment += pathDescription[i].duration;
|
||||
pathDescription[indexOfSegmentBegin].length = lengthOfSegment;
|
||||
pathDescription[indexOfSegmentBegin].duration = durationOfSegment;
|
||||
|
||||
|
||||
if(TurnInstructionsClass::NoTurn != pathDescription[i].turnInstruction) {
|
||||
//SimpleLogger().Write() << "Turn after " << lengthOfSegment << "m into way with name id " << pathDescription[i].nameID;
|
||||
assert(pathDescription[i].necessary);
|
||||
lengthOfSegment = 0;
|
||||
durationOfSegment = 0;
|
||||
indexOfSegmentBegin = i;
|
||||
}
|
||||
}
|
||||
// SimpleLogger().Write() << "#segs: " << pathDescription.size();
|
||||
|
||||
//Post-processing to remove empty or nearly empty path segments
|
||||
if(std::numeric_limits<double>::epsilon() > pathDescription.back().length) {
|
||||
// SimpleLogger().Write() << "#segs: " << pathDescription.size() << ", last ratio: " << target_phantom.ratio << ", length: " << pathDescription.back().length;
|
||||
if(pathDescription.size() > 2){
|
||||
pathDescription.pop_back();
|
||||
pathDescription.back().necessary = true;
|
||||
pathDescription.back().turnInstruction = TurnInstructions.NoTurn;
|
||||
target_phantom.nodeBasedEdgeNameID = (pathDescription.end()-2)->nameID;
|
||||
// SimpleLogger().Write() << "Deleting last turn instruction";
|
||||
}
|
||||
} else {
|
||||
pathDescription[indexOfSegmentBegin].duration *= (1.-target_phantom.ratio);
|
||||
}
|
||||
if(std::numeric_limits<double>::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;
|
||||
start_phantom.nodeBasedEdgeNameID = pathDescription[0].nameID;
|
||||
// SimpleLogger().Write() << "Deleting first turn instruction, ratio: " << start_phantom.ratio << ", length: " << pathDescription[0].length;
|
||||
}
|
||||
} else {
|
||||
pathDescription[0].duration *= start_phantom.ratio;
|
||||
}
|
||||
|
||||
//Generalize poly line
|
||||
polyline_generalizer.Run(pathDescription, zoomLevel);
|
||||
|
||||
//fix what needs to be fixed else
|
||||
for(unsigned i = 0; i < pathDescription.size()-1 && pathDescription.size() >= 2; ++i){
|
||||
if(pathDescription[i].necessary) {
|
||||
double angle = GetBearing(pathDescription[i].location, pathDescription[i+1].location);
|
||||
pathDescription[i].bearing = angle;
|
||||
}
|
||||
}
|
||||
|
||||
// BuildRouteSummary(entireLength, duration);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DESCRIPTIONFACTORY_H_ */
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GPX_DESCRIPTOR_H_
|
||||
#define GPX_DESCRIPTOR_H_
|
||||
|
||||
#include "BaseDescriptor.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
template<class DataFacadeT>
|
||||
class GPXDescriptor : public BaseDescriptor<DataFacadeT> {
|
||||
private:
|
||||
DescriptorConfig config;
|
||||
FixedPointCoordinate current;
|
||||
|
||||
std::string tmp;
|
||||
public:
|
||||
void SetConfig(const DescriptorConfig & c) { config = c; }
|
||||
|
||||
//TODO: reorder parameters
|
||||
void Run(
|
||||
http::Reply & reply,
|
||||
const RawRouteData &rawRoute,
|
||||
PhantomNodes &phantomNodes,
|
||||
const DataFacadeT * facade
|
||||
) {
|
||||
reply.content.push_back("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
reply.content.push_back(
|
||||
"<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" "
|
||||
"xmlns=\"http://www.topografix.com/GPX/1/1\" "
|
||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||
"xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
|
||||
"\">");
|
||||
reply.content.push_back(
|
||||
"<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
|
||||
" OpenStreetMap contributors (ODbL)</license></copyright>"
|
||||
"</metadata>");
|
||||
reply.content.push_back("<rte>");
|
||||
bool found_route = (rawRoute.lengthOfShortestPath != INT_MAX) &&
|
||||
(rawRoute.computedShortestPath.size() );
|
||||
if( found_route ) {
|
||||
convertInternalLatLonToString(
|
||||
phantomNodes.startPhantom.location.lat,
|
||||
tmp
|
||||
);
|
||||
reply.content.push_back("<rtept lat=\"" + tmp + "\" ");
|
||||
convertInternalLatLonToString(
|
||||
phantomNodes.startPhantom.location.lon,
|
||||
tmp
|
||||
);
|
||||
reply.content.push_back("lon=\"" + tmp + "\"></rtept>");
|
||||
|
||||
BOOST_FOREACH(
|
||||
const _PathData & pathData,
|
||||
rawRoute.computedShortestPath
|
||||
) {
|
||||
current = facade->GetCoordinateOfNode(pathData.node);
|
||||
|
||||
convertInternalLatLonToString(current.lat, tmp);
|
||||
reply.content.push_back("<rtept lat=\"" + tmp + "\" ");
|
||||
convertInternalLatLonToString(current.lon, tmp);
|
||||
reply.content.push_back("lon=\"" + tmp + "\"></rtept>");
|
||||
}
|
||||
convertInternalLatLonToString(
|
||||
phantomNodes.targetPhantom.location.lat,
|
||||
tmp
|
||||
);
|
||||
reply.content.push_back("<rtept lat=\"" + tmp + "\" ");
|
||||
convertInternalLatLonToString(
|
||||
phantomNodes.targetPhantom.location.lon,
|
||||
tmp
|
||||
);
|
||||
reply.content.push_back("lon=\"" + tmp + "\"></rtept>");
|
||||
}
|
||||
reply.content.push_back("</rte></gpx>");
|
||||
}
|
||||
};
|
||||
#endif // GPX_DESCRIPTOR_H_
|
||||
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef JSON_DESCRIPTOR_H_
|
||||
#define JSON_DESCRIPTOR_H_
|
||||
|
||||
#include "BaseDescriptor.h"
|
||||
#include "DescriptionFactory.h"
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/Azimuth.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
template<class DataFacadeT>
|
||||
class JSONDescriptor : public BaseDescriptor<DataFacadeT> {
|
||||
private:
|
||||
DescriptorConfig config;
|
||||
DescriptionFactory description_factory;
|
||||
DescriptionFactory alternateDescriptionFactory;
|
||||
FixedPointCoordinate current;
|
||||
unsigned entered_restricted_area_count;
|
||||
struct RoundAbout{
|
||||
RoundAbout() :
|
||||
start_index(INT_MAX),
|
||||
name_id(INT_MAX),
|
||||
leave_at_exit(INT_MAX)
|
||||
{}
|
||||
int start_index;
|
||||
int name_id;
|
||||
int leave_at_exit;
|
||||
} roundAbout;
|
||||
|
||||
struct Segment {
|
||||
Segment() : name_id(-1), length(-1), position(-1) {}
|
||||
Segment(int n, int l, int p) : name_id(n), length(l), position(p) {}
|
||||
int name_id;
|
||||
int length;
|
||||
int position;
|
||||
};
|
||||
std::vector<Segment> shortest_path_segments, alternative_path_segments;
|
||||
|
||||
struct RouteNames {
|
||||
std::string shortestPathName1;
|
||||
std::string shortestPathName2;
|
||||
std::string alternativePathName1;
|
||||
std::string alternativePathName2;
|
||||
};
|
||||
|
||||
public:
|
||||
JSONDescriptor() : entered_restricted_area_count(0) {}
|
||||
void SetConfig(const DescriptorConfig & c) { config = c; }
|
||||
|
||||
//TODO: reorder parameters
|
||||
void Run(
|
||||
http::Reply & reply,
|
||||
const RawRouteData & raw_route_information,
|
||||
PhantomNodes & phantom_nodes,
|
||||
const DataFacadeT * facade
|
||||
) {
|
||||
|
||||
WriteHeaderToOutput(reply.content);
|
||||
|
||||
if(raw_route_information.lengthOfShortestPath != INT_MAX) {
|
||||
description_factory.SetStartSegment(phantom_nodes.startPhantom);
|
||||
reply.content.push_back("0,"
|
||||
"\"status_message\": \"Found route between points\",");
|
||||
|
||||
//Get all the coordinates for the computed route
|
||||
BOOST_FOREACH(const _PathData & path_data, raw_route_information.computedShortestPath) {
|
||||
current = facade->GetCoordinateOfNode(path_data.node);
|
||||
description_factory.AppendSegment(current, path_data );
|
||||
}
|
||||
description_factory.SetEndSegment(phantom_nodes.targetPhantom);
|
||||
} else {
|
||||
//We do not need to do much, if there is no route ;-)
|
||||
reply.content.push_back("207,"
|
||||
"\"status_message\": \"Cannot find route between points\",");
|
||||
}
|
||||
|
||||
description_factory.Run(facade, config.zoom_level);
|
||||
reply.content.push_back("\"route_geometry\": ");
|
||||
if(config.geometry) {
|
||||
description_factory.AppendEncodedPolylineString(
|
||||
config.encode_geometry,
|
||||
reply.content
|
||||
);
|
||||
} else {
|
||||
reply.content.push_back("[]");
|
||||
}
|
||||
|
||||
reply.content.push_back(","
|
||||
"\"route_instructions\": [");
|
||||
entered_restricted_area_count = 0;
|
||||
if(config.instructions) {
|
||||
BuildTextualDescription(
|
||||
description_factory,
|
||||
reply,
|
||||
raw_route_information.lengthOfShortestPath,
|
||||
facade,
|
||||
shortest_path_segments
|
||||
);
|
||||
} else {
|
||||
BOOST_FOREACH(
|
||||
const SegmentInformation & segment,
|
||||
description_factory.pathDescription
|
||||
) {
|
||||
TurnInstruction current_instruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag;
|
||||
entered_restricted_area_count += (current_instruction != segment.turnInstruction);
|
||||
}
|
||||
}
|
||||
reply.content.push_back("],");
|
||||
description_factory.BuildRouteSummary(
|
||||
description_factory.entireLength,
|
||||
raw_route_information.lengthOfShortestPath - ( entered_restricted_area_count*TurnInstructions.AccessRestrictionPenalty)
|
||||
);
|
||||
|
||||
reply.content.push_back("\"route_summary\":");
|
||||
reply.content.push_back("{");
|
||||
reply.content.push_back("\"total_distance\":");
|
||||
reply.content.push_back(description_factory.summary.lengthString);
|
||||
reply.content.push_back(","
|
||||
"\"total_time\":");
|
||||
reply.content.push_back(description_factory.summary.durationString);
|
||||
reply.content.push_back(","
|
||||
"\"start_point\":\"");
|
||||
reply.content.push_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.startName)
|
||||
);
|
||||
reply.content.push_back("\","
|
||||
"\"end_point\":\"");
|
||||
reply.content.push_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.destName)
|
||||
);
|
||||
reply.content.push_back("\"");
|
||||
reply.content.push_back("}");
|
||||
reply.content.push_back(",");
|
||||
|
||||
//only one alternative route is computed at this time, so this is hardcoded
|
||||
|
||||
if(raw_route_information.lengthOfAlternativePath != INT_MAX) {
|
||||
alternateDescriptionFactory.SetStartSegment(phantom_nodes.startPhantom);
|
||||
//Get all the coordinates for the computed route
|
||||
BOOST_FOREACH(const _PathData & path_data, raw_route_information.computedAlternativePath) {
|
||||
current = facade->GetCoordinateOfNode(path_data.node);
|
||||
alternateDescriptionFactory.AppendSegment(current, path_data );
|
||||
}
|
||||
alternateDescriptionFactory.SetEndSegment(phantom_nodes.targetPhantom);
|
||||
}
|
||||
alternateDescriptionFactory.Run(facade, config.zoom_level);
|
||||
|
||||
//give an array of alternative routes
|
||||
reply.content.push_back("\"alternative_geometries\": [");
|
||||
if(config.geometry && INT_MAX != raw_route_information.lengthOfAlternativePath) {
|
||||
//Generate the linestrings for each alternative
|
||||
alternateDescriptionFactory.AppendEncodedPolylineString(
|
||||
config.encode_geometry,
|
||||
reply.content
|
||||
);
|
||||
}
|
||||
reply.content.push_back("],");
|
||||
reply.content.push_back("\"alternative_instructions\":[");
|
||||
entered_restricted_area_count = 0;
|
||||
if(INT_MAX != raw_route_information.lengthOfAlternativePath) {
|
||||
reply.content.push_back("[");
|
||||
//Generate instructions for each alternative
|
||||
if(config.instructions) {
|
||||
BuildTextualDescription(
|
||||
alternateDescriptionFactory,
|
||||
reply,
|
||||
raw_route_information.lengthOfAlternativePath,
|
||||
facade,
|
||||
alternative_path_segments
|
||||
);
|
||||
} else {
|
||||
BOOST_FOREACH(const SegmentInformation & segment, alternateDescriptionFactory.pathDescription) {
|
||||
TurnInstruction current_instruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag;
|
||||
entered_restricted_area_count += (current_instruction != segment.turnInstruction);
|
||||
}
|
||||
}
|
||||
reply.content.push_back("]");
|
||||
}
|
||||
reply.content.push_back("],");
|
||||
reply.content.push_back("\"alternative_summaries\":[");
|
||||
if(INT_MAX != raw_route_information.lengthOfAlternativePath) {
|
||||
//Generate route summary (length, duration) for each alternative
|
||||
alternateDescriptionFactory.BuildRouteSummary(alternateDescriptionFactory.entireLength, raw_route_information.lengthOfAlternativePath - ( entered_restricted_area_count*TurnInstructions.AccessRestrictionPenalty));
|
||||
reply.content.push_back("{");
|
||||
reply.content.push_back("\"total_distance\":");
|
||||
reply.content.push_back(alternateDescriptionFactory.summary.lengthString);
|
||||
reply.content.push_back(","
|
||||
"\"total_time\":");
|
||||
reply.content.push_back(alternateDescriptionFactory.summary.durationString);
|
||||
reply.content.push_back(","
|
||||
"\"start_point\":\"");
|
||||
reply.content.push_back(facade->GetEscapedNameForNameID(description_factory.summary.startName));
|
||||
reply.content.push_back("\","
|
||||
"\"end_point\":\"");
|
||||
reply.content.push_back(facade->GetEscapedNameForNameID(description_factory.summary.destName));
|
||||
reply.content.push_back("\"");
|
||||
reply.content.push_back("}");
|
||||
}
|
||||
reply.content.push_back("],");
|
||||
|
||||
//Get Names for both routes
|
||||
RouteNames routeNames;
|
||||
GetRouteNames(shortest_path_segments, alternative_path_segments, facade, routeNames);
|
||||
|
||||
reply.content.push_back("\"route_name\":[\"");
|
||||
reply.content.push_back(routeNames.shortestPathName1);
|
||||
reply.content.push_back("\",\"");
|
||||
reply.content.push_back(routeNames.shortestPathName2);
|
||||
reply.content.push_back("\"],"
|
||||
"\"alternative_names\":[");
|
||||
reply.content.push_back("[\"");
|
||||
reply.content.push_back(routeNames.alternativePathName1);
|
||||
reply.content.push_back("\",\"");
|
||||
reply.content.push_back(routeNames.alternativePathName2);
|
||||
reply.content.push_back("\"]");
|
||||
reply.content.push_back("],");
|
||||
//list all viapoints so that the client may display it
|
||||
reply.content.push_back("\"via_points\":[");
|
||||
std::string tmp;
|
||||
if(config.geometry && INT_MAX != raw_route_information.lengthOfShortestPath) {
|
||||
for(unsigned i = 0; i < raw_route_information.segmentEndCoordinates.size(); ++i) {
|
||||
reply.content.push_back("[");
|
||||
if(raw_route_information.segmentEndCoordinates[i].startPhantom.location.isSet())
|
||||
convertInternalReversedCoordinateToString(raw_route_information.segmentEndCoordinates[i].startPhantom.location, tmp);
|
||||
else
|
||||
convertInternalReversedCoordinateToString(raw_route_information.rawViaNodeCoordinates[i], tmp);
|
||||
|
||||
reply.content.push_back(tmp);
|
||||
reply.content.push_back("],");
|
||||
}
|
||||
reply.content.push_back("[");
|
||||
if(raw_route_information.segmentEndCoordinates.back().startPhantom.location.isSet())
|
||||
convertInternalReversedCoordinateToString(raw_route_information.segmentEndCoordinates.back().targetPhantom.location, tmp);
|
||||
else
|
||||
convertInternalReversedCoordinateToString(raw_route_information.rawViaNodeCoordinates.back(), tmp);
|
||||
reply.content.push_back(tmp);
|
||||
reply.content.push_back("]");
|
||||
}
|
||||
reply.content.push_back("],");
|
||||
reply.content.push_back("\"hint_data\": {");
|
||||
reply.content.push_back("\"checksum\":");
|
||||
intToString(raw_route_information.checkSum, tmp);
|
||||
reply.content.push_back(tmp);
|
||||
reply.content.push_back(", \"locations\": [");
|
||||
|
||||
std::string hint;
|
||||
for(unsigned i = 0; i < raw_route_information.segmentEndCoordinates.size(); ++i) {
|
||||
reply.content.push_back("\"");
|
||||
EncodeObjectToBase64(raw_route_information.segmentEndCoordinates[i].startPhantom, hint);
|
||||
reply.content.push_back(hint);
|
||||
reply.content.push_back("\", ");
|
||||
}
|
||||
EncodeObjectToBase64(raw_route_information.segmentEndCoordinates.back().targetPhantom, hint);
|
||||
reply.content.push_back("\"");
|
||||
reply.content.push_back(hint);
|
||||
reply.content.push_back("\"]");
|
||||
reply.content.push_back("},");
|
||||
reply.content.push_back("\"transactionId\": \"OSRM Routing Engine JSON Descriptor (v0.3)\"");
|
||||
reply.content.push_back("}");
|
||||
}
|
||||
|
||||
// construct routes names
|
||||
void GetRouteNames(
|
||||
std::vector<Segment> & shortest_path_segments,
|
||||
std::vector<Segment> & alternative_path_segments,
|
||||
const DataFacadeT * facade,
|
||||
RouteNames & routeNames
|
||||
) {
|
||||
|
||||
Segment shortestSegment1, shortestSegment2;
|
||||
Segment alternativeSegment1, alternativeSegment2;
|
||||
|
||||
if(0 < shortest_path_segments.size()) {
|
||||
sort(shortest_path_segments.begin(), shortest_path_segments.end(), boost::bind(&Segment::length, _1) > boost::bind(&Segment::length, _2) );
|
||||
shortestSegment1 = shortest_path_segments[0];
|
||||
if(0 < alternative_path_segments.size()) {
|
||||
sort(alternative_path_segments.begin(), alternative_path_segments.end(), boost::bind(&Segment::length, _1) > boost::bind(&Segment::length, _2) );
|
||||
alternativeSegment1 = alternative_path_segments[0];
|
||||
}
|
||||
std::vector<Segment> shortestDifference(shortest_path_segments.size());
|
||||
std::vector<Segment> alternativeDifference(alternative_path_segments.size());
|
||||
std::set_difference(shortest_path_segments.begin(), shortest_path_segments.end(), alternative_path_segments.begin(), alternative_path_segments.end(), shortestDifference.begin(), boost::bind(&Segment::name_id, _1) < boost::bind(&Segment::name_id, _2) );
|
||||
int size_of_difference = shortestDifference.size();
|
||||
if(0 < size_of_difference ) {
|
||||
int i = 0;
|
||||
while( i < size_of_difference && shortestDifference[i].name_id == shortest_path_segments[0].name_id) {
|
||||
++i;
|
||||
}
|
||||
if(i < size_of_difference ) {
|
||||
shortestSegment2 = shortestDifference[i];
|
||||
}
|
||||
}
|
||||
|
||||
std::set_difference(alternative_path_segments.begin(), alternative_path_segments.end(), shortest_path_segments.begin(), shortest_path_segments.end(), alternativeDifference.begin(), boost::bind(&Segment::name_id, _1) < boost::bind(&Segment::name_id, _2) );
|
||||
size_of_difference = alternativeDifference.size();
|
||||
if(0 < size_of_difference ) {
|
||||
int i = 0;
|
||||
while( i < size_of_difference && alternativeDifference[i].name_id == alternative_path_segments[0].name_id) {
|
||||
++i;
|
||||
}
|
||||
if(i < size_of_difference ) {
|
||||
alternativeSegment2 = alternativeDifference[i];
|
||||
}
|
||||
}
|
||||
if(shortestSegment1.position > shortestSegment2.position)
|
||||
std::swap(shortestSegment1, shortestSegment2);
|
||||
|
||||
if(alternativeSegment1.position > alternativeSegment2.position)
|
||||
std::swap(alternativeSegment1, alternativeSegment2);
|
||||
|
||||
routeNames.shortestPathName1 = facade->GetEscapedNameForNameID(
|
||||
shortestSegment1.name_id
|
||||
);
|
||||
routeNames.shortestPathName2 = facade->GetEscapedNameForNameID(
|
||||
shortestSegment2.name_id
|
||||
);
|
||||
|
||||
routeNames.alternativePathName1 = facade->GetEscapedNameForNameID(
|
||||
alternativeSegment1.name_id
|
||||
);
|
||||
routeNames.alternativePathName2 = facade->GetEscapedNameForNameID(
|
||||
alternativeSegment2.name_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteHeaderToOutput(std::vector<std::string> & output) {
|
||||
output.push_back(
|
||||
"{"
|
||||
"\"version\": 0.3,"
|
||||
"\"status\":"
|
||||
);
|
||||
}
|
||||
|
||||
//TODO: reorder parameters
|
||||
inline void BuildTextualDescription(
|
||||
DescriptionFactory & description_factory,
|
||||
http::Reply & reply,
|
||||
const int route_length,
|
||||
const DataFacadeT * facade,
|
||||
std::vector<Segment> & route_segments_list
|
||||
) {
|
||||
//Segment information has following format:
|
||||
//["instruction","streetname",length,position,time,"length","earth_direction",azimuth]
|
||||
//Example: ["Turn left","High Street",200,4,10,"200m","NE",22.5]
|
||||
//See also: http://developers.cloudmade.com/wiki/navengine/JSON_format
|
||||
unsigned prefixSumOfNecessarySegments = 0;
|
||||
roundAbout.leave_at_exit = 0;
|
||||
roundAbout.name_id = 0;
|
||||
std::string tmpDist, tmpLength, tmpDuration, tmpBearing, tmpInstruction;
|
||||
//Fetch data from Factory and generate a string from it.
|
||||
BOOST_FOREACH(const SegmentInformation & segment, description_factory.pathDescription) {
|
||||
TurnInstruction current_instruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag;
|
||||
entered_restricted_area_count += (current_instruction != segment.turnInstruction);
|
||||
if(TurnInstructions.TurnIsNecessary( current_instruction) ) {
|
||||
if(TurnInstructions.EnterRoundAbout == current_instruction) {
|
||||
roundAbout.name_id = segment.nameID;
|
||||
roundAbout.start_index = prefixSumOfNecessarySegments;
|
||||
} else {
|
||||
if(0 != prefixSumOfNecessarySegments){
|
||||
reply.content.push_back(",");
|
||||
}
|
||||
reply.content.push_back("[\"");
|
||||
if(TurnInstructions.LeaveRoundAbout == current_instruction) {
|
||||
intToString(TurnInstructions.EnterRoundAbout, tmpInstruction);
|
||||
reply.content.push_back(tmpInstruction);
|
||||
reply.content.push_back("-");
|
||||
intToString(roundAbout.leave_at_exit+1, tmpInstruction);
|
||||
reply.content.push_back(tmpInstruction);
|
||||
roundAbout.leave_at_exit = 0;
|
||||
} else {
|
||||
intToString(current_instruction, tmpInstruction);
|
||||
reply.content.push_back(tmpInstruction);
|
||||
}
|
||||
|
||||
reply.content.push_back("\",\"");
|
||||
reply.content.push_back(facade->GetEscapedNameForNameID(segment.nameID));
|
||||
reply.content.push_back("\",");
|
||||
intToString(segment.length, tmpDist);
|
||||
reply.content.push_back(tmpDist);
|
||||
reply.content.push_back(",");
|
||||
intToString(prefixSumOfNecessarySegments, tmpLength);
|
||||
reply.content.push_back(tmpLength);
|
||||
reply.content.push_back(",");
|
||||
intToString(segment.duration/10, tmpDuration);
|
||||
reply.content.push_back(tmpDuration);
|
||||
reply.content.push_back(",\"");
|
||||
intToString(segment.length, tmpLength);
|
||||
reply.content.push_back(tmpLength);
|
||||
reply.content.push_back("m\",\"");
|
||||
reply.content.push_back(Azimuth::Get(segment.bearing));
|
||||
reply.content.push_back("\",");
|
||||
intToString(round(segment.bearing), tmpBearing);
|
||||
reply.content.push_back(tmpBearing);
|
||||
reply.content.push_back("]");
|
||||
|
||||
route_segments_list.push_back(
|
||||
Segment(
|
||||
segment.nameID,
|
||||
segment.length,
|
||||
route_segments_list.size()
|
||||
)
|
||||
);
|
||||
}
|
||||
} else if(TurnInstructions.StayOnRoundAbout == current_instruction) {
|
||||
++roundAbout.leave_at_exit;
|
||||
}
|
||||
if(segment.necessary)
|
||||
++prefixSumOfNecessarySegments;
|
||||
}
|
||||
if(INT_MAX != route_length) {
|
||||
reply.content.push_back(",[\"");
|
||||
intToString(TurnInstructions.ReachedYourDestination, tmpInstruction);
|
||||
reply.content.push_back(tmpInstruction);
|
||||
reply.content.push_back("\",\"");
|
||||
reply.content.push_back("\",");
|
||||
reply.content.push_back("0");
|
||||
reply.content.push_back(",");
|
||||
intToString(prefixSumOfNecessarySegments-1, tmpLength);
|
||||
reply.content.push_back(tmpLength);
|
||||
reply.content.push_back(",");
|
||||
reply.content.push_back("0");
|
||||
reply.content.push_back(",\"");
|
||||
reply.content.push_back("\",\"");
|
||||
reply.content.push_back(Azimuth::Get(0.0));
|
||||
reply.content.push_back("\",");
|
||||
reply.content.push_back("0.0");
|
||||
reply.content.push_back("]");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
#endif /* JSON_DESCRIPTOR_H_ */
|
||||
@@ -0,0 +1,3 @@
|
||||
The javascript based web client is a seperate project available at
|
||||
|
||||
https://github.com/DennisSchiefer/Project-OSRM-Web
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "BaseParser.h"
|
||||
|
||||
BaseParser::BaseParser(ExtractorCallbacks* ec, ScriptingEnvironment& se) :
|
||||
extractor_callbacks(ec), scriptingEnvironment(se), luaState(NULL), use_turn_restrictions(true) {
|
||||
luaState = se.getLuaStateForThreadID(0);
|
||||
ReadUseRestrictionsSetting();
|
||||
ReadRestrictionExceptions();
|
||||
}
|
||||
|
||||
void BaseParser::ReadUseRestrictionsSetting() {
|
||||
if( 0 != luaL_dostring( luaState, "return use_turn_restrictions\n") ) {
|
||||
throw OSRMException(
|
||||
/*lua_tostring( luaState, -1 ) + */"ERROR occured in scripting block"
|
||||
);
|
||||
}
|
||||
if( lua_isboolean( luaState, -1) ) {
|
||||
use_turn_restrictions = lua_toboolean(luaState, -1);
|
||||
}
|
||||
if( use_turn_restrictions ) {
|
||||
SimpleLogger().Write() << "Using turn restrictions";
|
||||
} else {
|
||||
SimpleLogger().Write() << "Ignoring turn restrictions";
|
||||
}
|
||||
}
|
||||
|
||||
void BaseParser::ReadRestrictionExceptions() {
|
||||
if(lua_function_exists(luaState, "get_exceptions" )) {
|
||||
//get list of turn restriction exceptions
|
||||
luabind::call_function<void>(
|
||||
luaState,
|
||||
"get_exceptions",
|
||||
boost::ref(restriction_exceptions)
|
||||
);
|
||||
SimpleLogger().Write() << "Found " << restriction_exceptions.size() << " exceptions to turn restriction";
|
||||
BOOST_FOREACH(const std::string & str, restriction_exceptions) {
|
||||
SimpleLogger().Write() << " " << str;
|
||||
}
|
||||
} else {
|
||||
SimpleLogger().Write() << "Found no exceptions to turn restrictions";
|
||||
}
|
||||
}
|
||||
|
||||
void BaseParser::report_errors(lua_State *L, const int status) const {
|
||||
if( 0!=status ) {
|
||||
std::cerr << "-- " << lua_tostring(L, -1) << std::endl;
|
||||
lua_pop(L, 1); // remove error message
|
||||
}
|
||||
}
|
||||
|
||||
void BaseParser::ParseNodeInLua(ImportNode& n, lua_State* localLuaState) {
|
||||
luabind::call_function<void>( localLuaState, "node_function", boost::ref(n) );
|
||||
}
|
||||
|
||||
void BaseParser::ParseWayInLua(ExtractionWay& w, lua_State* localLuaState) {
|
||||
luabind::call_function<void>( localLuaState, "way_function", boost::ref(w) );
|
||||
}
|
||||
|
||||
bool BaseParser::ShouldIgnoreRestriction(const std::string & except_tag_string) const {
|
||||
//should this restriction be ignored? yes if there's an overlap between:
|
||||
//a) the list of modes in the except tag of the restriction (except_tag_string), ex: except=bus;bicycle
|
||||
//b) the lua profile defines a hierachy of modes, ex: [access, vehicle, bicycle]
|
||||
|
||||
if( "" == except_tag_string ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Be warned, this is quadratic work here, but we assume that
|
||||
//only a few exceptions are actually defined.
|
||||
std::vector<std::string> exceptions;
|
||||
boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*"));
|
||||
BOOST_FOREACH(std::string& str, exceptions) {
|
||||
if( restriction_exceptions.end() != std::find(restriction_exceptions.begin(), restriction_exceptions.end(), str) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BASEPARSER_H_
|
||||
#define BASEPARSER_H_
|
||||
|
||||
#include "ExtractorCallbacks.h"
|
||||
#include "ScriptingEnvironment.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
extern "C" {
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
}
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
class BaseParser : boost::noncopyable {
|
||||
public:
|
||||
BaseParser(ExtractorCallbacks* ec, ScriptingEnvironment& se);
|
||||
virtual ~BaseParser() {}
|
||||
virtual bool ReadHeader() = 0;
|
||||
virtual bool Parse() = 0;
|
||||
|
||||
virtual void ParseNodeInLua(ImportNode& n, lua_State* luaStateForThread);
|
||||
virtual void ParseWayInLua(ExtractionWay& n, lua_State* luaStateForThread);
|
||||
virtual void report_errors(lua_State *L, const int status) const;
|
||||
|
||||
protected:
|
||||
virtual void ReadUseRestrictionsSetting();
|
||||
virtual void ReadRestrictionExceptions();
|
||||
virtual bool ShouldIgnoreRestriction(const std::string& except_tag_string) const;
|
||||
|
||||
ExtractorCallbacks* extractor_callbacks;
|
||||
ScriptingEnvironment& scriptingEnvironment;
|
||||
lua_State* luaState;
|
||||
std::vector<std::string> restriction_exceptions;
|
||||
bool use_turn_restrictions;
|
||||
|
||||
};
|
||||
|
||||
#endif /* BASEPARSER_H_ */
|
||||
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "ExtractionContainers.h"
|
||||
|
||||
void ExtractionContainers::PrepareData(
|
||||
const std::string & output_file_name,
|
||||
const std::string & restrictions_file_name
|
||||
) {
|
||||
try {
|
||||
unsigned number_of_used_nodes = 0;
|
||||
unsigned number_of_used_edges = 0;
|
||||
double time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] Sorting used nodes ... " << std::flush;
|
||||
stxxl::sort(
|
||||
used_node_id_list.begin(),
|
||||
used_node_id_list.end(),
|
||||
Cmp(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
|
||||
time = get_timestamp();
|
||||
std::cout << "[extractor] Erasing duplicate nodes ... " << std::flush;
|
||||
stxxl::vector<NodeID>::iterator NewEnd = std::unique ( used_node_id_list.begin(),used_node_id_list.end() ) ;
|
||||
used_node_id_list.resize ( NewEnd - used_node_id_list.begin() );
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] Sorting all nodes ... " << std::flush;
|
||||
stxxl::sort(
|
||||
all_nodes_list.begin(),
|
||||
all_nodes_list.end(),
|
||||
CmpNodeByID(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] Sorting used ways ... " << std::flush;
|
||||
stxxl::sort(
|
||||
way_start_end_id_list.begin(),
|
||||
way_start_end_id_list.end(),
|
||||
CmpWayByID(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Sorting restrctns. by from... " << std::flush;
|
||||
stxxl::sort(
|
||||
restrictions_list.begin(),
|
||||
restrictions_list.end(),
|
||||
CmpRestrictionContainerByFrom(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Fixing restriction starts ... " << std::flush;
|
||||
STXXLRestrictionsVector::iterator restrictions_iterator = restrictions_list.begin();
|
||||
STXXLWayIDStartEndVector::iterator way_start_and_end_iterator = way_start_end_id_list.begin();
|
||||
|
||||
while(
|
||||
way_start_and_end_iterator != way_start_end_id_list.end() &&
|
||||
restrictions_iterator != restrictions_list.end()
|
||||
) {
|
||||
|
||||
if(way_start_and_end_iterator->wayID < restrictions_iterator->fromWay){
|
||||
++way_start_and_end_iterator;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(way_start_and_end_iterator->wayID > restrictions_iterator->fromWay) {
|
||||
++restrictions_iterator;
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(way_start_and_end_iterator->wayID == restrictions_iterator->fromWay);
|
||||
NodeID via_node_id = restrictions_iterator->restriction.viaNode;
|
||||
|
||||
if(way_start_and_end_iterator->firstStart == via_node_id) {
|
||||
restrictions_iterator->restriction.fromNode = way_start_and_end_iterator->firstTarget;
|
||||
} else if(way_start_and_end_iterator->firstTarget == via_node_id) {
|
||||
restrictions_iterator->restriction.fromNode = way_start_and_end_iterator->firstStart;
|
||||
} else if(way_start_and_end_iterator->lastStart == via_node_id) {
|
||||
restrictions_iterator->restriction.fromNode = way_start_and_end_iterator->lastTarget;
|
||||
} else if(way_start_and_end_iterator->lastTarget == via_node_id) {
|
||||
restrictions_iterator->restriction.fromNode = way_start_and_end_iterator->lastStart;
|
||||
}
|
||||
++restrictions_iterator;
|
||||
}
|
||||
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] Sorting restrctns. by to ... " << std::flush;
|
||||
stxxl::sort(
|
||||
restrictions_list.begin(),
|
||||
restrictions_list.end(),
|
||||
CmpRestrictionContainerByTo(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
|
||||
time = get_timestamp();
|
||||
unsigned usableRestrictionsCounter(0);
|
||||
std::cout << "[extractor] Fixing restriction ends ... " << std::flush;
|
||||
restrictions_iterator = restrictions_list.begin();
|
||||
way_start_and_end_iterator = way_start_end_id_list.begin();
|
||||
while(
|
||||
way_start_and_end_iterator != way_start_end_id_list.end() &&
|
||||
restrictions_iterator != restrictions_list.end()
|
||||
) {
|
||||
if(way_start_and_end_iterator->wayID < restrictions_iterator->toWay){
|
||||
++way_start_and_end_iterator;
|
||||
continue;
|
||||
}
|
||||
if(way_start_and_end_iterator->wayID > restrictions_iterator->toWay) {
|
||||
++restrictions_iterator;
|
||||
continue;
|
||||
}
|
||||
NodeID via_node_id = restrictions_iterator->restriction.viaNode;
|
||||
if(way_start_and_end_iterator->lastStart == via_node_id) {
|
||||
restrictions_iterator->restriction.toNode = way_start_and_end_iterator->lastTarget;
|
||||
} else if(way_start_and_end_iterator->lastTarget == via_node_id) {
|
||||
restrictions_iterator->restriction.toNode = way_start_and_end_iterator->lastStart;
|
||||
} else if(way_start_and_end_iterator->firstStart == via_node_id) {
|
||||
restrictions_iterator->restriction.toNode = way_start_and_end_iterator->firstTarget;
|
||||
} else if(way_start_and_end_iterator->firstTarget == via_node_id) {
|
||||
restrictions_iterator->restriction.toNode = way_start_and_end_iterator->firstStart;
|
||||
}
|
||||
|
||||
if(
|
||||
UINT_MAX != restrictions_iterator->restriction.fromNode &&
|
||||
UINT_MAX != restrictions_iterator->restriction.toNode
|
||||
) {
|
||||
++usableRestrictionsCounter;
|
||||
}
|
||||
++restrictions_iterator;
|
||||
}
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
SimpleLogger().Write() << "usable restrictions: " << usableRestrictionsCounter;
|
||||
//serialize restrictions
|
||||
std::ofstream restrictions_out_stream;
|
||||
restrictions_out_stream.open(restrictions_file_name.c_str(), std::ios::binary);
|
||||
restrictions_out_stream.write((char*)&uuid, sizeof(UUID));
|
||||
restrictions_out_stream.write(
|
||||
(char*)&usableRestrictionsCounter,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
for(
|
||||
restrictions_iterator = restrictions_list.begin();
|
||||
restrictions_iterator != restrictions_list.end();
|
||||
++restrictions_iterator
|
||||
) {
|
||||
if(
|
||||
UINT_MAX != restrictions_iterator->restriction.fromNode &&
|
||||
UINT_MAX != restrictions_iterator->restriction.toNode
|
||||
) {
|
||||
restrictions_out_stream.write(
|
||||
(char *)&(restrictions_iterator->restriction),
|
||||
sizeof(TurnRestriction)
|
||||
);
|
||||
}
|
||||
}
|
||||
restrictions_out_stream.close();
|
||||
|
||||
std::ofstream file_out_stream;
|
||||
file_out_stream.open(output_file_name.c_str(), std::ios::binary);
|
||||
file_out_stream.write((char*)&uuid, sizeof(UUID));
|
||||
file_out_stream.write((char*)&number_of_used_nodes, sizeof(unsigned));
|
||||
time = get_timestamp();
|
||||
std::cout << "[extractor] Confirming/Writing used nodes ... " << std::flush;
|
||||
|
||||
//identify all used nodes by a merging step of two sorted lists
|
||||
STXXLNodeVector::iterator node_iterator = all_nodes_list.begin();
|
||||
STXXLNodeIDVector::iterator node_id_iterator = used_node_id_list.begin();
|
||||
while(
|
||||
node_id_iterator != used_node_id_list.end() &&
|
||||
node_iterator != all_nodes_list.end()
|
||||
) {
|
||||
if(*node_id_iterator < node_iterator->id){
|
||||
++node_id_iterator;
|
||||
continue;
|
||||
}
|
||||
if(*node_id_iterator > node_iterator->id) {
|
||||
++node_iterator;
|
||||
continue;
|
||||
}
|
||||
BOOST_ASSERT( *node_id_iterator == node_iterator->id);
|
||||
|
||||
file_out_stream.write(
|
||||
(char*)&(*node_iterator),
|
||||
sizeof(ExternalMemoryNode)
|
||||
);
|
||||
|
||||
++number_of_used_nodes;
|
||||
++node_id_iterator;
|
||||
++node_iterator;
|
||||
}
|
||||
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] setting number of nodes ... " << std::flush;
|
||||
std::ios::pos_type previous_file_position = file_out_stream.tellp();
|
||||
file_out_stream.seekp(std::ios::beg+sizeof(UUID));
|
||||
file_out_stream.write((char*)&number_of_used_nodes, sizeof(unsigned));
|
||||
file_out_stream.seekp(previous_file_position);
|
||||
|
||||
std::cout << "ok" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
// Sort edges by start.
|
||||
std::cout << "[extractor] Sorting edges by start ... " << std::flush;
|
||||
stxxl::sort(
|
||||
all_edges_list.begin(),
|
||||
all_edges_list.end(),
|
||||
CmpEdgeByStartID(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] Setting start coords ... " << std::flush;
|
||||
file_out_stream.write((char*)&number_of_used_edges, sizeof(unsigned));
|
||||
// Traverse list of edges and nodes in parallel and set start coord
|
||||
node_iterator = all_nodes_list.begin();
|
||||
STXXLEdgeVector::iterator edge_iterator = all_edges_list.begin();
|
||||
while(
|
||||
edge_iterator != all_edges_list.end() &&
|
||||
node_iterator != all_nodes_list.end()
|
||||
) {
|
||||
if(edge_iterator->start < node_iterator->id){
|
||||
++edge_iterator;
|
||||
continue;
|
||||
}
|
||||
if(edge_iterator->start > node_iterator->id) {
|
||||
node_iterator++;
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(edge_iterator->start == node_iterator->id);
|
||||
edge_iterator->startCoord.lat = node_iterator->lat;
|
||||
edge_iterator->startCoord.lon = node_iterator->lon;
|
||||
++edge_iterator;
|
||||
}
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
// Sort Edges by target
|
||||
std::cout << "[extractor] Sorting edges by target ... " << std::flush;
|
||||
stxxl::sort(
|
||||
all_edges_list.begin(),
|
||||
all_edges_list.end(),
|
||||
CmpEdgeByTargetID(),
|
||||
4294967296
|
||||
);
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] Setting target coords ... " << std::flush;
|
||||
// Traverse list of edges and nodes in parallel and set target coord
|
||||
node_iterator = all_nodes_list.begin();
|
||||
edge_iterator = all_edges_list.begin();
|
||||
|
||||
while(
|
||||
edge_iterator != all_edges_list.end() &&
|
||||
node_iterator != all_nodes_list.end()
|
||||
) {
|
||||
if(edge_iterator->target < node_iterator->id){
|
||||
++edge_iterator;
|
||||
continue;
|
||||
}
|
||||
if(edge_iterator->target > node_iterator->id) {
|
||||
++node_iterator;
|
||||
continue;
|
||||
}
|
||||
BOOST_ASSERT(edge_iterator->target == node_iterator->id);
|
||||
if(edge_iterator->startCoord.lat != INT_MIN && edge_iterator->startCoord.lon != INT_MIN) {
|
||||
edge_iterator->targetCoord.lat = node_iterator->lat;
|
||||
edge_iterator->targetCoord.lon = node_iterator->lon;
|
||||
|
||||
const double distance = ApproximateDistance(
|
||||
edge_iterator->startCoord.lat,
|
||||
edge_iterator->startCoord.lon,
|
||||
node_iterator->lat,
|
||||
node_iterator->lon
|
||||
);
|
||||
|
||||
BOOST_ASSERT(edge_iterator->speed != -1);
|
||||
const double weight = ( distance * 10. ) / (edge_iterator->speed / 3.6);
|
||||
int integer_weight = std::max( 1, (int)std::floor((edge_iterator->isDurationSet ? edge_iterator->speed : weight)+.5) );
|
||||
int integer_distance = std::max( 1, (int)distance );
|
||||
short zero = 0;
|
||||
short one = 1;
|
||||
|
||||
file_out_stream.write((char*)&edge_iterator->start, sizeof(unsigned));
|
||||
file_out_stream.write((char*)&edge_iterator->target, sizeof(unsigned));
|
||||
file_out_stream.write((char*)&integer_distance, sizeof(int));
|
||||
switch(edge_iterator->direction) {
|
||||
case ExtractionWay::notSure:
|
||||
file_out_stream.write((char*)&zero, sizeof(short));
|
||||
break;
|
||||
case ExtractionWay::oneway:
|
||||
file_out_stream.write((char*)&one, sizeof(short));
|
||||
break;
|
||||
case ExtractionWay::bidirectional:
|
||||
file_out_stream.write((char*)&zero, sizeof(short));
|
||||
|
||||
break;
|
||||
case ExtractionWay::opposite:
|
||||
file_out_stream.write((char*)&one, sizeof(short));
|
||||
break;
|
||||
default:
|
||||
throw OSRMException("edge has broken direction");
|
||||
break;
|
||||
}
|
||||
file_out_stream.write(
|
||||
(char*)&integer_weight, sizeof(int)
|
||||
);
|
||||
BOOST_ASSERT(edge_iterator->type >= 0);
|
||||
file_out_stream.write(
|
||||
(char*)&edge_iterator->type,
|
||||
sizeof(short)
|
||||
);
|
||||
file_out_stream.write(
|
||||
(char*)&edge_iterator->nameID,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
file_out_stream.write(
|
||||
(char*)&edge_iterator->isRoundabout,
|
||||
sizeof(bool)
|
||||
);
|
||||
file_out_stream.write(
|
||||
(char*)&edge_iterator->ignoreInGrid,
|
||||
sizeof(bool)
|
||||
);
|
||||
file_out_stream.write(
|
||||
(char*)&edge_iterator->isAccessRestricted,
|
||||
sizeof(bool)
|
||||
);
|
||||
file_out_stream.write(
|
||||
(char*)&edge_iterator->isContraFlow,
|
||||
sizeof(bool)
|
||||
);
|
||||
++number_of_used_edges;
|
||||
}
|
||||
++edge_iterator;
|
||||
}
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
std::cout << "[extractor] setting number of edges ... " << std::flush;
|
||||
|
||||
file_out_stream.seekp(previous_file_position);
|
||||
file_out_stream.write((char*)&number_of_used_edges, sizeof(unsigned));
|
||||
file_out_stream.close();
|
||||
std::cout << "ok" << std::endl;
|
||||
time = get_timestamp();
|
||||
|
||||
std::cout << "[extractor] writing street name index ... " << std::flush;
|
||||
std::string name_file_streamName = (output_file_name + ".names");
|
||||
boost::filesystem::ofstream name_file_stream(
|
||||
name_file_streamName,
|
||||
std::ios::binary
|
||||
);
|
||||
|
||||
//write number of names
|
||||
const unsigned number_of_names = name_list.size()+1;
|
||||
name_file_stream.write((char *)&(number_of_names), sizeof(unsigned));
|
||||
|
||||
//compute total number of chars
|
||||
unsigned total_number_of_chars = 0;
|
||||
BOOST_FOREACH(const std::string & temp_string, name_list) {
|
||||
total_number_of_chars += temp_string.length();
|
||||
}
|
||||
//write total number of chars
|
||||
name_file_stream.write(
|
||||
(char *)&(total_number_of_chars),
|
||||
sizeof(unsigned)
|
||||
);
|
||||
//write prefixe sums
|
||||
unsigned name_lengths_prefix_sum = 0;
|
||||
BOOST_FOREACH(const std::string & temp_string, name_list) {
|
||||
name_file_stream.write(
|
||||
(char *)&(name_lengths_prefix_sum),
|
||||
sizeof(unsigned)
|
||||
);
|
||||
name_lengths_prefix_sum += temp_string.length();
|
||||
}
|
||||
//duplicate on purpose!
|
||||
name_file_stream.write(
|
||||
(char *)&(name_lengths_prefix_sum),
|
||||
sizeof(unsigned)
|
||||
);
|
||||
|
||||
//write all chars consecutively
|
||||
BOOST_FOREACH(const std::string & temp_string, name_list) {
|
||||
const unsigned string_length = temp_string.length();
|
||||
name_file_stream.write(temp_string.c_str(), string_length);
|
||||
}
|
||||
|
||||
name_file_stream.close();
|
||||
std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
|
||||
SimpleLogger().Write() << "Processed " <<
|
||||
number_of_used_nodes << " nodes and " <<
|
||||
number_of_used_edges << " edges";
|
||||
|
||||
} catch ( const std::exception& e ) {
|
||||
std::cerr << "Caught Execption:" << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTIONCONTAINERS_H_
|
||||
#define EXTRACTIONCONTAINERS_H_
|
||||
|
||||
#include "ExtractorStructs.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
#include "../Util/UUID.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
#include <stxxl/sort>
|
||||
#include <stxxl/vector>
|
||||
|
||||
class ExtractionContainers {
|
||||
public:
|
||||
typedef stxxl::vector<NodeID> STXXLNodeIDVector;
|
||||
typedef stxxl::vector<ExternalMemoryNode> STXXLNodeVector;
|
||||
typedef stxxl::vector<InternalExtractorEdge> STXXLEdgeVector;
|
||||
typedef stxxl::vector<std::string> STXXLStringVector;
|
||||
typedef stxxl::vector<InputRestrictionContainer> STXXLRestrictionsVector;
|
||||
typedef stxxl::vector<_WayIDStartAndEndEdge> STXXLWayIDStartEndVector;
|
||||
|
||||
STXXLNodeIDVector used_node_id_list;
|
||||
STXXLNodeVector all_nodes_list;
|
||||
STXXLEdgeVector all_edges_list;
|
||||
STXXLStringVector name_list;
|
||||
STXXLRestrictionsVector restrictions_list;
|
||||
STXXLWayIDStartEndVector way_start_end_id_list;
|
||||
const UUID uuid;
|
||||
|
||||
ExtractionContainers() {
|
||||
//Check if stxxl can be instantiated
|
||||
stxxl::vector<unsigned> dummy_vector;
|
||||
name_list.push_back("");
|
||||
}
|
||||
|
||||
virtual ~ExtractionContainers() {
|
||||
used_node_id_list.clear();
|
||||
all_nodes_list.clear();
|
||||
all_edges_list.clear();
|
||||
name_list.clear();
|
||||
restrictions_list.clear();
|
||||
way_start_end_id_list.clear();
|
||||
}
|
||||
|
||||
void PrepareData(
|
||||
const std::string & output_file_name,
|
||||
const std::string & restrictions_file_name
|
||||
);
|
||||
};
|
||||
|
||||
#endif /* EXTRACTIONCONTAINERS_H_ */
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTIONHELPERFUNCTIONS_H_
|
||||
#define EXTRACTIONHELPERFUNCTIONS_H_
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string_regex.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <climits>
|
||||
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
//TODO: Move into LUA
|
||||
|
||||
inline bool durationIsValid(const std::string &s) {
|
||||
boost::regex e ("((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",boost::regex_constants::icase|boost::regex_constants::perl);
|
||||
|
||||
std::vector< std::string > result;
|
||||
boost::algorithm::split_regex( result, s, boost::regex( ":" ) ) ;
|
||||
bool matched = regex_match(s, e);
|
||||
return matched;
|
||||
}
|
||||
|
||||
inline unsigned parseDuration(const std::string &s) {
|
||||
unsigned hours = 0;
|
||||
unsigned minutes = 0;
|
||||
unsigned seconds = 0;
|
||||
boost::regex e ("((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",boost::regex_constants::icase|boost::regex_constants::perl);
|
||||
|
||||
std::vector< std::string > result;
|
||||
boost::algorithm::split_regex( result, s, boost::regex( ":" ) ) ;
|
||||
bool matched = regex_match(s, e);
|
||||
if(matched) {
|
||||
if(1 == result.size()) {
|
||||
minutes = stringToInt(result[0]);
|
||||
}
|
||||
if(2 == result.size()) {
|
||||
minutes = stringToInt(result[1]);
|
||||
hours = stringToInt(result[0]);
|
||||
}
|
||||
if(3 == result.size()) {
|
||||
seconds = stringToInt(result[2]);
|
||||
minutes = stringToInt(result[1]);
|
||||
hours = stringToInt(result[0]);
|
||||
}
|
||||
return 10*(3600*hours+60*minutes+seconds);
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
inline int parseMaxspeed(std::string input) { //call-by-value on purpose.
|
||||
boost::algorithm::to_lower(input);
|
||||
int n = stringToInt(input);
|
||||
if (input.find("mph") != std::string::npos || input.find("mp/h") != std::string::npos) {
|
||||
n = (n*1609)/1000;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif /* EXTRACTIONHELPERFUNCTIONS_H_ */
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "ExtractorCallbacks.h"
|
||||
|
||||
ExtractorCallbacks::ExtractorCallbacks() {externalMemory = NULL; stringMap = NULL; }
|
||||
ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers * ext, StringMap * strMap) {
|
||||
externalMemory = ext;
|
||||
stringMap = strMap;
|
||||
}
|
||||
|
||||
ExtractorCallbacks::~ExtractorCallbacks() { }
|
||||
|
||||
/** warning: caller needs to take care of synchronization! */
|
||||
void ExtractorCallbacks::nodeFunction(const ExternalMemoryNode &n) {
|
||||
if(n.lat <= 85*COORDINATE_PRECISION && n.lat >= -85*COORDINATE_PRECISION) {
|
||||
externalMemory->all_nodes_list.push_back(n);
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtractorCallbacks::restrictionFunction(const InputRestrictionContainer &r) {
|
||||
externalMemory->restrictions_list.push_back(r);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** warning: caller needs to take care of synchronization! */
|
||||
void ExtractorCallbacks::wayFunction(ExtractionWay &parsed_way) {
|
||||
if((0 < parsed_way.speed) || (0 < parsed_way.duration)) { //Only true if the way is specified by the speed profile
|
||||
if(UINT_MAX == parsed_way.id){
|
||||
SimpleLogger().Write(logDEBUG) <<
|
||||
"found bogus way with id: " << parsed_way.id <<
|
||||
" of size " << parsed_way.path.size();
|
||||
return;
|
||||
}
|
||||
|
||||
if(0 < parsed_way.duration) {
|
||||
//TODO: iterate all way segments and set duration corresponding to the length of each segment
|
||||
parsed_way.speed = parsed_way.duration/(parsed_way.path.size()-1);
|
||||
}
|
||||
|
||||
if(std::numeric_limits<double>::epsilon() >= fabs(-1. - parsed_way.speed)){
|
||||
SimpleLogger().Write(logDEBUG) <<
|
||||
"found way with bogus speed, id: " << parsed_way.id;
|
||||
return;
|
||||
}
|
||||
|
||||
//Get the unique identifier for the street name
|
||||
const StringMap::const_iterator string_map_iterator = stringMap->find(parsed_way.name);
|
||||
if(stringMap->end() == string_map_iterator) {
|
||||
parsed_way.nameID = externalMemory->name_list.size();
|
||||
externalMemory->name_list.push_back(parsed_way.name);
|
||||
stringMap->insert(std::make_pair(parsed_way.name, parsed_way.nameID));
|
||||
} else {
|
||||
parsed_way.nameID = string_map_iterator->second;
|
||||
}
|
||||
|
||||
if(ExtractionWay::opposite == parsed_way.direction) {
|
||||
std::reverse( parsed_way.path.begin(), parsed_way.path.end() );
|
||||
parsed_way.direction = ExtractionWay::oneway;
|
||||
}
|
||||
|
||||
const bool split_bidirectional_edge = (parsed_way.backward_speed > 0) && (parsed_way.speed != parsed_way.backward_speed);
|
||||
|
||||
for(std::vector< NodeID >::size_type n = 0; n < parsed_way.path.size()-1; ++n) {
|
||||
externalMemory->all_edges_list.push_back(
|
||||
InternalExtractorEdge(parsed_way.path[n],
|
||||
parsed_way.path[n+1],
|
||||
parsed_way.type,
|
||||
(split_bidirectional_edge ? ExtractionWay::oneway : parsed_way.direction),
|
||||
parsed_way.speed,
|
||||
parsed_way.nameID,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.ignoreInGrid,
|
||||
(0 < parsed_way.duration),
|
||||
parsed_way.isAccessRestricted
|
||||
)
|
||||
);
|
||||
externalMemory->used_node_id_list.push_back(parsed_way.path[n]);
|
||||
}
|
||||
externalMemory->used_node_id_list.push_back(parsed_way.path.back());
|
||||
|
||||
//The following information is needed to identify start and end segments of restrictions
|
||||
externalMemory->way_start_end_id_list.push_back(_WayIDStartAndEndEdge(parsed_way.id, parsed_way.path[0], parsed_way.path[1], parsed_way.path[parsed_way.path.size()-2], parsed_way.path.back()));
|
||||
|
||||
if(split_bidirectional_edge) { //Only true if the way should be split
|
||||
std::reverse( parsed_way.path.begin(), parsed_way.path.end() );
|
||||
for(std::vector< NodeID >::size_type n = 0; n < parsed_way.path.size()-1; ++n) {
|
||||
externalMemory->all_edges_list.push_back(
|
||||
InternalExtractorEdge(parsed_way.path[n],
|
||||
parsed_way.path[n+1],
|
||||
parsed_way.type,
|
||||
ExtractionWay::oneway,
|
||||
parsed_way.backward_speed,
|
||||
parsed_way.nameID,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.ignoreInGrid,
|
||||
(0 < parsed_way.duration),
|
||||
parsed_way.isAccessRestricted,
|
||||
(ExtractionWay::oneway == parsed_way.direction)
|
||||
)
|
||||
);
|
||||
}
|
||||
externalMemory->way_start_end_id_list.push_back(_WayIDStartAndEndEdge(parsed_way.id, parsed_way.path[0], parsed_way.path[1], parsed_way.path[parsed_way.path.size()-2], parsed_way.path.back()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTORCALLBACKS_H_
|
||||
#define EXTRACTORCALLBACKS_H_
|
||||
|
||||
#include "ExtractionContainers.h"
|
||||
#include "ExtractionHelperFunctions.h"
|
||||
#include "ExtractorStructs.h"
|
||||
|
||||
#include "../DataStructures/Coordinate.h"
|
||||
|
||||
#include <cfloat>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/regex.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class ExtractorCallbacks{
|
||||
private:
|
||||
StringMap * stringMap;
|
||||
ExtractionContainers * externalMemory;
|
||||
|
||||
ExtractorCallbacks();
|
||||
public:
|
||||
explicit ExtractorCallbacks(ExtractionContainers * ext, StringMap * strMap);
|
||||
|
||||
~ExtractorCallbacks();
|
||||
|
||||
/** warning: caller needs to take care of synchronization! */
|
||||
void nodeFunction(const ExternalMemoryNode &n);
|
||||
|
||||
bool restrictionFunction(const InputRestrictionContainer &r);
|
||||
|
||||
/** warning: caller needs to take care of synchronization! */
|
||||
void wayFunction(ExtractionWay &w);
|
||||
|
||||
};
|
||||
|
||||
#endif /* EXTRACTORCALLBACKS_H_ */
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTORSTRUCTS_H_
|
||||
#define EXTRACTORSTRUCTS_H_
|
||||
|
||||
#include "../DataStructures/Coordinate.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../DataStructures/QueryNode.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/regex.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include <climits>
|
||||
#include <string>
|
||||
|
||||
typedef boost::unordered_map<std::string, NodeID > StringMap;
|
||||
typedef boost::unordered_map<std::string, std::pair<int, short> > StringToIntPairMap;
|
||||
|
||||
struct ExtractionWay {
|
||||
ExtractionWay() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
inline void Clear(){
|
||||
id = UINT_MAX;
|
||||
nameID = UINT_MAX;
|
||||
path.clear();
|
||||
keyVals.clear();
|
||||
direction = ExtractionWay::notSure;
|
||||
speed = -1;
|
||||
backward_speed = -1;
|
||||
duration = -1;
|
||||
type = -1;
|
||||
access = true;
|
||||
roundabout = false;
|
||||
isAccessRestricted = false;
|
||||
ignoreInGrid = false;
|
||||
}
|
||||
|
||||
enum Directions {
|
||||
notSure = 0, oneway, bidirectional, opposite
|
||||
};
|
||||
Directions direction;
|
||||
unsigned id;
|
||||
unsigned nameID;
|
||||
std::string name;
|
||||
double speed;
|
||||
double backward_speed;
|
||||
double duration;
|
||||
short type;
|
||||
bool access;
|
||||
bool roundabout;
|
||||
bool isAccessRestricted;
|
||||
bool ignoreInGrid;
|
||||
std::vector< NodeID > path;
|
||||
HashTable<std::string, std::string> keyVals;
|
||||
};
|
||||
|
||||
struct ExtractorRelation {
|
||||
ExtractorRelation() : type(unknown){}
|
||||
enum {
|
||||
unknown = 0, ferry, turnRestriction
|
||||
} type;
|
||||
HashTable<std::string, std::string> keyVals;
|
||||
};
|
||||
|
||||
struct InternalExtractorEdge {
|
||||
InternalExtractorEdge() : start(0), target(0), type(0), direction(0), speed(0), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false), isContraFlow(false) {};
|
||||
InternalExtractorEdge(NodeID s, NodeID t) : start(s), target(t), type(0), direction(0), speed(0), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false), isContraFlow(false) { }
|
||||
InternalExtractorEdge(NodeID s, NodeID t, short tp, short d, double sp): start(s), target(t), type(tp), direction(d), speed(sp), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false), isContraFlow(false) { }
|
||||
InternalExtractorEdge(NodeID s, NodeID t, short tp, short d, double sp, unsigned nid, bool isra, bool iing, bool ids, bool iar): start(s), target(t), type(tp), direction(d), speed(sp), nameID(nid), isRoundabout(isra), ignoreInGrid(iing), isDurationSet(ids), isAccessRestricted(iar), isContraFlow(false) {
|
||||
assert(0 <= type);
|
||||
}
|
||||
InternalExtractorEdge(NodeID s, NodeID t, short tp, short d, double sp, unsigned nid, bool isra, bool iing, bool ids, bool iar, bool icf): start(s), target(t), type(tp), direction(d), speed(sp), nameID(nid), isRoundabout(isra), ignoreInGrid(iing), isDurationSet(ids), isAccessRestricted(iar), isContraFlow(icf) {
|
||||
assert(0 <= type);
|
||||
}
|
||||
NodeID start;
|
||||
NodeID target;
|
||||
short type;
|
||||
short direction;
|
||||
double speed;
|
||||
unsigned nameID;
|
||||
bool isRoundabout;
|
||||
bool ignoreInGrid;
|
||||
bool isDurationSet;
|
||||
bool isAccessRestricted;
|
||||
bool isContraFlow;
|
||||
|
||||
FixedPointCoordinate startCoord;
|
||||
FixedPointCoordinate targetCoord;
|
||||
|
||||
static InternalExtractorEdge min_value() {
|
||||
return InternalExtractorEdge(0,0);
|
||||
}
|
||||
static InternalExtractorEdge max_value() {
|
||||
return InternalExtractorEdge((std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct _WayIDStartAndEndEdge {
|
||||
unsigned wayID;
|
||||
NodeID firstStart;
|
||||
NodeID firstTarget;
|
||||
NodeID lastStart;
|
||||
NodeID lastTarget;
|
||||
_WayIDStartAndEndEdge() : wayID(UINT_MAX), firstStart(UINT_MAX), firstTarget(UINT_MAX), lastStart(UINT_MAX), lastTarget(UINT_MAX) {}
|
||||
_WayIDStartAndEndEdge(unsigned w, NodeID fs, NodeID ft, NodeID ls, NodeID lt) : wayID(w), firstStart(fs), firstTarget(ft), lastStart(ls), lastTarget(lt) {}
|
||||
|
||||
static _WayIDStartAndEndEdge min_value() {
|
||||
return _WayIDStartAndEndEdge((std::numeric_limits<unsigned>::min)(), (std::numeric_limits<unsigned>::min)(), (std::numeric_limits<unsigned>::min)(), (std::numeric_limits<unsigned>::min)(), (std::numeric_limits<unsigned>::min)());
|
||||
}
|
||||
static _WayIDStartAndEndEdge max_value() {
|
||||
return _WayIDStartAndEndEdge((std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)());
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpWayByID : public std::binary_function<_WayIDStartAndEndEdge, _WayIDStartAndEndEdge, bool> {
|
||||
typedef _WayIDStartAndEndEdge value_type;
|
||||
bool operator () (const _WayIDStartAndEndEdge & a, const _WayIDStartAndEndEdge & b) const {
|
||||
return a.wayID < b.wayID;
|
||||
}
|
||||
value_type max_value() {
|
||||
return _WayIDStartAndEndEdge::max_value();
|
||||
}
|
||||
value_type min_value() {
|
||||
return _WayIDStartAndEndEdge::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct Cmp : public std::binary_function<NodeID, NodeID, bool> {
|
||||
typedef NodeID value_type;
|
||||
bool operator () (const NodeID a, const NodeID b) const {
|
||||
return a < b;
|
||||
}
|
||||
value_type max_value() {
|
||||
return 0xffffffff;
|
||||
}
|
||||
value_type min_value() {
|
||||
return 0x0;
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpNodeByID : public std::binary_function<ExternalMemoryNode, ExternalMemoryNode, bool> {
|
||||
typedef ExternalMemoryNode value_type;
|
||||
bool operator () (
|
||||
const ExternalMemoryNode & a,
|
||||
const ExternalMemoryNode & b
|
||||
) const {
|
||||
return a.id < b.id;
|
||||
}
|
||||
value_type max_value() {
|
||||
return ExternalMemoryNode::max_value();
|
||||
}
|
||||
value_type min_value() {
|
||||
return ExternalMemoryNode::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpEdgeByStartID : public std::binary_function<InternalExtractorEdge, InternalExtractorEdge, bool> {
|
||||
typedef InternalExtractorEdge value_type;
|
||||
bool operator () (const InternalExtractorEdge & a, const InternalExtractorEdge & b) const {
|
||||
return a.start < b.start;
|
||||
}
|
||||
value_type max_value() {
|
||||
return InternalExtractorEdge::max_value();
|
||||
}
|
||||
value_type min_value() {
|
||||
return InternalExtractorEdge::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpEdgeByTargetID : public std::binary_function<InternalExtractorEdge, InternalExtractorEdge, bool> {
|
||||
typedef InternalExtractorEdge value_type;
|
||||
bool operator () (const InternalExtractorEdge & a, const InternalExtractorEdge & b) const {
|
||||
return a.target < b.target;
|
||||
}
|
||||
value_type max_value() {
|
||||
return InternalExtractorEdge::max_value();
|
||||
}
|
||||
value_type min_value() {
|
||||
return InternalExtractorEdge::min_value();
|
||||
}
|
||||
};
|
||||
|
||||
inline std::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 std::string(s);
|
||||
}
|
||||
|
||||
#endif /* EXTRACTORSTRUCTS_H_ */
|
||||
@@ -0,0 +1,504 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "PBFParser.h"
|
||||
|
||||
PBFParser::PBFParser(const char * fileName, ExtractorCallbacks* ec, ScriptingEnvironment& se) : BaseParser( ec, se ) {
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
//TODO: What is the bottleneck here? Filling the queue or reading the stuff from disk?
|
||||
//NOTE: With Lua scripting, it is parsing the stuff. I/O is virtually for free.
|
||||
threadDataQueue = boost::make_shared<ConcurrentQueue<_ThreadData*> >( 2500 ); /* Max 2500 items in queue, hardcoded. */
|
||||
input.open(fileName, std::ios::in | std::ios::binary);
|
||||
|
||||
if (!input) {
|
||||
throw OSRMException("pbf file not found.");
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
blockCount = 0;
|
||||
groupCount = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
PBFParser::~PBFParser() {
|
||||
if(input.is_open()) {
|
||||
input.close();
|
||||
}
|
||||
|
||||
// Clean up any leftover ThreadData objects in the queue
|
||||
_ThreadData* td;
|
||||
while (threadDataQueue->try_pop(td)) {
|
||||
delete td;
|
||||
}
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
|
||||
#ifndef NDEBUG
|
||||
SimpleLogger().Write(logDEBUG) <<
|
||||
"parsed " << blockCount <<
|
||||
" blocks from pbf with " << groupCount <<
|
||||
" groups";
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool PBFParser::ReadHeader() {
|
||||
_ThreadData initData;
|
||||
/** read Header */
|
||||
if(!readPBFBlobHeader(input, &initData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(readBlob(input, &initData)) {
|
||||
if(!initData.PBFHeaderBlock.ParseFromArray(&(initData.charBuffer[0]), initData.charBuffer.size() ) ) {
|
||||
std::cerr << "[error] Header not parseable!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = 0, featureSize = initData.PBFHeaderBlock.required_features_size(); i < featureSize; ++i) {
|
||||
const std::string& feature = initData.PBFHeaderBlock.required_features( i );
|
||||
bool supported = false;
|
||||
if ( "OsmSchema-V0.6" == feature ) {
|
||||
supported = true;
|
||||
}
|
||||
else if ( "DenseNodes" == feature ) {
|
||||
supported = true;
|
||||
}
|
||||
|
||||
if ( !supported ) {
|
||||
std::cerr << "[error] required feature not supported: " << feature.data() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::cerr << "[error] blob not loaded!" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void PBFParser::ReadData() {
|
||||
bool keepRunning = true;
|
||||
do {
|
||||
_ThreadData *threadData = new _ThreadData();
|
||||
keepRunning = readNextBlock(input, threadData);
|
||||
|
||||
if (keepRunning) {
|
||||
threadDataQueue->push(threadData);
|
||||
} else {
|
||||
threadDataQueue->push(NULL); // No more data to read, parse stops when NULL encountered
|
||||
delete threadData;
|
||||
}
|
||||
} while(keepRunning);
|
||||
}
|
||||
|
||||
inline void PBFParser::ParseData() {
|
||||
while (true) {
|
||||
_ThreadData *threadData;
|
||||
threadDataQueue->wait_and_pop(threadData);
|
||||
if( NULL==threadData ) {
|
||||
SimpleLogger().Write() << "Parse Data Thread Finished";
|
||||
threadDataQueue->push(NULL); // Signal end of data for other threads
|
||||
break;
|
||||
}
|
||||
|
||||
loadBlock(threadData);
|
||||
|
||||
for(int i = 0, groupSize = threadData->PBFprimitiveBlock.primitivegroup_size(); i < groupSize; ++i) {
|
||||
threadData->currentGroupID = i;
|
||||
loadGroup(threadData);
|
||||
|
||||
if(threadData->entityTypeIndicator == TypeNode) {
|
||||
parseNode(threadData);
|
||||
}
|
||||
if(threadData->entityTypeIndicator == TypeWay) {
|
||||
parseWay(threadData);
|
||||
}
|
||||
if(threadData->entityTypeIndicator == TypeRelation) {
|
||||
parseRelation(threadData);
|
||||
}
|
||||
if(threadData->entityTypeIndicator == TypeDenseNode) {
|
||||
parseDenseNode(threadData);
|
||||
}
|
||||
}
|
||||
|
||||
delete threadData;
|
||||
threadData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool PBFParser::Parse() {
|
||||
// Start the read and parse threads
|
||||
boost::thread readThread(boost::bind(&PBFParser::ReadData, this));
|
||||
|
||||
//Open several parse threads that are synchronized before call to
|
||||
boost::thread parseThread(boost::bind(&PBFParser::ParseData, this));
|
||||
|
||||
// Wait for the threads to finish
|
||||
readThread.join();
|
||||
parseThread.join();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void PBFParser::parseDenseNode(_ThreadData * threadData) {
|
||||
const OSMPBF::DenseNodes& dense = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).dense();
|
||||
int denseTagIndex = 0;
|
||||
int64_t m_lastDenseID = 0;
|
||||
int64_t m_lastDenseLatitude = 0;
|
||||
int64_t m_lastDenseLongitude = 0;
|
||||
|
||||
const int number_of_nodes = dense.id_size();
|
||||
std::vector<ImportNode> extracted_nodes_vector(number_of_nodes);
|
||||
for(int i = 0; i < number_of_nodes; ++i) {
|
||||
m_lastDenseID += dense.id( i );
|
||||
m_lastDenseLatitude += dense.lat( i );
|
||||
m_lastDenseLongitude += dense.lon( i );
|
||||
extracted_nodes_vector[i].id = m_lastDenseID;
|
||||
extracted_nodes_vector[i].lat = COORDINATE_PRECISION*( ( double ) m_lastDenseLatitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lat_offset() ) / NANO;
|
||||
extracted_nodes_vector[i].lon = COORDINATE_PRECISION*( ( double ) m_lastDenseLongitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lon_offset() ) / NANO;
|
||||
while (denseTagIndex < dense.keys_vals_size()) {
|
||||
const int tagValue = dense.keys_vals( denseTagIndex );
|
||||
if( 0 == tagValue ) {
|
||||
++denseTagIndex;
|
||||
break;
|
||||
}
|
||||
const int keyValue = dense.keys_vals ( denseTagIndex+1 );
|
||||
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(tagValue);
|
||||
const std::string & value = threadData->PBFprimitiveBlock.stringtable().s(keyValue);
|
||||
extracted_nodes_vector[i].keyVals.emplace(key, value);
|
||||
denseTagIndex += 2;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for(int i = 0; i < number_of_nodes; ++i) {
|
||||
ImportNode &n = extracted_nodes_vector[i];
|
||||
ParseNodeInLua( n, scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()) );
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const ImportNode &n, extracted_nodes_vector) {
|
||||
extractor_callbacks->nodeFunction(n);
|
||||
}
|
||||
}
|
||||
|
||||
inline void PBFParser::parseNode(_ThreadData * ) {
|
||||
throw OSRMException(
|
||||
"Parsing of simple nodes not supported. PBF should use dense nodes"
|
||||
);
|
||||
}
|
||||
|
||||
inline void PBFParser::parseRelation(_ThreadData * threadData) {
|
||||
//TODO: leave early, if relation is not a restriction
|
||||
//TODO: reuse rawRestriction container
|
||||
if( !use_turn_restrictions ) {
|
||||
return;
|
||||
}
|
||||
const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID );
|
||||
|
||||
for(int i = 0, relation_size = group.relations_size(); i < relation_size; ++i ) {
|
||||
std::string except_tag_string;
|
||||
const OSMPBF::Relation& inputRelation = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).relations(i);
|
||||
bool isRestriction = false;
|
||||
bool isOnlyRestriction = false;
|
||||
for(int k = 0, endOfKeys = inputRelation.keys_size(); k < endOfKeys; ++k) {
|
||||
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.keys(k));
|
||||
const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.vals(k));
|
||||
if ("type" == key) {
|
||||
if( "restriction" == val) {
|
||||
isRestriction = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ("restriction" == key) {
|
||||
if(val.find("only_") == 0) {
|
||||
isOnlyRestriction = true;
|
||||
}
|
||||
}
|
||||
if ("except" == key) {
|
||||
except_tag_string = val;
|
||||
}
|
||||
}
|
||||
|
||||
if( isRestriction && ShouldIgnoreRestriction(except_tag_string) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isRestriction) {
|
||||
int64_t lastRef = 0;
|
||||
InputRestrictionContainer currentRestrictionContainer(isOnlyRestriction);
|
||||
for(
|
||||
int rolesIndex = 0, last_role = inputRelation.roles_sid_size();
|
||||
rolesIndex < last_role;
|
||||
++rolesIndex
|
||||
) {
|
||||
const std::string & role = threadData->PBFprimitiveBlock.stringtable().s( inputRelation.roles_sid( rolesIndex ) );
|
||||
lastRef += inputRelation.memids(rolesIndex);
|
||||
|
||||
if(!("from" == role || "to" == role || "via" == role)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(inputRelation.types(rolesIndex)) {
|
||||
case 0: //node
|
||||
if("from" == role || "to" == role) { //Only via should be a node
|
||||
continue;
|
||||
}
|
||||
assert("via" == role);
|
||||
if(UINT_MAX != currentRestrictionContainer.viaNode) {
|
||||
currentRestrictionContainer.viaNode = UINT_MAX;
|
||||
}
|
||||
assert(UINT_MAX == currentRestrictionContainer.viaNode);
|
||||
currentRestrictionContainer.restriction.viaNode = lastRef;
|
||||
break;
|
||||
case 1: //way
|
||||
assert("from" == role || "to" == role || "via" == role);
|
||||
if("from" == role) {
|
||||
currentRestrictionContainer.fromWay = lastRef;
|
||||
}
|
||||
if ("to" == role) {
|
||||
currentRestrictionContainer.toWay = lastRef;
|
||||
}
|
||||
if ("via" == role) {
|
||||
assert(currentRestrictionContainer.restriction.toNode == UINT_MAX);
|
||||
currentRestrictionContainer.viaNode = lastRef;
|
||||
}
|
||||
break;
|
||||
case 2: //relation, not used. relations relating to relations are evil.
|
||||
continue;
|
||||
assert(false);
|
||||
break;
|
||||
|
||||
default: //should not happen
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!extractor_callbacks->restrictionFunction(currentRestrictionContainer)) {
|
||||
std::cerr << "[PBFParser] relation not parsed" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void PBFParser::parseWay(_ThreadData * threadData) {
|
||||
const int number_of_ways = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size();
|
||||
std::vector<ExtractionWay> parsed_way_vector(number_of_ways);
|
||||
for(int i = 0; i < number_of_ways; ++i) {
|
||||
const OSMPBF::Way& inputWay = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways( i );
|
||||
parsed_way_vector[i].id = inputWay.id();
|
||||
unsigned pathNode(0);
|
||||
const int number_of_referenced_nodes = inputWay.refs_size();
|
||||
for(int j = 0; j < number_of_referenced_nodes; ++j) {
|
||||
pathNode += inputWay.refs(j);
|
||||
parsed_way_vector[i].path.push_back(pathNode);
|
||||
}
|
||||
assert(inputWay.keys_size() == inputWay.vals_size());
|
||||
const int number_of_keys = inputWay.keys_size();
|
||||
for(int j = 0; j < number_of_keys; ++j) {
|
||||
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputWay.keys(j));
|
||||
const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputWay.vals(j));
|
||||
parsed_way_vector[i].keyVals.emplace(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp parallel for schedule ( guided )
|
||||
for(int i = 0; i < number_of_ways; ++i) {
|
||||
ExtractionWay & w = parsed_way_vector[i];
|
||||
if(2 > w.path.size()) {
|
||||
continue;
|
||||
}
|
||||
ParseWayInLua( w, scriptingEnvironment.getLuaStateForThreadID( omp_get_thread_num()) );
|
||||
}
|
||||
|
||||
BOOST_FOREACH(ExtractionWay & w, parsed_way_vector) {
|
||||
if(2 > w.path.size()) {
|
||||
continue;
|
||||
}
|
||||
extractor_callbacks->wayFunction(w);
|
||||
}
|
||||
}
|
||||
|
||||
inline void PBFParser::loadGroup(_ThreadData * threadData) {
|
||||
#ifndef NDEBUG
|
||||
++groupCount;
|
||||
#endif
|
||||
|
||||
const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID );
|
||||
threadData->entityTypeIndicator = TypeDummy;
|
||||
if ( 0 != group.nodes_size() ) {
|
||||
threadData->entityTypeIndicator = TypeNode;
|
||||
}
|
||||
if ( 0 != group.ways_size() ) {
|
||||
threadData->entityTypeIndicator = TypeWay;
|
||||
}
|
||||
if ( 0 != group.relations_size() ) {
|
||||
threadData->entityTypeIndicator = TypeRelation;
|
||||
}
|
||||
if ( group.has_dense() ) {
|
||||
threadData->entityTypeIndicator = TypeDenseNode;
|
||||
assert( 0 != group.dense().id_size() );
|
||||
}
|
||||
assert( threadData->entityTypeIndicator != TypeDummy );
|
||||
}
|
||||
|
||||
inline void PBFParser::loadBlock(_ThreadData * threadData) {
|
||||
#ifndef NDEBUG
|
||||
++blockCount;
|
||||
#endif
|
||||
threadData->currentGroupID = 0;
|
||||
threadData->currentEntityID = 0;
|
||||
}
|
||||
|
||||
inline bool PBFParser::readPBFBlobHeader(std::fstream& stream, _ThreadData * threadData) {
|
||||
int size(0);
|
||||
stream.read((char *)&size, sizeof(int));
|
||||
size = swapEndian(size);
|
||||
if(stream.eof()) {
|
||||
return false;
|
||||
}
|
||||
if ( size > MAX_BLOB_HEADER_SIZE || size < 0 ) {
|
||||
return false;
|
||||
}
|
||||
char *data = new char[size];
|
||||
stream.read(data, size*sizeof(data[0]));
|
||||
|
||||
bool dataSuccessfullyParsed = (threadData->PBFBlobHeader).ParseFromArray( data, size);
|
||||
delete[] data;
|
||||
return dataSuccessfullyParsed;
|
||||
}
|
||||
|
||||
inline bool PBFParser::unpackZLIB(std::fstream &, _ThreadData * threadData) {
|
||||
unsigned rawSize = threadData->PBFBlob.raw_size();
|
||||
char* unpackedDataArray = new char[rawSize];
|
||||
z_stream compressedDataStream;
|
||||
compressedDataStream.next_in = ( unsigned char* ) threadData->PBFBlob.zlib_data().data();
|
||||
compressedDataStream.avail_in = threadData->PBFBlob.zlib_data().size();
|
||||
compressedDataStream.next_out = ( unsigned char* ) unpackedDataArray;
|
||||
compressedDataStream.avail_out = rawSize;
|
||||
compressedDataStream.zalloc = Z_NULL;
|
||||
compressedDataStream.zfree = Z_NULL;
|
||||
compressedDataStream.opaque = Z_NULL;
|
||||
int ret = inflateInit( &compressedDataStream );
|
||||
if ( ret != Z_OK ) {
|
||||
std::cerr << "[error] failed to init zlib stream" << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = inflate( &compressedDataStream, Z_FINISH );
|
||||
if ( ret != Z_STREAM_END ) {
|
||||
std::cerr << "[error] failed to inflate zlib stream" << std::endl;
|
||||
std::cerr << "[error] Error type: " << ret << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = inflateEnd( &compressedDataStream );
|
||||
if ( ret != Z_OK ) {
|
||||
std::cerr << "[error] failed to deinit zlib stream" << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
return false;
|
||||
}
|
||||
|
||||
threadData->charBuffer.clear(); threadData->charBuffer.resize(rawSize);
|
||||
std::copy(unpackedDataArray, unpackedDataArray + rawSize, threadData->charBuffer.begin());
|
||||
delete[] unpackedDataArray;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool PBFParser::unpackLZMA(std::fstream &, _ThreadData * ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool PBFParser::readBlob(std::fstream& stream, _ThreadData * threadData) {
|
||||
if(stream.eof()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int size = threadData->PBFBlobHeader.datasize();
|
||||
if ( size < 0 || size > MAX_BLOB_SIZE ) {
|
||||
std::cerr << "[error] invalid Blob size:" << size << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
char* data = new char[size];
|
||||
stream.read(data, sizeof(data[0])*size);
|
||||
|
||||
if ( !threadData->PBFBlob.ParseFromArray( data, size ) ) {
|
||||
std::cerr << "[error] failed to parse blob" << std::endl;
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( threadData->PBFBlob.has_raw() ) {
|
||||
const std::string& data = threadData->PBFBlob.raw();
|
||||
threadData->charBuffer.clear();
|
||||
threadData->charBuffer.resize( data.size() );
|
||||
std::copy(data.begin(), data.end(), threadData->charBuffer.begin());
|
||||
} else if ( threadData->PBFBlob.has_zlib_data() ) {
|
||||
if ( !unpackZLIB(stream, threadData) ) {
|
||||
std::cerr << "[error] zlib data encountered that could not be unpacked" << std::endl;
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
} else if ( threadData->PBFBlob.has_lzma_data() ) {
|
||||
if ( !unpackLZMA(stream, threadData) ) {
|
||||
std::cerr << "[error] lzma data encountered that could not be unpacked" << std::endl;
|
||||
}
|
||||
delete[] data;
|
||||
return false;
|
||||
} else {
|
||||
std::cerr << "[error] Blob contains no data" << std::endl;
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
delete[] data;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PBFParser::readNextBlock(std::fstream& stream, _ThreadData * threadData) {
|
||||
if(stream.eof()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !readPBFBlobHeader(stream, threadData) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( threadData->PBFBlobHeader.type() != "OSMData" ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !readBlob(stream, threadData) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !threadData->PBFprimitiveBlock.ParseFromArray( &(threadData->charBuffer[0]), threadData-> charBuffer.size() ) ) {
|
||||
std::cerr << "failed to parse PrimitiveBlock" << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PBFPARSER_H_
|
||||
#define PBFPARSER_H_
|
||||
|
||||
#include "BaseParser.h"
|
||||
|
||||
#include "../DataStructures/Coordinate.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/ConcurrentQueue.h"
|
||||
#include "../Util/MachineInfo.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
|
||||
#include <osmpbf/fileformat.pb.h>
|
||||
#include <osmpbf/osmformat.pb.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
class PBFParser : public BaseParser {
|
||||
|
||||
enum EntityType {
|
||||
TypeDummy = 0,
|
||||
TypeNode = 1,
|
||||
TypeWay = 2,
|
||||
TypeRelation = 4,
|
||||
TypeDenseNode = 8
|
||||
};
|
||||
|
||||
struct _ThreadData {
|
||||
int currentGroupID;
|
||||
int currentEntityID;
|
||||
EntityType entityTypeIndicator;
|
||||
|
||||
OSMPBF::BlobHeader PBFBlobHeader;
|
||||
OSMPBF::Blob PBFBlob;
|
||||
|
||||
OSMPBF::HeaderBlock PBFHeaderBlock;
|
||||
OSMPBF::PrimitiveBlock PBFprimitiveBlock;
|
||||
|
||||
std::vector<char> charBuffer;
|
||||
};
|
||||
|
||||
public:
|
||||
PBFParser(const char * fileName, ExtractorCallbacks* ec, ScriptingEnvironment& se);
|
||||
virtual ~PBFParser();
|
||||
|
||||
inline bool ReadHeader();
|
||||
inline bool Parse();
|
||||
|
||||
private:
|
||||
inline void ReadData();
|
||||
inline void ParseData();
|
||||
inline void parseDenseNode (_ThreadData * threadData);
|
||||
inline void parseNode (_ThreadData * threadData);
|
||||
inline void parseRelation (_ThreadData * threadData);
|
||||
inline void parseWay (_ThreadData * threadData);
|
||||
|
||||
inline void loadGroup (_ThreadData * threadData);
|
||||
inline void loadBlock (_ThreadData * threadData);
|
||||
inline bool readPBFBlobHeader(std::fstream & stream, _ThreadData * threadData);
|
||||
inline bool unpackZLIB (std::fstream & stream, _ThreadData * threadData);
|
||||
inline bool unpackLZMA (std::fstream & stream, _ThreadData * threadData);
|
||||
inline bool readBlob (std::fstream & stream, _ThreadData * threadData);
|
||||
inline bool readNextBlock (std::fstream & stream, _ThreadData * threadData);
|
||||
|
||||
static const int NANO = 1000 * 1000 * 1000;
|
||||
static const int MAX_BLOB_HEADER_SIZE = 64 * 1024;
|
||||
static const int MAX_BLOB_SIZE = 32 * 1024 * 1024;
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* counting the number of read blocks and groups */
|
||||
unsigned groupCount;
|
||||
unsigned blockCount;
|
||||
#endif
|
||||
|
||||
std::fstream input; // the input stream to parse
|
||||
boost::shared_ptr<ConcurrentQueue < _ThreadData* > > threadDataQueue;
|
||||
};
|
||||
|
||||
#endif /* PBFPARSER_H_ */
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "ScriptingEnvironment.h"
|
||||
|
||||
ScriptingEnvironment::ScriptingEnvironment() {}
|
||||
ScriptingEnvironment::ScriptingEnvironment(const char * fileName) {
|
||||
SimpleLogger().Write() << "Using script " << fileName;
|
||||
|
||||
// Create a new lua state
|
||||
for(int i = 0; i < omp_get_max_threads(); ++i) {
|
||||
luaStateVector.push_back(luaL_newstate());
|
||||
}
|
||||
|
||||
// Connect LuaBind to this lua state for all threads
|
||||
#pragma omp parallel
|
||||
{
|
||||
lua_State * myLuaState = getLuaStateForThreadID(omp_get_thread_num());
|
||||
luabind::open(myLuaState);
|
||||
//open utility libraries string library;
|
||||
luaL_openlibs(myLuaState);
|
||||
|
||||
luaAddScriptFolderToLoadPath( myLuaState, fileName );
|
||||
|
||||
// Add our function to the state's global scope
|
||||
luabind::module(myLuaState) [
|
||||
luabind::def("print", LUA_print<std::string>),
|
||||
luabind::def("parseMaxspeed", parseMaxspeed),
|
||||
luabind::def("durationIsValid", durationIsValid),
|
||||
luabind::def("parseDuration", parseDuration)
|
||||
];
|
||||
|
||||
luabind::module(myLuaState) [
|
||||
luabind::class_<HashTable<std::string, std::string> >("keyVals")
|
||||
.def("Add", &HashTable<std::string, std::string>::Add)
|
||||
.def("Find", &HashTable<std::string, std::string>::Find)
|
||||
.def("Holds", &HashTable<std::string, std::string>::Holds)
|
||||
];
|
||||
|
||||
luabind::module(myLuaState) [
|
||||
luabind::class_<ImportNode>("Node")
|
||||
.def(luabind::constructor<>())
|
||||
.def_readwrite("lat", &ImportNode::lat)
|
||||
.def_readwrite("lon", &ImportNode::lon)
|
||||
.def_readonly("id", &ImportNode::id)
|
||||
.def_readwrite("bollard", &ImportNode::bollard)
|
||||
.def_readwrite("traffic_light", &ImportNode::trafficLight)
|
||||
.def_readwrite("tags", &ImportNode::keyVals)
|
||||
];
|
||||
|
||||
luabind::module(myLuaState) [
|
||||
luabind::class_<ExtractionWay>("Way")
|
||||
.def(luabind::constructor<>())
|
||||
.def_readonly("id", &ExtractionWay::id)
|
||||
.def_readwrite("name", &ExtractionWay::name)
|
||||
.def_readwrite("speed", &ExtractionWay::speed)
|
||||
.def_readwrite("backward_speed", &ExtractionWay::backward_speed)
|
||||
.def_readwrite("duration", &ExtractionWay::duration)
|
||||
.def_readwrite("type", &ExtractionWay::type)
|
||||
.def_readwrite("access", &ExtractionWay::access)
|
||||
.def_readwrite("roundabout", &ExtractionWay::roundabout)
|
||||
.def_readwrite("is_access_restricted", &ExtractionWay::isAccessRestricted)
|
||||
.def_readwrite("ignore_in_grid", &ExtractionWay::ignoreInGrid)
|
||||
.def_readwrite("tags", &ExtractionWay::keyVals)
|
||||
.def_readwrite("direction", &ExtractionWay::direction)
|
||||
.enum_("constants") [
|
||||
luabind::value("notSure", 0),
|
||||
luabind::value("oneway", 1),
|
||||
luabind::value("bidirectional", 2),
|
||||
luabind::value("opposite", 3)
|
||||
]
|
||||
];
|
||||
|
||||
// fails on c++11/OS X 10.9
|
||||
luabind::module(myLuaState) [
|
||||
luabind::class_<std::vector<std::string> >("vector")
|
||||
.def("Add", static_cast<void (std::vector<std::string>::*)(const std::string&)>(&std::vector<std::string>::push_back)
|
||||
)
|
||||
];
|
||||
|
||||
if(0 != luaL_dofile(myLuaState, fileName) ) {
|
||||
throw OSRMException("ERROR occured in scripting block");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScriptingEnvironment::~ScriptingEnvironment() {
|
||||
for(unsigned i = 0; i < luaStateVector.size(); ++i) {
|
||||
// luaStateVector[i];
|
||||
}
|
||||
}
|
||||
|
||||
lua_State * ScriptingEnvironment::getLuaStateForThreadID(const int id) {
|
||||
return luaStateVector[id];
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SCRIPTINGENVIRONMENT_H_
|
||||
#define SCRIPTINGENVIRONMENT_H_
|
||||
|
||||
#include "ExtractionHelperFunctions.h"
|
||||
#include "ExtractorStructs.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../Util/LuaUtil.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class ScriptingEnvironment {
|
||||
public:
|
||||
ScriptingEnvironment();
|
||||
ScriptingEnvironment(const char * fileName);
|
||||
virtual ~ScriptingEnvironment();
|
||||
|
||||
lua_State * getLuaStateForThreadID(const int);
|
||||
|
||||
std::vector<lua_State *> luaStateVector;
|
||||
};
|
||||
|
||||
#endif /* SCRIPTINGENVIRONMENT_H_ */
|
||||
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "XMLParser.h"
|
||||
|
||||
#include "ExtractorStructs.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../DataStructures/InputReaderFactory.h"
|
||||
|
||||
#include <boost/ref.hpp>
|
||||
|
||||
XMLParser::XMLParser(const char * filename, ExtractorCallbacks* ec, ScriptingEnvironment& se) : BaseParser(ec, se) {
|
||||
SimpleLogger().Write(logWARNING) <<
|
||||
"Parsing plain .osm/.osm.bz2 is deprecated. Switch to .pbf";
|
||||
|
||||
inputReader = inputReaderFactory(filename);
|
||||
}
|
||||
|
||||
bool XMLParser::ReadHeader() {
|
||||
return (xmlTextReaderRead( inputReader ) == 1);
|
||||
}
|
||||
bool XMLParser::Parse() {
|
||||
while ( xmlTextReaderRead( inputReader ) == 1 ) {
|
||||
const int type = xmlTextReaderNodeType( inputReader );
|
||||
|
||||
//1 is Element
|
||||
if ( type != 1 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
xmlChar* currentName = xmlTextReaderName( inputReader );
|
||||
if ( currentName == NULL ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( xmlStrEqual( currentName, ( const xmlChar* ) "node" ) == 1 ) {
|
||||
ImportNode n = _ReadXMLNode();
|
||||
ParseNodeInLua( n, luaState );
|
||||
extractor_callbacks->nodeFunction(n);
|
||||
// if(!extractor_callbacks->nodeFunction(n))
|
||||
// std::cerr << "[XMLParser] dense node not parsed" << std::endl;
|
||||
}
|
||||
|
||||
if ( xmlStrEqual( currentName, ( const xmlChar* ) "way" ) == 1 ) {
|
||||
ExtractionWay way = _ReadXMLWay( );
|
||||
ParseWayInLua( way, luaState );
|
||||
extractor_callbacks->wayFunction(way);
|
||||
// if(!extractor_callbacks->wayFunction(way))
|
||||
// std::cerr << "[PBFParser] way not parsed" << std::endl;
|
||||
}
|
||||
if( use_turn_restrictions ) {
|
||||
if ( xmlStrEqual( currentName, ( const xmlChar* ) "relation" ) == 1 ) {
|
||||
InputRestrictionContainer r = _ReadXMLRestriction();
|
||||
if(r.fromWay != UINT_MAX) {
|
||||
if(!extractor_callbacks->restrictionFunction(r)) {
|
||||
std::cerr << "[XMLParser] restriction not parsed" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlFree( currentName );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
InputRestrictionContainer XMLParser::_ReadXMLRestriction() {
|
||||
InputRestrictionContainer restriction;
|
||||
std::string except_tag_string;
|
||||
|
||||
if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) {
|
||||
const int depth = xmlTextReaderDepth( inputReader );while ( xmlTextReaderRead( inputReader ) == 1 ) {
|
||||
const int childType = xmlTextReaderNodeType( inputReader );
|
||||
if ( childType != 1 && childType != 15 ) {
|
||||
continue;
|
||||
}
|
||||
const int childDepth = xmlTextReaderDepth( inputReader );
|
||||
xmlChar* childName = xmlTextReaderName( inputReader );
|
||||
if ( childName == NULL ) {
|
||||
continue;
|
||||
}
|
||||
if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "relation" ) == 1 ) {
|
||||
xmlFree( childName );
|
||||
break;
|
||||
}
|
||||
if ( childType != 1 ) {
|
||||
xmlFree( childName );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) {
|
||||
xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" );
|
||||
xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" );
|
||||
if ( k != NULL && value != NULL ) {
|
||||
if(xmlStrEqual(k, ( const xmlChar* ) "restriction" )){
|
||||
if(0 == std::string((const char *) value).find("only_")) {
|
||||
restriction.restriction.flags.isOnly = true;
|
||||
}
|
||||
}
|
||||
if ( xmlStrEqual(k, (const xmlChar *) "except") ) {
|
||||
except_tag_string = (const char*) value;
|
||||
}
|
||||
}
|
||||
|
||||
if ( k != NULL ) {
|
||||
xmlFree( k );
|
||||
}
|
||||
if ( value != NULL ) {
|
||||
xmlFree( value );
|
||||
}
|
||||
} else if ( xmlStrEqual( childName, ( const xmlChar* ) "member" ) == 1 ) {
|
||||
xmlChar* ref = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "ref" );
|
||||
if ( ref != NULL ) {
|
||||
xmlChar * role = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "role" );
|
||||
xmlChar * type = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "type" );
|
||||
|
||||
if(xmlStrEqual(role, (const xmlChar *) "to") && xmlStrEqual(type, (const xmlChar *) "way")) {
|
||||
restriction.toWay = stringToUint((const char*) ref);
|
||||
}
|
||||
if(xmlStrEqual(role, (const xmlChar *) "from") && xmlStrEqual(type, (const xmlChar *) "way")) {
|
||||
restriction.fromWay = stringToUint((const char*) ref);
|
||||
}
|
||||
if(xmlStrEqual(role, (const xmlChar *) "via") && xmlStrEqual(type, (const xmlChar *) "node")) {
|
||||
restriction.restriction.viaNode = stringToUint((const char*) ref);
|
||||
}
|
||||
|
||||
if(NULL != type) {
|
||||
xmlFree( type );
|
||||
}
|
||||
if(NULL != role) {
|
||||
xmlFree( role );
|
||||
}
|
||||
if(NULL != ref) {
|
||||
xmlFree( ref );
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlFree( childName );
|
||||
}
|
||||
}
|
||||
|
||||
if( ShouldIgnoreRestriction(except_tag_string) ) {
|
||||
restriction.fromWay = UINT_MAX; //workaround to ignore the restriction
|
||||
}
|
||||
return restriction;
|
||||
}
|
||||
|
||||
ExtractionWay XMLParser::_ReadXMLWay() {
|
||||
ExtractionWay way;
|
||||
if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) {
|
||||
const int depth = xmlTextReaderDepth( inputReader );
|
||||
while ( xmlTextReaderRead( inputReader ) == 1 ) {
|
||||
const int childType = xmlTextReaderNodeType( inputReader );
|
||||
if ( childType != 1 && childType != 15 ) {
|
||||
continue;
|
||||
}
|
||||
const int childDepth = xmlTextReaderDepth( inputReader );
|
||||
xmlChar* childName = xmlTextReaderName( inputReader );
|
||||
if ( childName == NULL ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "way" ) == 1 ) {
|
||||
xmlChar* id = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "id" );
|
||||
way.id = stringToUint((char*)id);
|
||||
xmlFree(id);
|
||||
xmlFree( childName );
|
||||
break;
|
||||
}
|
||||
if ( childType != 1 ) {
|
||||
xmlFree( childName );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) {
|
||||
xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" );
|
||||
xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" );
|
||||
// cout << "->k=" << k << ", v=" << value << endl;
|
||||
if ( k != NULL && value != NULL ) {
|
||||
way.keyVals.Add(std::string( (char *) k ), std::string( (char *) value));
|
||||
}
|
||||
if ( k != NULL ) {
|
||||
xmlFree( k );
|
||||
}
|
||||
if ( value != NULL ) {
|
||||
xmlFree( value );
|
||||
}
|
||||
} else if ( xmlStrEqual( childName, ( const xmlChar* ) "nd" ) == 1 ) {
|
||||
xmlChar* ref = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "ref" );
|
||||
if ( ref != NULL ) {
|
||||
way.path.push_back( stringToUint(( const char* ) ref ) );
|
||||
xmlFree( ref );
|
||||
}
|
||||
}
|
||||
xmlFree( childName );
|
||||
}
|
||||
}
|
||||
return way;
|
||||
}
|
||||
|
||||
ImportNode XMLParser::_ReadXMLNode() {
|
||||
ImportNode node;
|
||||
|
||||
xmlChar* attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lat" );
|
||||
if ( attribute != NULL ) {
|
||||
node.lat = static_cast<NodeID>(COORDINATE_PRECISION*atof(( const char* ) attribute ) );
|
||||
xmlFree( attribute );
|
||||
}
|
||||
attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lon" );
|
||||
if ( attribute != NULL ) {
|
||||
node.lon = static_cast<NodeID>(COORDINATE_PRECISION*atof(( const char* ) attribute ));
|
||||
xmlFree( attribute );
|
||||
}
|
||||
attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "id" );
|
||||
if ( attribute != NULL ) {
|
||||
node.id = stringToUint(( const char* ) attribute );
|
||||
xmlFree( attribute );
|
||||
}
|
||||
|
||||
if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) {
|
||||
const int depth = xmlTextReaderDepth( inputReader );
|
||||
while ( xmlTextReaderRead( inputReader ) == 1 ) {
|
||||
const int childType = xmlTextReaderNodeType( inputReader );
|
||||
// 1 = Element, 15 = EndElement
|
||||
if ( childType != 1 && childType != 15 ) {
|
||||
continue;
|
||||
}
|
||||
const int childDepth = xmlTextReaderDepth( inputReader );
|
||||
xmlChar* childName = xmlTextReaderName( inputReader );
|
||||
if ( childName == NULL ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "node" ) == 1 ) {
|
||||
xmlFree( childName );
|
||||
break;
|
||||
}
|
||||
if ( childType != 1 ) {
|
||||
xmlFree( childName );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) {
|
||||
xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" );
|
||||
xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" );
|
||||
if ( k != NULL && value != NULL ) {
|
||||
node.keyVals.Add(std::string( reinterpret_cast<char*>(k) ), std::string( reinterpret_cast<char*>(value)));
|
||||
}
|
||||
if ( k != NULL ) {
|
||||
xmlFree( k );
|
||||
}
|
||||
if ( value != NULL ) {
|
||||
xmlFree( value );
|
||||
}
|
||||
}
|
||||
|
||||
xmlFree( childName );
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef XMLPARSER_H_
|
||||
#define XMLPARSER_H_
|
||||
|
||||
#include "BaseParser.h"
|
||||
#include "../DataStructures/Coordinate.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <libxml/xmlreader.h>
|
||||
|
||||
|
||||
class XMLParser : public BaseParser {
|
||||
public:
|
||||
XMLParser(const char* filename, ExtractorCallbacks* ec, ScriptingEnvironment& se);
|
||||
bool ReadHeader();
|
||||
bool Parse();
|
||||
|
||||
private:
|
||||
InputRestrictionContainer _ReadXMLRestriction();
|
||||
ExtractionWay _ReadXMLWay();
|
||||
ImportNode _ReadXMLNode();
|
||||
xmlTextReaderPtr inputReader;
|
||||
};
|
||||
|
||||
#endif /* XMLPARSER_H_ */
|
||||
@@ -0,0 +1,7 @@
|
||||
source "http://rubygems.org"
|
||||
|
||||
gem "cucumber"
|
||||
gem "rake"
|
||||
gem "osmlib-base"
|
||||
gem "sys-proctable"
|
||||
gem "rspec-expectations"
|
||||
@@ -0,0 +1,30 @@
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
builder (3.2.2)
|
||||
cucumber (1.3.8)
|
||||
builder (>= 2.1.2)
|
||||
diff-lcs (>= 1.1.3)
|
||||
gherkin (~> 2.12.1)
|
||||
multi_json (>= 1.7.5, < 2.0)
|
||||
multi_test (>= 0.0.2)
|
||||
diff-lcs (1.2.4)
|
||||
gherkin (2.12.1)
|
||||
multi_json (~> 1.3)
|
||||
multi_json (1.8.0)
|
||||
multi_test (0.0.2)
|
||||
osmlib-base (0.1.4)
|
||||
rake (10.1.0)
|
||||
rspec-expectations (2.14.3)
|
||||
diff-lcs (>= 1.1.3, < 2.0)
|
||||
sys-proctable (0.9.3)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
cucumber
|
||||
osmlib-base
|
||||
rake
|
||||
rspec-expectations
|
||||
sys-proctable
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "OSRM.h"
|
||||
|
||||
OSRM::OSRM( const ServerPaths & server_paths, const bool use_shared_memory )
|
||||
:
|
||||
use_shared_memory(use_shared_memory)
|
||||
{
|
||||
if( !use_shared_memory ) {
|
||||
query_data_facade = new InternalDataFacade<QueryEdge::EdgeData>(
|
||||
server_paths
|
||||
);
|
||||
} else {
|
||||
query_data_facade = new SharedDataFacade<QueryEdge::EdgeData>( );
|
||||
}
|
||||
|
||||
//The following plugins handle all requests.
|
||||
RegisterPlugin(
|
||||
new HelloWorldPlugin()
|
||||
);
|
||||
RegisterPlugin(
|
||||
new LocatePlugin<BaseDataFacade<QueryEdge::EdgeData> >(
|
||||
query_data_facade
|
||||
)
|
||||
);
|
||||
RegisterPlugin(
|
||||
new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData> >(
|
||||
query_data_facade
|
||||
)
|
||||
);
|
||||
RegisterPlugin(
|
||||
new TimestampPlugin<BaseDataFacade<QueryEdge::EdgeData> >(
|
||||
query_data_facade
|
||||
)
|
||||
);
|
||||
RegisterPlugin(
|
||||
new ViaRoutePlugin<BaseDataFacade<QueryEdge::EdgeData> >(
|
||||
query_data_facade
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
OSRM::~OSRM() {
|
||||
BOOST_FOREACH(PluginMap::value_type & plugin_pointer, plugin_map) {
|
||||
delete plugin_pointer.second;
|
||||
}
|
||||
}
|
||||
|
||||
void OSRM::RegisterPlugin(BasePlugin * plugin) {
|
||||
SimpleLogger().Write() << "loaded plugin: " << plugin->GetDescriptor();
|
||||
if( plugin_map.find(plugin->GetDescriptor()) != plugin_map.end() ) {
|
||||
delete plugin_map.find(plugin->GetDescriptor())->second;
|
||||
}
|
||||
plugin_map.emplace(plugin->GetDescriptor(), plugin);
|
||||
}
|
||||
|
||||
void OSRM::RunQuery(RouteParameters & route_parameters, http::Reply & reply) {
|
||||
const PluginMap::const_iterator & iter = plugin_map.find(
|
||||
route_parameters.service
|
||||
);
|
||||
|
||||
if(plugin_map.end() != iter) {
|
||||
reply.status = http::Reply::ok;
|
||||
if( use_shared_memory ) {
|
||||
// lock update pending
|
||||
boost::interprocess::scoped_lock<
|
||||
boost::interprocess::named_mutex
|
||||
> pending_lock(barrier.pending_update_mutex);
|
||||
|
||||
// lock query
|
||||
boost::interprocess::scoped_lock<
|
||||
boost::interprocess::named_mutex
|
||||
> query_lock(barrier.query_mutex);
|
||||
|
||||
// unlock update pending
|
||||
pending_lock.unlock();
|
||||
|
||||
// increment query count
|
||||
++(barrier.number_of_queries);
|
||||
|
||||
(static_cast<SharedDataFacade<QueryEdge::EdgeData>* >(query_data_facade))->CheckAndReloadFacade();
|
||||
}
|
||||
|
||||
iter->second->HandleRequest(route_parameters, reply );
|
||||
if( use_shared_memory ) {
|
||||
// lock query
|
||||
boost::interprocess::scoped_lock<
|
||||
boost::interprocess::named_mutex
|
||||
> query_lock(barrier.query_mutex);
|
||||
|
||||
// decrement query count
|
||||
--(barrier.number_of_queries);
|
||||
BOOST_ASSERT_MSG(
|
||||
0 <= barrier.number_of_queries,
|
||||
"invalid number of queries"
|
||||
);
|
||||
|
||||
// notify all processes that were waiting for this condition
|
||||
if (0 == barrier.number_of_queries) {
|
||||
barrier.no_running_queries_condition.notify_all();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OSRM_H
|
||||
#define OSRM_H
|
||||
|
||||
#include "OSRM.h"
|
||||
|
||||
#include "../Plugins/BasePlugin.h"
|
||||
#include "../Plugins/HelloWorldPlugin.h"
|
||||
#include "../Plugins/LocatePlugin.h"
|
||||
#include "../Plugins/NearestPlugin.h"
|
||||
#include "../Plugins/TimestampPlugin.h"
|
||||
#include "../Plugins/ViaRoutePlugin.h"
|
||||
#include "../Server/DataStructures/BaseDataFacade.h"
|
||||
#include "../Server/DataStructures/InternalDataFacade.h"
|
||||
#include "../Server/DataStructures/SharedBarriers.h"
|
||||
#include "../Server/DataStructures/SharedDataFacade.h"
|
||||
#include "../Server/DataStructures/RouteParameters.h"
|
||||
#include "../Util/InputFileUtil.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/interprocess/shared_memory_object.hpp>
|
||||
#include <boost/interprocess/mapped_region.hpp>
|
||||
#include <boost/interprocess/sync/scoped_lock.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class OSRM : boost::noncopyable {
|
||||
private:
|
||||
typedef boost::unordered_map<std::string, BasePlugin *> PluginMap;
|
||||
public:
|
||||
OSRM(
|
||||
const ServerPaths & paths,
|
||||
const bool use_shared_memory = false
|
||||
);
|
||||
~OSRM();
|
||||
void RunQuery(RouteParameters & route_parameters, http::Reply & reply);
|
||||
|
||||
private:
|
||||
void RegisterPlugin(BasePlugin * plugin);
|
||||
PluginMap plugin_map;
|
||||
bool use_shared_memory;
|
||||
SharedBarriers barrier;
|
||||
//base class pointer to the objects
|
||||
BaseDataFacade<QueryEdge::EdgeData> * query_data_facade;
|
||||
};
|
||||
|
||||
#endif //OSRM_H
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BASEPLUGIN_H_
|
||||
#define BASEPLUGIN_H_
|
||||
|
||||
#include "../DataStructures/Coordinate.h"
|
||||
#include "../Server/DataStructures/RouteParameters.h"
|
||||
#include "../Server/Http/Reply.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class BasePlugin {
|
||||
public:
|
||||
BasePlugin() { }
|
||||
//Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BasePlugin() { }
|
||||
virtual const std::string & GetDescriptor() const = 0;
|
||||
virtual void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) = 0;
|
||||
|
||||
inline bool checkCoord(const FixedPointCoordinate & c) {
|
||||
if(
|
||||
c.lat > 90*COORDINATE_PRECISION ||
|
||||
c.lat < -90*COORDINATE_PRECISION ||
|
||||
c.lon > 180*COORDINATE_PRECISION ||
|
||||
c.lon < -180*COORDINATE_PRECISION
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* BASEPLUGIN_H_ */
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HELLOWORLDPLUGIN_H_
|
||||
#define HELLOWORLDPLUGIN_H_
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class HelloWorldPlugin : public BasePlugin {
|
||||
private:
|
||||
std::string temp_string;
|
||||
public:
|
||||
HelloWorldPlugin() : descriptor_string("hello"){}
|
||||
virtual ~HelloWorldPlugin() { }
|
||||
const std::string & GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.push_back("<html><head><title>Hello World Demonstration Document</title></head><body><h1>Hello, World!</h1>");
|
||||
reply.content.push_back("<pre>");
|
||||
reply.content.push_back("zoom level: ");
|
||||
intToString(routeParameters.zoomLevel, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("\nchecksum: ");
|
||||
intToString(routeParameters.checkSum, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("\ninstructions: ");
|
||||
reply.content.push_back((routeParameters.printInstructions ? "yes" : "no"));
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("\ngeometry: ");
|
||||
reply.content.push_back((routeParameters.geometry ? "yes" : "no"));
|
||||
reply.content.push_back("\ncompression: ");
|
||||
reply.content.push_back((routeParameters.compression ? "yes" : "no"));
|
||||
reply.content.push_back("\noutput format: ");
|
||||
reply.content.push_back(routeParameters.outputFormat);
|
||||
reply.content.push_back("\njson parameter: ");
|
||||
reply.content.push_back(routeParameters.jsonpParameter);
|
||||
reply.content.push_back("\nlanguage: ");
|
||||
reply.content.push_back(routeParameters.language);
|
||||
reply.content.push_back("\nNumber of locations: ");
|
||||
intToString(routeParameters.coordinates.size(), temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("\n");
|
||||
for(unsigned i = 0; i < routeParameters.coordinates.size(); ++i) {
|
||||
reply.content.push_back( " [");
|
||||
intToString(i, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("] ");
|
||||
doubleToString(routeParameters.coordinates[i].lat/COORDINATE_PRECISION, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back(",");
|
||||
doubleToString(routeParameters.coordinates[i].lon/COORDINATE_PRECISION, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("\n");
|
||||
}
|
||||
reply.content.push_back( "Number of hints: ");
|
||||
intToString(routeParameters.hints.size(), temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("\n");
|
||||
for(unsigned i = 0; i < routeParameters.hints.size(); ++i) {
|
||||
reply.content.push_back( " [");
|
||||
intToString(i, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
reply.content.push_back("] ");
|
||||
reply.content.push_back(routeParameters.hints[i]);
|
||||
reply.content.push_back("\n");
|
||||
}
|
||||
reply.content.push_back( "</pre></body></html>");
|
||||
}
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* HELLOWORLDPLUGIN_H_ */
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef LOCATEPLUGIN_H_
|
||||
#define LOCATEPLUGIN_H_
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
//locates the nearest node in the road network for a given coordinate.
|
||||
|
||||
template<class DataFacadeT>
|
||||
class LocatePlugin : public BasePlugin {
|
||||
public:
|
||||
LocatePlugin(DataFacadeT * facade)
|
||||
:
|
||||
descriptor_string("locate"),
|
||||
facade(facade)
|
||||
{ }
|
||||
const std::string & GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(
|
||||
const RouteParameters & routeParameters,
|
||||
http::Reply& reply
|
||||
) {
|
||||
//check number of parameters
|
||||
if(!routeParameters.coordinates.size()) {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
if(false == checkCoord(routeParameters.coordinates[0])) {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
//query to helpdesk
|
||||
FixedPointCoordinate result;
|
||||
std::string tmp;
|
||||
//json
|
||||
|
||||
if(!routeParameters.jsonpParameter.empty()) {
|
||||
reply.content.push_back(routeParameters.jsonpParameter);
|
||||
reply.content.push_back("(");
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.push_back ("{");
|
||||
reply.content.push_back ("\"version\":0.3,");
|
||||
if(
|
||||
!facade->LocateClosestEndPointForCoordinate(
|
||||
routeParameters.coordinates[0],
|
||||
result
|
||||
)
|
||||
) {
|
||||
reply.content.push_back ("\"status\":207,");
|
||||
reply.content.push_back ("\"mapped_coordinate\":[]");
|
||||
} else {
|
||||
//Write coordinate to stream
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.push_back ("\"status\":0,");
|
||||
reply.content.push_back ("\"mapped_coordinate\":");
|
||||
convertInternalLatLonToString(result.lat, tmp);
|
||||
reply.content.push_back("[");
|
||||
reply.content.push_back(tmp);
|
||||
convertInternalLatLonToString(result.lon, tmp);
|
||||
reply.content.push_back(",");
|
||||
reply.content.push_back(tmp);
|
||||
reply.content.push_back("]");
|
||||
}
|
||||
reply.content.push_back(",\"transactionId\": \"OSRM Routing Engine JSON Locate (v0.3)\"");
|
||||
reply.content.push_back("}");
|
||||
reply.headers.resize(3);
|
||||
if(!routeParameters.jsonpParameter.empty()) {
|
||||
reply.content.push_back( ")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.js\"";
|
||||
} else {
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.json\"";
|
||||
}
|
||||
reply.headers[0].name = "Content-Length";
|
||||
unsigned content_length = 0;
|
||||
BOOST_FOREACH(const std::string & snippet, reply.content) {
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT * facade;
|
||||
};
|
||||
|
||||
#endif /* LOCATEPLUGIN_H_ */
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NearestPlugin_H_
|
||||
#define NearestPlugin_H_
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
/*
|
||||
* This Plugin locates the nearest point on a street in the road network for a given coordinate.
|
||||
*/
|
||||
|
||||
template<class DataFacadeT>
|
||||
class NearestPlugin : public BasePlugin {
|
||||
public:
|
||||
NearestPlugin(DataFacadeT * facade )
|
||||
:
|
||||
facade(facade),
|
||||
descriptor_string("nearest")
|
||||
{
|
||||
descriptorTable.insert(std::make_pair("" , 0)); //default descriptor
|
||||
descriptorTable.insert(std::make_pair("json", 1));
|
||||
}
|
||||
const std::string & GetDescriptor() const { return descriptor_string; }
|
||||
void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
|
||||
//check number of parameters
|
||||
if(!routeParameters.coordinates.size()) {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
if( !checkCoord(routeParameters.coordinates[0]) ) {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
PhantomNode result;
|
||||
facade->FindPhantomNodeForCoordinate(
|
||||
routeParameters.coordinates[0],
|
||||
result,
|
||||
routeParameters.zoomLevel
|
||||
);
|
||||
|
||||
std::string temp_string;
|
||||
//json
|
||||
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content.push_back(routeParameters.jsonpParameter);
|
||||
reply.content.push_back("(");
|
||||
}
|
||||
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.push_back("{");
|
||||
reply.content.push_back("\"version\":0.3,");
|
||||
reply.content.push_back("\"status\":");
|
||||
if(UINT_MAX != result.edgeBasedNode) {
|
||||
reply.content.push_back("0,");
|
||||
} else {
|
||||
reply.content.push_back("207,");
|
||||
}
|
||||
reply.content.push_back("\"mapped_coordinate\":");
|
||||
reply.content.push_back("[");
|
||||
if(UINT_MAX != result.edgeBasedNode) {
|
||||
convertInternalLatLonToString(result.location.lat, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
convertInternalLatLonToString(result.location.lon, temp_string);
|
||||
reply.content.push_back(",");
|
||||
reply.content.push_back(temp_string);
|
||||
}
|
||||
reply.content.push_back("],");
|
||||
reply.content.push_back("\"name\":\"");
|
||||
if(UINT_MAX != result.edgeBasedNode) {
|
||||
facade->GetName(result.nodeBasedEdgeNameID, temp_string);
|
||||
reply.content.push_back(temp_string);
|
||||
}
|
||||
reply.content.push_back("\"");
|
||||
reply.content.push_back(",\"transactionId\":\"OSRM Routing Engine JSON Nearest (v0.3)\"");
|
||||
reply.content.push_back("}");
|
||||
reply.headers.resize(3);
|
||||
if( !routeParameters.jsonpParameter.empty() ) {
|
||||
reply.content.push_back(")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.js\"";
|
||||
} else {
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.json\"";
|
||||
}
|
||||
reply.headers[0].name = "Content-Length";
|
||||
unsigned content_length = 0;
|
||||
BOOST_FOREACH(const std::string & snippet, reply.content) {
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, temp_string);
|
||||
reply.headers[0].value = temp_string;
|
||||
}
|
||||
|
||||
private:
|
||||
DataFacadeT * facade;
|
||||
HashTable<std::string, unsigned> descriptorTable;
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* NearestPlugin_H_ */
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TIMESTAMPPLUGIN_H_
|
||||
#define TIMESTAMPPLUGIN_H_
|
||||
|
||||
#include "BasePlugin.h"
|
||||
|
||||
template<class DataFacadeT>
|
||||
class TimestampPlugin : public BasePlugin {
|
||||
public:
|
||||
TimestampPlugin(const DataFacadeT * facade)
|
||||
: facade(facade), descriptor_string("timestamp")
|
||||
{ }
|
||||
const std::string & GetDescriptor() const { return descriptor_string; }
|
||||
void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
|
||||
std::string tmp;
|
||||
|
||||
//json
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content.push_back(routeParameters.jsonpParameter);
|
||||
reply.content.push_back("(");
|
||||
}
|
||||
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.push_back("{");
|
||||
reply.content.push_back("\"version\":0.3,");
|
||||
reply.content.push_back("\"status\":");
|
||||
reply.content.push_back("0,");
|
||||
reply.content.push_back("\"timestamp\":\"");
|
||||
reply.content.push_back(facade->GetTimestamp());
|
||||
reply.content.push_back("\"");
|
||||
reply.content.push_back(",\"transactionId\":\"OSRM Routing Engine JSON timestamp (v0.3)\"");
|
||||
reply.content.push_back("}");
|
||||
reply.headers.resize(3);
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content.push_back(")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"timestamp.js\"";
|
||||
} else {
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"timestamp.json\"";
|
||||
}
|
||||
unsigned content_length = 0;
|
||||
BOOST_FOREACH(const std::string & snippet, reply.content) {
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
}
|
||||
private:
|
||||
const DataFacadeT * facade;
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* TIMESTAMPPLUGIN_H_ */
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef VIAROUTEPLUGIN_H_
|
||||
#define VIAROUTEPLUGIN_H_
|
||||
|
||||
#include "BasePlugin.h"
|
||||
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/SearchEngine.h"
|
||||
#include "../Descriptors/BaseDescriptor.h"
|
||||
#include "../Descriptors/GPXDescriptor.h"
|
||||
#include "../Descriptors/JSONDescriptor.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template<class DataFacadeT>
|
||||
class ViaRoutePlugin : public BasePlugin {
|
||||
private:
|
||||
boost::unordered_map<std::string, unsigned> descriptorTable;
|
||||
SearchEngine<DataFacadeT> * search_engine_ptr;
|
||||
public:
|
||||
|
||||
ViaRoutePlugin(DataFacadeT * facade)
|
||||
:
|
||||
descriptor_string("viaroute"),
|
||||
facade(facade)
|
||||
{
|
||||
//TODO: set up an engine for each thread!!
|
||||
search_engine_ptr = new SearchEngine<DataFacadeT>(facade);
|
||||
|
||||
descriptorTable.emplace("json", 0);
|
||||
descriptorTable.emplace("gpx" , 1);
|
||||
}
|
||||
|
||||
virtual ~ViaRoutePlugin() {
|
||||
delete search_engine_ptr;
|
||||
}
|
||||
|
||||
const std::string & GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(
|
||||
const RouteParameters & routeParameters,
|
||||
http::Reply& reply
|
||||
) {
|
||||
//check number of parameters
|
||||
if( 2 > routeParameters.coordinates.size() ) {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
RawRouteData rawRoute;
|
||||
rawRoute.checkSum = facade->GetCheckSum();
|
||||
bool checksumOK = (routeParameters.checkSum == rawRoute.checkSum);
|
||||
std::vector<std::string> textCoord;
|
||||
for(unsigned i = 0; i < routeParameters.coordinates.size(); ++i) {
|
||||
if( !checkCoord(routeParameters.coordinates[i]) ) {
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
rawRoute.rawViaNodeCoordinates.push_back(routeParameters.coordinates[i]);
|
||||
}
|
||||
std::vector<PhantomNode> phantomNodeVector(rawRoute.rawViaNodeCoordinates.size());
|
||||
for(unsigned i = 0; i < rawRoute.rawViaNodeCoordinates.size(); ++i) {
|
||||
if(checksumOK && i < routeParameters.hints.size() && "" != routeParameters.hints[i]) {
|
||||
// SimpleLogger().Write() <<"Decoding hint: " << routeParameters.hints[i] << " for location index " << i;
|
||||
DecodeObjectFromBase64(routeParameters.hints[i], phantomNodeVector[i]);
|
||||
if(phantomNodeVector[i].isValid(facade->GetNumberOfNodes())) {
|
||||
// SimpleLogger().Write() << "Decoded hint " << i << " successfully";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// SimpleLogger().Write() << "Brute force lookup of coordinate " << i;
|
||||
facade->FindPhantomNodeForCoordinate(
|
||||
rawRoute.rawViaNodeCoordinates[i],
|
||||
phantomNodeVector[i],
|
||||
routeParameters.zoomLevel
|
||||
);
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < phantomNodeVector.size()-1; ++i) {
|
||||
PhantomNodes segmentPhantomNodes;
|
||||
segmentPhantomNodes.startPhantom = phantomNodeVector[i];
|
||||
segmentPhantomNodes.targetPhantom = phantomNodeVector[i+1];
|
||||
rawRoute.segmentEndCoordinates.push_back(segmentPhantomNodes);
|
||||
}
|
||||
if(
|
||||
( routeParameters.alternateRoute ) &&
|
||||
(1 == rawRoute.segmentEndCoordinates.size())
|
||||
) {
|
||||
search_engine_ptr->alternative_path(
|
||||
rawRoute.segmentEndCoordinates[0],
|
||||
rawRoute
|
||||
);
|
||||
} else {
|
||||
search_engine_ptr->shortest_path(
|
||||
rawRoute.segmentEndCoordinates,
|
||||
rawRoute
|
||||
);
|
||||
}
|
||||
|
||||
if(INT_MAX == rawRoute.lengthOfShortestPath ) {
|
||||
SimpleLogger().Write(logDEBUG) <<
|
||||
"Error occurred, single path not found";
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
|
||||
//TODO: Move to member as smart pointer
|
||||
BaseDescriptor<DataFacadeT> * desc;
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content.push_back(routeParameters.jsonpParameter);
|
||||
reply.content.push_back("(");
|
||||
}
|
||||
|
||||
DescriptorConfig descriptorConfig;
|
||||
|
||||
unsigned descriptorType = 0;
|
||||
if(descriptorTable.find(routeParameters.outputFormat) != descriptorTable.end() ) {
|
||||
descriptorType = descriptorTable.find(routeParameters.outputFormat)->second;
|
||||
}
|
||||
descriptorConfig.zoom_level = routeParameters.zoomLevel;
|
||||
descriptorConfig.instructions = routeParameters.printInstructions;
|
||||
descriptorConfig.geometry = routeParameters.geometry;
|
||||
descriptorConfig.encode_geometry = routeParameters.compression;
|
||||
|
||||
switch(descriptorType){
|
||||
case 0:
|
||||
desc = new JSONDescriptor<DataFacadeT>();
|
||||
|
||||
break;
|
||||
case 1:
|
||||
desc = new GPXDescriptor<DataFacadeT>();
|
||||
|
||||
break;
|
||||
default:
|
||||
desc = new JSONDescriptor<DataFacadeT>();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
PhantomNodes phantomNodes;
|
||||
phantomNodes.startPhantom = rawRoute.segmentEndCoordinates[0].startPhantom;
|
||||
phantomNodes.targetPhantom = rawRoute.segmentEndCoordinates[rawRoute.segmentEndCoordinates.size()-1].targetPhantom;
|
||||
desc->SetConfig(descriptorConfig);
|
||||
|
||||
desc->Run(reply, rawRoute, phantomNodes, facade);
|
||||
if("" != routeParameters.jsonpParameter) {
|
||||
reply.content.push_back(")\n");
|
||||
}
|
||||
reply.headers.resize(3);
|
||||
reply.headers[0].name = "Content-Length";
|
||||
std::string tmp;
|
||||
unsigned content_length = 0;
|
||||
BOOST_FOREACH(const std::string & snippet, reply.content) {
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
switch(descriptorType){
|
||||
case 0:
|
||||
if( !routeParameters.jsonpParameter.empty() ){
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.js\"";
|
||||
} else {
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.json\"";
|
||||
}
|
||||
|
||||
break;
|
||||
case 1:
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/gpx+xml; charset=UTF-8";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.gpx\"";
|
||||
|
||||
break;
|
||||
default:
|
||||
if( !routeParameters.jsonpParameter.empty() ){
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.js\"";
|
||||
} else {
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.json\"";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
delete desc;
|
||||
return;
|
||||
}
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT * facade;
|
||||
};
|
||||
|
||||
|
||||
#endif /* VIAROUTEPLUGIN_H_ */
|
||||
@@ -1,55 +1,40 @@
|
||||
Overview
|
||||
--------
|
||||
The repository provides a Leaflet [(1)] based web frontend to the Open Source Routing Machine (Project-OSRM [(2)]).
|
||||
The frontend is implemented in Javascript.
|
||||
Data is fetched from routing and geocoding servers using JSONP queries.
|
||||
The website is XHTML 1.0 Strict compliant.
|
||||
A deployed version of the the web frontend can be seen at [(3)].
|
||||
# Readme
|
||||
|
||||
For instructions on how to compile and run OSRM, please consult the Wiki at
|
||||
|
||||
Setup
|
||||
-----
|
||||
The frontend should work directly as provided.
|
||||
Several settings - including the URL for the routing server and the geocoder server - can be specified in `OSRM.config.js`.
|
||||
Different tile servers can be specified in `OSRM.Map.js`.
|
||||
Note that the URL shortener used for generating route links only works with URLs pointing to the official Project-OSRM website.
|
||||
https://github.com/DennisOSRM/Project-OSRM/wiki
|
||||
|
||||
or use our free and daily updated online service at
|
||||
|
||||
Branches
|
||||
--------
|
||||
* The `master` branch will always point to the latest released version of the frontend.
|
||||
* The `develop` branch should always point to a working version with new features and bugfixes (think of it as a nightly-build).
|
||||
* Other branches contain various work in progress.
|
||||
http://map.project-osrm.org
|
||||
|
||||
## References in publications
|
||||
|
||||
Bugtracking
|
||||
-----------
|
||||
Please use the OSRM-Project bug tracker [(4)] for submitting any bug reports or feature requests.
|
||||
When using the code in a (scientific) publication, please cite
|
||||
|
||||
Integration into Project-OSRM repository
|
||||
----------------------------------------
|
||||
The Project-OSRM repository already contains the frontend repository as a submodule.
|
||||
It will always point to the latest deployed version.
|
||||
To successfully work a repository that contains submodules, use the following git commands (available in git 1.7.1+):
|
||||
```
|
||||
@inproceedings{luxen-vetter-2011,
|
||||
author = {Luxen, Dennis and Vetter, Christian},
|
||||
title = {Real-time routing with OpenStreetMap data},
|
||||
booktitle = {Proceedings of the 19th ACM SIGSPATIAL International Conference on Advances in Geographic Information Systems},
|
||||
series = {GIS '11},
|
||||
year = {2011},
|
||||
isbn = {978-1-4503-1031-4},
|
||||
location = {Chicago, Illinois},
|
||||
pages = {513--516},
|
||||
numpages = {4},
|
||||
url = {http://doi.acm.org/10.1145/2093973.2094062},
|
||||
doi = {10.1145/2093973.2094062},
|
||||
acmid = {2094062},
|
||||
publisher = {ACM},
|
||||
address = {New York, NY, USA},
|
||||
}
|
||||
```
|
||||
|
||||
* `git clone --recursive`
|
||||
to clone a repository and the contained submodules
|
||||
## Current build status
|
||||
|
||||
* `git pull && git submodule update`
|
||||
to pull the latest version of the repository and update its submodules if required
|
||||
|
||||
Note that the frontend can also be checked out independently of the Project-OSRM repository.
|
||||
|
||||
|
||||
References
|
||||
----------
|
||||
[(1)] Cloudmade Leaflet: http://leaflet.cloudmade.com/
|
||||
[(2)] Project OSRM: http://project-osrm.org/
|
||||
[(3)] Project OSRM Frontend: http://map.project-osrm.org/
|
||||
[(4)] Project OSRM Bugtracker: https://github.com/DennisOSRM/Project-OSRM/issues/
|
||||
|
||||
|
||||
[(1)]: http://leaflet.cloudmade.com/ "Cloudmade Leaflet"
|
||||
[(2)]: http://project-osrm.org/ "Project OSRM"
|
||||
[(3)]: http://map.project-osrm.org/ "Project-OSRM Frontend"
|
||||
[(4)]: https://github.com/DennisOSRM/Project-OSRM/issues/ "Project-OSRM Bugtracker"
|
||||
| build config | branch | status |
|
||||
|:-------------|:--------|:------------|
|
||||
| Project OSRM | master | [](https://travis-ci.org/DennisOSRM/Project-OSRM) |
|
||||
| Project OSRM | develop | [](https://travis-ci.org/DennisOSRM/Project-OSRM) |
|
||||
| LUAbind fork | master | [](https://travis-ci.org/DennisOSRM/luabind) |
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
require 'OSM/StreamParser'
|
||||
require 'socket'
|
||||
require 'digest/sha1'
|
||||
require 'cucumber/rake/task'
|
||||
require 'sys/proctable'
|
||||
|
||||
BUILD_FOLDER = 'build'
|
||||
DATA_FOLDER = 'sandbox'
|
||||
PROFILE = 'examples/postgis'
|
||||
OSRM_PORT = 5000
|
||||
PROFILES_FOLDER = '../profiles'
|
||||
|
||||
Cucumber::Rake::Task.new do |t|
|
||||
t.cucumber_opts = %w{--format pretty}
|
||||
end
|
||||
|
||||
areas = {
|
||||
:kbh => { :country => 'denmark', :bbox => 'top=55.6972 left=12.5222 right=12.624 bottom=55.6376' },
|
||||
:frd => { :country => 'denmark', :bbox => 'top=55.7007 left=12.4765 bottom=55.6576 right=12.5698' },
|
||||
:regh => { :country => 'denmark', :bbox => 'top=56.164 left=11.792 bottom=55.403 right=12.731' },
|
||||
:denmark => { :country => 'denmark', :bbox => nil },
|
||||
:skaane => { :country => 'sweden', :bbox => 'top=56.55 left=12.4 bottom=55.3 right=14.6' }
|
||||
}
|
||||
|
||||
|
||||
|
||||
osm_data_area_name = ARGV[1] ? ARGV[1].to_s.to_sym : :kbh
|
||||
raise "Unknown data area." unless areas[osm_data_area_name]
|
||||
osm_data_country = areas[osm_data_area_name][:country]
|
||||
osm_data_area_bbox = areas[osm_data_area_name][:bbox]
|
||||
|
||||
|
||||
task osm_data_area_name.to_sym {} #define empty task to prevent rake from whining. will break if area has same name as a task
|
||||
|
||||
|
||||
def each_process name, &block
|
||||
Sys::ProcTable.ps do |process|
|
||||
if process.comm.strip == name.strip && process.state != 'zombie'
|
||||
yield process.pid.to_i, process.state.strip
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def up?
|
||||
find_pid('osrm-routed') != nil
|
||||
end
|
||||
|
||||
def find_pid name
|
||||
each_process(name) { |pid,state| return pid.to_i }
|
||||
return nil
|
||||
end
|
||||
|
||||
def wait_for_shutdown name
|
||||
timeout = 10
|
||||
(timeout*10).times do
|
||||
return if find_pid(name) == nil
|
||||
sleep 0.1
|
||||
end
|
||||
raise "*** Could not terminate #{name}."
|
||||
end
|
||||
|
||||
|
||||
desc "Rebuild and run tests."
|
||||
task :default => [:build]
|
||||
|
||||
desc "Build using CMake."
|
||||
task :build do
|
||||
if Dir.exists? BUILD_FOLDER
|
||||
Dir.chdir BUILD_FOLDER do
|
||||
system "make"
|
||||
end
|
||||
else
|
||||
system "mkdir build; cd build; cmake ..; make"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Setup config files."
|
||||
task :setup do
|
||||
end
|
||||
|
||||
desc "Download OSM data."
|
||||
task :download do
|
||||
Dir.mkdir "#{DATA_FOLDER}" unless File.exist? "#{DATA_FOLDER}"
|
||||
puts "Downloading..."
|
||||
puts "curl http://download.geofabrik.de/europe/#{osm_data_country}-latest.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
|
||||
raise "Error while downloading data." unless system "curl http://download.geofabrik.de/europe/#{osm_data_country}-latest.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
|
||||
if osm_data_area_bbox
|
||||
puts "Cropping and converting to protobuffer..."
|
||||
raise "Error while cropping data." unless system "osmosis --read-pbf file=#{DATA_FOLDER}/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=#{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf omitmetadata=true"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Crop OSM data"
|
||||
task :crop do
|
||||
if osm_data_area_bbox
|
||||
raise "Error while cropping data." unless system "osmosis --read-pbf file=#{DATA_FOLDER}/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=#{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf omitmetadata=true"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Reprocess OSM data."
|
||||
task :process => [:extract,:prepare] do
|
||||
end
|
||||
|
||||
desc "Extract OSM data."
|
||||
task :extract do
|
||||
Dir.chdir DATA_FOLDER do
|
||||
raise "Error while extracting data." unless system "../#{BUILD_FOLDER}/osrm-extract #{osm_data_area_name}.osm.pbf --profile ../profiles/#{PROFILE}.lua"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Prepare OSM data."
|
||||
task :prepare do
|
||||
Dir.chdir DATA_FOLDER do
|
||||
raise "Error while preparing data." unless system "../#{BUILD_FOLDER}/osrm-prepare #{osm_data_area_name}.osrm --profile ../profiles/#{PROFILE}.lua"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Delete preprocessing files."
|
||||
task :clean do
|
||||
File.delete *Dir.glob("#{DATA_FOLDER}/*.osrm")
|
||||
File.delete *Dir.glob("#{DATA_FOLDER}/*.osrm.*")
|
||||
end
|
||||
|
||||
desc "Run all cucumber test"
|
||||
task :test do
|
||||
system "cucumber"
|
||||
puts
|
||||
end
|
||||
|
||||
desc "Run the routing server in the terminal. Press Ctrl-C to stop."
|
||||
task :run do
|
||||
Dir.chdir DATA_FOLDER do
|
||||
system "../#{BUILD_FOLDER}/osrm-routed #{osm_data_area_name}.osrm --port #{OSRM_PORT}"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Launch the routing server in the background. Use rake:down to stop it."
|
||||
task :up do
|
||||
Dir.chdir DATA_FOLDER do
|
||||
abort("Already up.") if up?
|
||||
pipe = IO.popen("../#{BUILD_FOLDER}/osrm-routed #{osm_data_area_name}.osrm --port #{OSRM_PORT} 1>>osrm-routed.log 2>>osrm-routed.log")
|
||||
timeout = 5
|
||||
(timeout*10).times do
|
||||
begin
|
||||
socket = TCPSocket.new('localhost', OSRM_PORT)
|
||||
socket.puts 'ping'
|
||||
rescue Errno::ECONNREFUSED
|
||||
sleep 0.1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Stop the routing server."
|
||||
task :down do
|
||||
pid = find_pid 'osrm-routed'
|
||||
if pid
|
||||
Process.kill 'TERM', pid
|
||||
else
|
||||
puts "Already down."
|
||||
end
|
||||
end
|
||||
|
||||
desc "Kill all osrm-extract, osrm-prepare and osrm-routed processes."
|
||||
task :kill do
|
||||
each_process('osrm-routed') { |pid,state| Process.kill 'KILL', pid }
|
||||
each_process('osrm-prepare') { |pid,state| Process.kill 'KILL', pid }
|
||||
each_process('osrm-extract') { |pid,state| Process.kill 'KILL', pid }
|
||||
wait_for_shutdown 'osrm-routed'
|
||||
wait_for_shutdown 'osrm-prepare'
|
||||
wait_for_shutdown 'osrm-extract'
|
||||
end
|
||||
|
||||
desc "Get PIDs of all osrm-extract, osrm-prepare and osrm-routed processes."
|
||||
task :pid do
|
||||
each_process 'osrm-routed' do |pid,state|
|
||||
puts "#{pid}\t#{state}"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Stop, reprocess and restart."
|
||||
task :update => [:down,:process,:up] do
|
||||
end
|
||||
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ALTERNATIVEROUTES_H_
|
||||
#define ALTERNATIVEROUTES_H_
|
||||
|
||||
#include "BasicRoutingInterface.h"
|
||||
#include "../DataStructures/SearchEngineData.h"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
const double VIAPATH_ALPHA = 0.15;
|
||||
const double VIAPATH_EPSILON = 0.10; //alternative at most 15% longer
|
||||
const double VIAPATH_GAMMA = 0.75; //alternative shares at most 75% with the shortest.
|
||||
|
||||
template<class DataFacadeT>
|
||||
class AlternativeRouting : private BasicRoutingInterface<DataFacadeT> {
|
||||
typedef BasicRoutingInterface<DataFacadeT> super;
|
||||
typedef typename DataFacadeT::EdgeData EdgeData;
|
||||
typedef SearchEngineData::QueryHeap QueryHeap;
|
||||
typedef std::pair<NodeID, NodeID> SearchSpaceEdge;
|
||||
|
||||
struct RankedCandidateNode {
|
||||
RankedCandidateNode(const NodeID n, const int l, const int s) :
|
||||
node(n),
|
||||
length(l),
|
||||
sharing(s)
|
||||
{ }
|
||||
|
||||
NodeID node;
|
||||
int length;
|
||||
int sharing;
|
||||
bool operator<(const RankedCandidateNode& other) const {
|
||||
return (2*length + sharing) < (2*other.length + other.sharing);
|
||||
}
|
||||
};
|
||||
DataFacadeT * facade;
|
||||
SearchEngineData & engine_working_data;
|
||||
public:
|
||||
|
||||
AlternativeRouting(
|
||||
DataFacadeT * facade,
|
||||
SearchEngineData & engine_working_data
|
||||
) :
|
||||
super(facade),
|
||||
facade(facade),
|
||||
engine_working_data(engine_working_data)
|
||||
{ }
|
||||
|
||||
~AlternativeRouting() {}
|
||||
|
||||
void operator()(
|
||||
const PhantomNodes & phantom_node_pair,
|
||||
RawRouteData & raw_route_data) {
|
||||
if( (!phantom_node_pair.AtLeastOnePhantomNodeIsUINTMAX()) ||
|
||||
phantom_node_pair.PhantomNodesHaveEqualLocation()
|
||||
) {
|
||||
raw_route_data.lengthOfShortestPath = INT_MAX;
|
||||
raw_route_data.lengthOfAlternativePath = INT_MAX;
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<NodeID> alternative_path;
|
||||
std::vector<NodeID> via_node_candidate_list;
|
||||
std::vector<SearchSpaceEdge> forward_search_space;
|
||||
std::vector<SearchSpaceEdge> reverse_search_space;
|
||||
|
||||
//Init queues, semi-expensive because access to TSS invokes a sys-call
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
engine_working_data.InitializeOrClearThirdThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
|
||||
QueryHeap & forward_heap1 = *(engine_working_data.forwardHeap);
|
||||
QueryHeap & reverse_heap1 = *(engine_working_data.backwardHeap);
|
||||
QueryHeap & forward_heap2 = *(engine_working_data.forwardHeap2);
|
||||
QueryHeap & reverse_heap2 = *(engine_working_data.backwardHeap2);
|
||||
|
||||
int upper_bound_to_shortest_path_distance = INT_MAX;
|
||||
NodeID middle_node = UINT_MAX;
|
||||
forward_heap1.Insert(
|
||||
phantom_node_pair.startPhantom.edgeBasedNode,
|
||||
-phantom_node_pair.startPhantom.weight1,
|
||||
phantom_node_pair.startPhantom.edgeBasedNode
|
||||
);
|
||||
if(phantom_node_pair.startPhantom.isBidirected() ) {
|
||||
forward_heap1.Insert(
|
||||
phantom_node_pair.startPhantom.edgeBasedNode+1,
|
||||
-phantom_node_pair.startPhantom.weight2,
|
||||
phantom_node_pair.startPhantom.edgeBasedNode+1
|
||||
);
|
||||
}
|
||||
|
||||
reverse_heap1.Insert(
|
||||
phantom_node_pair.targetPhantom.edgeBasedNode,
|
||||
phantom_node_pair.targetPhantom.weight1,
|
||||
phantom_node_pair.targetPhantom.edgeBasedNode
|
||||
);
|
||||
if(phantom_node_pair.targetPhantom.isBidirected() ) {
|
||||
reverse_heap1.Insert(
|
||||
phantom_node_pair.targetPhantom.edgeBasedNode+1,
|
||||
phantom_node_pair.targetPhantom.weight2,
|
||||
phantom_node_pair.targetPhantom.edgeBasedNode+1
|
||||
);
|
||||
}
|
||||
|
||||
const int forward_offset = super::ComputeEdgeOffset(
|
||||
phantom_node_pair.startPhantom
|
||||
);
|
||||
const int reverse_offset = super::ComputeEdgeOffset(
|
||||
phantom_node_pair.targetPhantom
|
||||
);
|
||||
|
||||
//search from s and t till new_min/(1+epsilon) > length_of_shortest_path
|
||||
while(0 < (forward_heap1.Size() + reverse_heap1.Size())){
|
||||
if(0 < forward_heap1.Size()){
|
||||
AlternativeRoutingStep<true>(
|
||||
forward_heap1,
|
||||
reverse_heap1,
|
||||
&middle_node,
|
||||
&upper_bound_to_shortest_path_distance,
|
||||
via_node_candidate_list,
|
||||
forward_search_space,
|
||||
forward_offset
|
||||
);
|
||||
}
|
||||
if(0 < reverse_heap1.Size()){
|
||||
AlternativeRoutingStep<false>(
|
||||
reverse_heap1,
|
||||
forward_heap1,
|
||||
&middle_node,
|
||||
&upper_bound_to_shortest_path_distance,
|
||||
via_node_candidate_list,
|
||||
reverse_search_space,
|
||||
reverse_offset
|
||||
);
|
||||
}
|
||||
}
|
||||
sort_unique_resize(via_node_candidate_list);
|
||||
|
||||
std::vector<NodeID> packed_forward_path;
|
||||
std::vector<NodeID> packed_reverse_path;
|
||||
|
||||
super::RetrievePackedPathFromSingleHeap(
|
||||
forward_heap1,
|
||||
middle_node,
|
||||
packed_forward_path
|
||||
);
|
||||
super::RetrievePackedPathFromSingleHeap(
|
||||
reverse_heap1,
|
||||
middle_node,
|
||||
packed_reverse_path
|
||||
);
|
||||
|
||||
boost::unordered_map<NodeID, int> approximated_forward_sharing;
|
||||
boost::unordered_map<NodeID, int> approximated_reverse_sharing;
|
||||
|
||||
unsigned index_into_forward_path = 0;
|
||||
//sweep over search space, compute forward sharing for each current edge (u,v)
|
||||
BOOST_FOREACH(const SearchSpaceEdge & current_edge, forward_search_space) {
|
||||
const NodeID u = current_edge.first;
|
||||
const NodeID v = current_edge.second;
|
||||
if(packed_forward_path.size() < index_into_forward_path && current_edge == forward_search_space[index_into_forward_path]) {
|
||||
//current_edge is on shortest path => sharing(u):=queue.GetKey(u);
|
||||
++index_into_forward_path;
|
||||
approximated_forward_sharing[v] = forward_heap1.GetKey(u);
|
||||
} else {
|
||||
//sharing (s) = sharing (t)
|
||||
approximated_forward_sharing[v] = approximated_forward_sharing[u];
|
||||
}
|
||||
}
|
||||
|
||||
unsigned index_into_reverse_path = 0;
|
||||
//sweep over search space, compute backward sharing
|
||||
BOOST_FOREACH(const SearchSpaceEdge & current_edge, reverse_search_space) {
|
||||
const NodeID u = current_edge.first;
|
||||
const NodeID v = current_edge.second;
|
||||
if(packed_reverse_path.size() < index_into_reverse_path && current_edge == reverse_search_space[index_into_reverse_path]) {
|
||||
//current_edge is on shortest path => sharing(u):=queue.GetKey(u);
|
||||
++index_into_reverse_path;
|
||||
approximated_reverse_sharing[v] = reverse_heap1.GetKey(u);
|
||||
} else {
|
||||
//sharing (s) = sharing (t)
|
||||
approximated_reverse_sharing[v] = approximated_reverse_sharing[u];
|
||||
}
|
||||
}
|
||||
std::vector<NodeID> nodes_that_passed_preselection;
|
||||
BOOST_FOREACH(const NodeID node, via_node_candidate_list) {
|
||||
int approximated_sharing = approximated_forward_sharing[node] + approximated_reverse_sharing[node];
|
||||
int approximated_length = forward_heap1.GetKey(node)+reverse_heap1.GetKey(node);
|
||||
bool lengthPassed = (approximated_length < upper_bound_to_shortest_path_distance*(1+VIAPATH_EPSILON));
|
||||
bool sharingPassed = (approximated_sharing <= upper_bound_to_shortest_path_distance*VIAPATH_GAMMA);
|
||||
bool stretchPassed = approximated_length - approximated_sharing < (1.+VIAPATH_EPSILON)*(upper_bound_to_shortest_path_distance-approximated_sharing);
|
||||
|
||||
if(lengthPassed && sharingPassed && stretchPassed) {
|
||||
nodes_that_passed_preselection.push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<NodeID> & packedShortestPath = packed_forward_path;
|
||||
std::reverse(packedShortestPath.begin(), packedShortestPath.end());
|
||||
packedShortestPath.push_back(middle_node);
|
||||
packedShortestPath.insert(packedShortestPath.end(),packed_reverse_path.begin(), packed_reverse_path.end());
|
||||
std::vector<RankedCandidateNode > rankedCandidates;
|
||||
|
||||
//prioritizing via nodes for deep inspection
|
||||
BOOST_FOREACH(const NodeID node, nodes_that_passed_preselection) {
|
||||
int lengthOfViaPath = 0, sharingOfViaPath = 0;
|
||||
computeLengthAndSharingOfViaPath(node, &lengthOfViaPath, &sharingOfViaPath, forward_offset+reverse_offset, packedShortestPath);
|
||||
if(sharingOfViaPath <= upper_bound_to_shortest_path_distance*VIAPATH_GAMMA) {
|
||||
rankedCandidates.push_back(RankedCandidateNode(node, lengthOfViaPath, sharingOfViaPath));
|
||||
}
|
||||
}
|
||||
std::sort(rankedCandidates.begin(), rankedCandidates.end());
|
||||
|
||||
NodeID selectedViaNode = UINT_MAX;
|
||||
int lengthOfViaPath = INT_MAX;
|
||||
NodeID s_v_middle = UINT_MAX, v_t_middle = UINT_MAX;
|
||||
BOOST_FOREACH(const RankedCandidateNode & candidate, rankedCandidates){
|
||||
if(viaNodeCandidatePasses_T_Test(forward_heap1, reverse_heap1, forward_heap2, reverse_heap2, candidate, forward_offset+reverse_offset, upper_bound_to_shortest_path_distance, &lengthOfViaPath, &s_v_middle, &v_t_middle)) {
|
||||
// select first admissable
|
||||
selectedViaNode = candidate.node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Unpack shortest path and alternative, if they exist
|
||||
if(INT_MAX != upper_bound_to_shortest_path_distance) {
|
||||
super::UnpackPath(packedShortestPath, raw_route_data.computedShortestPath);
|
||||
raw_route_data.lengthOfShortestPath = upper_bound_to_shortest_path_distance;
|
||||
} else {
|
||||
raw_route_data.lengthOfShortestPath = INT_MAX;
|
||||
}
|
||||
|
||||
if(selectedViaNode != UINT_MAX) {
|
||||
retrievePackedViaPath(forward_heap1, reverse_heap1, forward_heap2, reverse_heap2, s_v_middle, v_t_middle, raw_route_data.computedAlternativePath);
|
||||
raw_route_data.lengthOfAlternativePath = lengthOfViaPath;
|
||||
} else {
|
||||
raw_route_data.lengthOfAlternativePath = INT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//unpack <s,..,v,..,t> by exploring search spaces from v
|
||||
inline void retrievePackedViaPath(QueryHeap & _forwardHeap1, QueryHeap & _backwardHeap1, QueryHeap & _forwardHeap2, QueryHeap & _backwardHeap2,
|
||||
const NodeID s_v_middle, const NodeID v_t_middle, std::vector<_PathData> & unpackedPath) {
|
||||
//unpack [s,v)
|
||||
std::vector<NodeID> packed_s_v_path, packed_v_t_path;
|
||||
super::RetrievePackedPathFromHeap(_forwardHeap1, _backwardHeap2, s_v_middle, packed_s_v_path);
|
||||
packed_s_v_path.resize(packed_s_v_path.size()-1);
|
||||
//unpack [v,t]
|
||||
super::RetrievePackedPathFromHeap(_forwardHeap2, _backwardHeap1, v_t_middle, packed_v_t_path);
|
||||
packed_s_v_path.insert(packed_s_v_path.end(),packed_v_t_path.begin(), packed_v_t_path.end() );
|
||||
super::UnpackPath(packed_s_v_path, unpackedPath);
|
||||
}
|
||||
|
||||
inline void computeLengthAndSharingOfViaPath(const NodeID via_node, int *real_length_of_via_path, int *sharing_of_via_path,
|
||||
const int offset, const std::vector<NodeID> & packed_shortest_path) {
|
||||
//compute and unpack <s,..,v> and <v,..,t> by exploring search spaces from v and intersecting against queues
|
||||
//only half-searches have to be done at this stage
|
||||
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
|
||||
QueryHeap & existingForwardHeap = *engine_working_data.forwardHeap;
|
||||
QueryHeap & existingBackwardHeap = *engine_working_data.backwardHeap;
|
||||
QueryHeap & newForwardHeap = *engine_working_data.forwardHeap2;
|
||||
QueryHeap & newBackwardHeap = *engine_working_data.backwardHeap2;
|
||||
|
||||
std::vector < NodeID > packed_s_v_path;
|
||||
std::vector < NodeID > packed_v_t_path;
|
||||
|
||||
std::vector<NodeID> partiallyUnpackedShortestPath;
|
||||
std::vector<NodeID> partiallyUnpackedViaPath;
|
||||
|
||||
NodeID s_v_middle = UINT_MAX;
|
||||
int upperBoundFor_s_v_Path = INT_MAX;//compute path <s,..,v> by reusing forward search from s
|
||||
newBackwardHeap.Insert(via_node, 0, via_node);
|
||||
while (0 < newBackwardHeap.Size()) {
|
||||
super::RoutingStep(newBackwardHeap, existingForwardHeap, &s_v_middle, &upperBoundFor_s_v_Path, 2 * offset, false);
|
||||
}
|
||||
//compute path <v,..,t> by reusing backward search from node t
|
||||
NodeID v_t_middle = UINT_MAX;
|
||||
int upperBoundFor_v_t_Path = INT_MAX;
|
||||
newForwardHeap.Insert(via_node, 0, via_node);
|
||||
while (0 < newForwardHeap.Size() ) {
|
||||
super::RoutingStep(newForwardHeap, existingBackwardHeap, &v_t_middle, &upperBoundFor_v_t_Path, 2 * offset, true);
|
||||
}
|
||||
*real_length_of_via_path = upperBoundFor_s_v_Path + upperBoundFor_v_t_Path;
|
||||
|
||||
if(UINT_MAX == s_v_middle || UINT_MAX == v_t_middle)
|
||||
return;
|
||||
|
||||
//retrieve packed paths
|
||||
super::RetrievePackedPathFromHeap(existingForwardHeap, newBackwardHeap, s_v_middle, packed_s_v_path);
|
||||
super::RetrievePackedPathFromHeap(newForwardHeap, existingBackwardHeap, v_t_middle, packed_v_t_path);
|
||||
|
||||
//partial unpacking, compute sharing
|
||||
//First partially unpack s-->v until paths deviate, note length of common path.
|
||||
for (unsigned i = 0, lengthOfPackedPath = std::min( packed_s_v_path.size(), packed_shortest_path.size()) - 1; (i < lengthOfPackedPath); ++i) {
|
||||
if (packed_s_v_path[i] == packed_shortest_path[i] && packed_s_v_path[i + 1] == packed_shortest_path[i + 1]) {
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_s_v_path[i], packed_s_v_path[i + 1]);
|
||||
*sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
|
||||
} else {
|
||||
if (packed_s_v_path[i] == packed_shortest_path[i]) {
|
||||
super::UnpackEdge(packed_s_v_path[i], packed_s_v_path[i+1], partiallyUnpackedViaPath);
|
||||
super::UnpackEdge(packed_shortest_path[i], packed_shortest_path[i+1], partiallyUnpackedShortestPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//traverse partially unpacked edge and note common prefix
|
||||
for (int i = 0, lengthOfPackedPath = std::min( partiallyUnpackedViaPath.size(), partiallyUnpackedShortestPath.size()) - 1; (i < lengthOfPackedPath) && (partiallyUnpackedViaPath[i] == partiallyUnpackedShortestPath[i] && partiallyUnpackedViaPath[i+1] == partiallyUnpackedShortestPath[i+1]); ++i) {
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection(partiallyUnpackedViaPath[i], partiallyUnpackedViaPath[i+1]);
|
||||
*sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
|
||||
}
|
||||
|
||||
//Second, partially unpack v-->t in reverse order until paths deviate and note lengths
|
||||
int viaPathIndex = packed_v_t_path.size() - 1;
|
||||
int shortestPathIndex = packed_shortest_path.size() - 1;
|
||||
for (; viaPathIndex > 0 && shortestPathIndex > 0; --viaPathIndex,--shortestPathIndex ) {
|
||||
if (packed_v_t_path[viaPathIndex - 1] == packed_shortest_path[shortestPathIndex - 1] && packed_v_t_path[viaPathIndex] == packed_shortest_path[shortestPathIndex]) {
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection( packed_v_t_path[viaPathIndex - 1], packed_v_t_path[viaPathIndex]);
|
||||
*sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
|
||||
} else {
|
||||
if (packed_v_t_path[viaPathIndex] == packed_shortest_path[shortestPathIndex]) {
|
||||
super::UnpackEdge(packed_v_t_path[viaPathIndex-1], packed_v_t_path[viaPathIndex], partiallyUnpackedViaPath);
|
||||
super::UnpackEdge(packed_shortest_path[shortestPathIndex-1] , packed_shortest_path[shortestPathIndex], partiallyUnpackedShortestPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viaPathIndex = partiallyUnpackedViaPath.size() - 1;
|
||||
shortestPathIndex = partiallyUnpackedShortestPath.size() - 1;
|
||||
for (; viaPathIndex > 0 && shortestPathIndex > 0; --viaPathIndex,--shortestPathIndex) {
|
||||
if (partiallyUnpackedViaPath[viaPathIndex - 1] == partiallyUnpackedShortestPath[shortestPathIndex - 1] && partiallyUnpackedViaPath[viaPathIndex] == partiallyUnpackedShortestPath[shortestPathIndex]) {
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection( partiallyUnpackedViaPath[viaPathIndex - 1], partiallyUnpackedViaPath[viaPathIndex]);
|
||||
*sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//finished partial unpacking spree! Amount of sharing is stored to appropriate pointer variable
|
||||
}
|
||||
|
||||
inline int approximateAmountOfSharing(const NodeID middleNodeIDOfAlternativePath, QueryHeap & _forwardHeap, QueryHeap & _backwardHeap, const std::vector<NodeID> & packedShortestPath) {
|
||||
std::vector<NodeID> packedAlternativePath;
|
||||
super::RetrievePackedPathFromHeap(_forwardHeap, _backwardHeap, middleNodeIDOfAlternativePath, packedAlternativePath);
|
||||
|
||||
if(packedShortestPath.size() < 2 || packedAlternativePath.size() < 2)
|
||||
return 0;
|
||||
|
||||
int sharing = 0;
|
||||
int aindex = 0;
|
||||
//compute forward sharing
|
||||
while( (packedAlternativePath[aindex] == packedShortestPath[aindex]) && (packedAlternativePath[aindex+1] == packedShortestPath[aindex+1]) ) {
|
||||
// SimpleLogger().Write() << "retrieving edge (" << packedAlternativePath[aindex] << "," << packedAlternativePath[aindex+1] << ")";
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection(packedAlternativePath[aindex], packedAlternativePath[aindex+1]);
|
||||
sharing += facade->GetEdgeData(edgeID).distance;
|
||||
++aindex;
|
||||
}
|
||||
|
||||
aindex = packedAlternativePath.size()-1;
|
||||
int bindex = packedShortestPath.size()-1;
|
||||
//compute backward sharing
|
||||
while( aindex > 0 && bindex > 0 && (packedAlternativePath[aindex] == packedShortestPath[bindex]) && (packedAlternativePath[aindex-1] == packedShortestPath[bindex-1]) ) {
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection(packedAlternativePath[aindex], packedAlternativePath[aindex-1]);
|
||||
sharing += facade->GetEdgeData(edgeID).distance;
|
||||
--aindex; --bindex;
|
||||
}
|
||||
return sharing;
|
||||
}
|
||||
|
||||
template<bool forwardDirection>
|
||||
inline void AlternativeRoutingStep(
|
||||
QueryHeap & _forward_heap,
|
||||
QueryHeap & _reverse_heap,
|
||||
NodeID *middle_node,
|
||||
int *upper_bound_to_shortest_path_distance,
|
||||
std::vector<NodeID>& searchSpaceIntersection,
|
||||
std::vector<SearchSpaceEdge> & search_space,
|
||||
const int edgeBasedOffset
|
||||
) const {
|
||||
const NodeID node = _forward_heap.DeleteMin();
|
||||
const int distance = _forward_heap.GetKey(node);
|
||||
int scaledDistance = (distance-edgeBasedOffset)/(1.+VIAPATH_EPSILON);
|
||||
if(scaledDistance > *upper_bound_to_shortest_path_distance){
|
||||
_forward_heap.DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
search_space.push_back(std::make_pair(_forward_heap.GetData( node ).parent, node));
|
||||
|
||||
if(_reverse_heap.WasInserted(node) ){
|
||||
searchSpaceIntersection.push_back(node);
|
||||
|
||||
const int newDistance = _reverse_heap.GetKey(node) + distance;
|
||||
if(newDistance < *upper_bound_to_shortest_path_distance ){
|
||||
if(newDistance>=0 ) {
|
||||
*middle_node = node;
|
||||
*upper_bound_to_shortest_path_distance = newDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( EdgeID edge = facade->BeginEdges( node ); edge < facade->EndEdges(node); edge++ ) {
|
||||
const EdgeData & data = facade->GetEdgeData(edge);
|
||||
bool forwardDirectionFlag = (forwardDirection ? data.forward : data.backward );
|
||||
if(forwardDirectionFlag) {
|
||||
|
||||
const NodeID to = facade->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 ( !_forward_heap.WasInserted( to ) ) {
|
||||
_forward_heap.Insert( to, toDistance, node );
|
||||
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < _forward_heap.GetKey( to ) ) {
|
||||
_forward_heap.GetData( to ).parent = node;
|
||||
_forward_heap.DecreaseKey( to, toDistance );
|
||||
//new parent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//conduct T-Test
|
||||
inline bool viaNodeCandidatePasses_T_Test( QueryHeap& existingForwardHeap, QueryHeap& existingBackwardHeap, QueryHeap& newForwardHeap, QueryHeap& newBackwardHeap, const RankedCandidateNode& candidate, const int offset, const int lengthOfShortestPath, int * lengthOfViaPath, NodeID * s_v_middle, NodeID * v_t_middle) {
|
||||
newForwardHeap.Clear();
|
||||
newBackwardHeap.Clear();
|
||||
std::vector < NodeID > packed_s_v_path;
|
||||
std::vector < NodeID > packed_v_t_path;
|
||||
|
||||
*s_v_middle = UINT_MAX;
|
||||
int upperBoundFor_s_v_Path = INT_MAX;
|
||||
//compute path <s,..,v> by reusing forward search from s
|
||||
newBackwardHeap.Insert(candidate.node, 0, candidate.node);
|
||||
while (newBackwardHeap.Size() > 0) {
|
||||
super::RoutingStep(newBackwardHeap, existingForwardHeap, s_v_middle, &upperBoundFor_s_v_Path, 2*offset, false);
|
||||
}
|
||||
|
||||
if(INT_MAX == upperBoundFor_s_v_Path)
|
||||
return false;
|
||||
|
||||
//compute path <v,..,t> by reusing backward search from t
|
||||
*v_t_middle = UINT_MAX;
|
||||
int upperBoundFor_v_t_Path = INT_MAX;
|
||||
newForwardHeap.Insert(candidate.node, 0, candidate.node);
|
||||
while (newForwardHeap.Size() > 0) {
|
||||
super::RoutingStep(newForwardHeap, existingBackwardHeap, v_t_middle, &upperBoundFor_v_t_Path, 2*offset, true);
|
||||
}
|
||||
|
||||
if(INT_MAX == upperBoundFor_v_t_Path)
|
||||
return false;
|
||||
|
||||
*lengthOfViaPath = upperBoundFor_s_v_Path + upperBoundFor_v_t_Path;
|
||||
|
||||
//retrieve packed paths
|
||||
super::RetrievePackedPathFromHeap(existingForwardHeap, newBackwardHeap, *s_v_middle, packed_s_v_path);
|
||||
super::RetrievePackedPathFromHeap(newForwardHeap, existingBackwardHeap, *v_t_middle, packed_v_t_path);
|
||||
|
||||
NodeID s_P = *s_v_middle, t_P = *v_t_middle;
|
||||
if(UINT_MAX == s_P) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(UINT_MAX == t_P) {
|
||||
return false;
|
||||
}
|
||||
const int T_threshold = VIAPATH_EPSILON * lengthOfShortestPath;
|
||||
int unpackedUntilDistance = 0;
|
||||
|
||||
std::stack<SearchSpaceEdge> unpackStack;
|
||||
//Traverse path s-->v
|
||||
for (unsigned i = packed_s_v_path.size() - 1; (i > 0) && unpackStack.empty(); --i) {
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection( packed_s_v_path[i - 1], packed_s_v_path[i]);
|
||||
int lengthOfCurrentEdge = facade->GetEdgeData(edgeID).distance;
|
||||
if (lengthOfCurrentEdge + unpackedUntilDistance >= T_threshold) {
|
||||
unpackStack.push(std::make_pair(packed_s_v_path[i - 1], packed_s_v_path[i]));
|
||||
} else {
|
||||
unpackedUntilDistance += lengthOfCurrentEdge;
|
||||
s_P = packed_s_v_path[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
while (!unpackStack.empty()) {
|
||||
const SearchSpaceEdge viaPathEdge = unpackStack.top();
|
||||
unpackStack.pop();
|
||||
EdgeID edgeIDInViaPath = facade->FindEdgeInEitherDirection(viaPathEdge.first, viaPathEdge.second);
|
||||
if(UINT_MAX == edgeIDInViaPath)
|
||||
return false;
|
||||
EdgeData currentEdgeData = facade->GetEdgeData(edgeIDInViaPath);
|
||||
bool IsViaEdgeShortCut = currentEdgeData.shortcut;
|
||||
if (IsViaEdgeShortCut) {
|
||||
const NodeID middleOfViaPath = currentEdgeData.id;
|
||||
EdgeID edgeIDOfSecondSegment = facade->FindEdgeInEitherDirection(middleOfViaPath, viaPathEdge.second);
|
||||
int lengthOfSecondSegment = facade->GetEdgeData(edgeIDOfSecondSegment).distance;
|
||||
//attention: !unpacking in reverse!
|
||||
//Check if second segment is the one to go over treshold? if yes add second segment to stack, else push first segment to stack and add distance of second one.
|
||||
if (unpackedUntilDistance + lengthOfSecondSegment >= T_threshold) {
|
||||
unpackStack.push(std::make_pair(middleOfViaPath, viaPathEdge.second));
|
||||
} else {
|
||||
unpackedUntilDistance += lengthOfSecondSegment;
|
||||
unpackStack.push(std::make_pair(viaPathEdge.first, middleOfViaPath));
|
||||
}
|
||||
} else {
|
||||
// edge is not a shortcut, set the start node for T-Test to end of edge.
|
||||
unpackedUntilDistance += currentEdgeData.distance;
|
||||
s_P = viaPathEdge.first;
|
||||
}
|
||||
}
|
||||
|
||||
int lengthOfPathT_Test_Path = unpackedUntilDistance;
|
||||
unpackedUntilDistance = 0;
|
||||
//Traverse path s-->v
|
||||
for (unsigned i = 0, lengthOfPackedPath = packed_v_t_path.size() - 1; (i < lengthOfPackedPath) && unpackStack.empty(); ++i) {
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection( packed_v_t_path[i], packed_v_t_path[i + 1]);
|
||||
int lengthOfCurrentEdge = facade->GetEdgeData(edgeID).distance;
|
||||
if (lengthOfCurrentEdge + unpackedUntilDistance >= T_threshold) {
|
||||
unpackStack.push( std::make_pair(packed_v_t_path[i], packed_v_t_path[i + 1]));
|
||||
} else {
|
||||
unpackedUntilDistance += lengthOfCurrentEdge;
|
||||
t_P = packed_v_t_path[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
while (!unpackStack.empty()) {
|
||||
const SearchSpaceEdge viaPathEdge = unpackStack.top();
|
||||
unpackStack.pop();
|
||||
EdgeID edgeIDInViaPath = facade->FindEdgeInEitherDirection(viaPathEdge.first, viaPathEdge.second);
|
||||
if(UINT_MAX == edgeIDInViaPath)
|
||||
return false;
|
||||
EdgeData currentEdgeData = facade->GetEdgeData(edgeIDInViaPath);
|
||||
const bool IsViaEdgeShortCut = currentEdgeData.shortcut;
|
||||
if (IsViaEdgeShortCut) {
|
||||
const NodeID middleOfViaPath = currentEdgeData.id;
|
||||
EdgeID edgeIDOfFirstSegment = facade->FindEdgeInEitherDirection(viaPathEdge.first, middleOfViaPath);
|
||||
int lengthOfFirstSegment = facade->GetEdgeData( edgeIDOfFirstSegment).distance;
|
||||
//Check if first segment is the one to go over treshold? if yes first segment to stack, else push second segment to stack and add distance of first one.
|
||||
if (unpackedUntilDistance + lengthOfFirstSegment >= T_threshold) {
|
||||
unpackStack.push( std::make_pair(viaPathEdge.first, middleOfViaPath));
|
||||
} else {
|
||||
unpackedUntilDistance += lengthOfFirstSegment;
|
||||
unpackStack.push( std::make_pair(middleOfViaPath, viaPathEdge.second));
|
||||
}
|
||||
} else {
|
||||
// edge is not a shortcut, set the start node for T-Test to end of edge.
|
||||
unpackedUntilDistance += currentEdgeData.distance;
|
||||
t_P = viaPathEdge.second;
|
||||
}
|
||||
}
|
||||
|
||||
lengthOfPathT_Test_Path += unpackedUntilDistance;
|
||||
//Run actual T-Test query and compare if distances equal.
|
||||
engine_working_data.InitializeOrClearThirdThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
|
||||
QueryHeap& forward_heap3 = *engine_working_data.forwardHeap3;
|
||||
QueryHeap& backward_heap3 = *engine_working_data.backwardHeap3;
|
||||
int _upperBound = INT_MAX;
|
||||
NodeID middle = UINT_MAX;
|
||||
forward_heap3.Insert(s_P, 0, s_P);
|
||||
backward_heap3.Insert(t_P, 0, t_P);
|
||||
//exploration from s and t until deletemin/(1+epsilon) > _lengthOfShortestPath
|
||||
while (forward_heap3.Size() + backward_heap3.Size() > 0) {
|
||||
if (forward_heap3.Size() > 0) {
|
||||
super::RoutingStep(forward_heap3, backward_heap3, &middle, &_upperBound, offset, true);
|
||||
}
|
||||
if (backward_heap3.Size() > 0) {
|
||||
super::RoutingStep(backward_heap3, forward_heap3, &middle, &_upperBound, offset, false);
|
||||
}
|
||||
}
|
||||
return (_upperBound <= lengthOfPathT_Test_Path);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* ALTERNATIVEROUTES_H_ */
|
||||
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BASICROUTINGINTERFACE_H_
|
||||
#define BASICROUTINGINTERFACE_H_
|
||||
|
||||
#include "../DataStructures/RawRouteData.h"
|
||||
#include "../DataStructures/SearchEngineData.h"
|
||||
#include "../Util/ContainerUtils.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <climits>
|
||||
|
||||
#include <stack>
|
||||
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap2;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap2;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap3;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap3;
|
||||
|
||||
template<class DataFacadeT>
|
||||
class BasicRoutingInterface : boost::noncopyable {
|
||||
private:
|
||||
typedef typename DataFacadeT::EdgeData EdgeData;
|
||||
protected:
|
||||
DataFacadeT * facade;
|
||||
public:
|
||||
BasicRoutingInterface( DataFacadeT * facade ) : facade(facade) { }
|
||||
virtual ~BasicRoutingInterface(){ };
|
||||
|
||||
inline void RoutingStep(
|
||||
SearchEngineData::QueryHeap & forward_heap,
|
||||
SearchEngineData::QueryHeap & reverse_heap,
|
||||
NodeID * middle_node_id,
|
||||
int * upper_bound,
|
||||
const int edge_expansion_offset,
|
||||
const bool forward_direction
|
||||
) const {
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const int distance = forward_heap.GetKey(node);
|
||||
//SimpleLogger().Write() << "Settled (" << forward_heap.GetData( node ).parent << "," << node << ")=" << distance;
|
||||
if(reverse_heap.WasInserted(node) ){
|
||||
const int new_distance = reverse_heap.GetKey(node) + distance;
|
||||
if(new_distance < *upper_bound ){
|
||||
if( new_distance >= 0 ) {
|
||||
*middle_node_id = node;
|
||||
*upper_bound = new_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( (distance-edge_expansion_offset) > *upper_bound ){
|
||||
forward_heap.DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
//Stalling
|
||||
for(
|
||||
EdgeID edge = facade->BeginEdges( node );
|
||||
edge < facade->EndEdges(node);
|
||||
++edge
|
||||
) {
|
||||
const EdgeData & data = facade->GetEdgeData(edge);
|
||||
const bool reverse_flag = (!forward_direction) ? data.forward : data.backward;
|
||||
if( reverse_flag ) {
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG( edge_weight > 0, "edge_weight invalid" );
|
||||
|
||||
if(forward_heap.WasInserted( to )) {
|
||||
if(forward_heap.GetKey( to ) + edge_weight < distance) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(
|
||||
EdgeID edge = facade->BeginEdges(node), end_edge = facade->EndEdges(node);
|
||||
edge < end_edge;
|
||||
++edge
|
||||
) {
|
||||
const EdgeData & data = facade->GetEdgeData(edge);
|
||||
bool forward_directionFlag = (forward_direction ? data.forward : data.backward );
|
||||
if( forward_directionFlag ) {
|
||||
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG( edge_weight > 0, "edge_weight invalid" );
|
||||
const int to_distance = distance + edge_weight;
|
||||
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !forward_heap.WasInserted( to ) ) {
|
||||
forward_heap.Insert( to, to_distance, node );
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( to_distance < forward_heap.GetKey( to ) ) {
|
||||
forward_heap.GetData( to ).parent = node;
|
||||
forward_heap.DecreaseKey( to, to_distance );
|
||||
//new parent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void UnpackPath(
|
||||
const std::vector<NodeID> & packed_path,
|
||||
std::vector<_PathData> & unpacked_path
|
||||
) const {
|
||||
const unsigned packed_path_size = packed_path.size();
|
||||
std::stack<std::pair<NodeID, NodeID> > recursion_stack;
|
||||
|
||||
//We have to push the path in reverse order onto the stack because it's LIFO.
|
||||
for(unsigned i = packed_path_size-1; i > 0; --i){
|
||||
recursion_stack.push(
|
||||
std::make_pair(packed_path[i-1], packed_path[i])
|
||||
);
|
||||
}
|
||||
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while(!recursion_stack.empty()) {
|
||||
edge = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = INT_MAX;
|
||||
for(
|
||||
EdgeID edge_id = facade->BeginEdges(edge.first);
|
||||
edge_id < facade->EndEdges(edge.first);
|
||||
++edge_id
|
||||
){
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if(
|
||||
(facade->GetTarget(edge_id) == edge.second) &&
|
||||
(weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).forward
|
||||
){
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
if( SPECIAL_EDGEID == smaller_edge_id ){
|
||||
for(
|
||||
EdgeID edge_id = facade->BeginEdges(edge.second);
|
||||
edge_id < facade->EndEdges(edge.second);
|
||||
++edge_id
|
||||
){
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if(
|
||||
(facade->GetTarget(edge_id) == edge.first) &&
|
||||
(weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).backward
|
||||
){
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT_MSG(edge_weight != INT_MAX, "edge id invalid");
|
||||
|
||||
const EdgeData& ed = facade->GetEdgeData(smaller_edge_id);
|
||||
if( ed.shortcut ) {//unpack
|
||||
const NodeID middle_node_id = ed.id;
|
||||
//again, we need to this in reversed order
|
||||
recursion_stack.push(std::make_pair(middle_node_id, edge.second));
|
||||
recursion_stack.push(std::make_pair(edge.first, middle_node_id));
|
||||
} else {
|
||||
BOOST_ASSERT_MSG(!ed.shortcut, "edge must be a shortcut");
|
||||
unpacked_path.push_back(
|
||||
_PathData(
|
||||
ed.id,
|
||||
facade->GetNameIndexFromEdgeID(ed.id),
|
||||
facade->GetTurnInstructionForEdgeID(ed.id),
|
||||
ed.distance
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void UnpackEdge(
|
||||
const NodeID s,
|
||||
const NodeID t,
|
||||
std::vector<NodeID> & unpacked_path
|
||||
) const {
|
||||
std::stack<std::pair<NodeID, NodeID> > recursion_stack;
|
||||
recursion_stack.push(std::make_pair(s,t));
|
||||
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while(!recursion_stack.empty()) {
|
||||
edge = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = INT_MAX;
|
||||
for(
|
||||
EdgeID edge_id = facade->BeginEdges(edge.first);
|
||||
edge_id < facade->EndEdges(edge.first);
|
||||
++edge_id
|
||||
){
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if(
|
||||
(facade->GetTarget(edge_id) == edge.second) &&
|
||||
(weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).forward
|
||||
){
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
if( SPECIAL_EDGEID == smaller_edge_id ){
|
||||
for(
|
||||
EdgeID edge_id = facade->BeginEdges(edge.second);
|
||||
edge_id < facade->EndEdges(edge.second);
|
||||
++edge_id
|
||||
){
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if(
|
||||
(facade->GetTarget(edge_id) == edge.first) &&
|
||||
(weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).backward
|
||||
){
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT_MSG(edge_weight != INT_MAX, "edge weight invalid");
|
||||
|
||||
const EdgeData& ed = facade->GetEdgeData(smaller_edge_id);
|
||||
if(ed.shortcut) {//unpack
|
||||
const NodeID middle_node_id = ed.id;
|
||||
//again, we need to this in reversed order
|
||||
recursion_stack.push(
|
||||
std::make_pair(middle_node_id, edge.second)
|
||||
);
|
||||
recursion_stack.push(
|
||||
std::make_pair(edge.first, middle_node_id)
|
||||
);
|
||||
} else {
|
||||
BOOST_ASSERT_MSG(!ed.shortcut, "edge must be shortcut");
|
||||
unpacked_path.push_back(edge.first );
|
||||
}
|
||||
}
|
||||
unpacked_path.push_back(t);
|
||||
}
|
||||
|
||||
inline void RetrievePackedPathFromHeap(
|
||||
SearchEngineData::QueryHeap & forward_heap,
|
||||
SearchEngineData::QueryHeap & reverse_heap,
|
||||
const NodeID middle_node_id,
|
||||
std::vector<NodeID> & packed_path
|
||||
) const {
|
||||
NodeID current_node_id = middle_node_id;
|
||||
while(current_node_id != forward_heap.GetData(current_node_id).parent) {
|
||||
current_node_id = forward_heap.GetData(current_node_id).parent;
|
||||
packed_path.push_back(current_node_id);
|
||||
}
|
||||
|
||||
std::reverse(packed_path.begin(), packed_path.end());
|
||||
packed_path.push_back(middle_node_id);
|
||||
current_node_id = middle_node_id;
|
||||
while (current_node_id != reverse_heap.GetData(current_node_id).parent){
|
||||
current_node_id = reverse_heap.GetData(current_node_id).parent;
|
||||
packed_path.push_back(current_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: reorder parameters
|
||||
inline void RetrievePackedPathFromSingleHeap(
|
||||
SearchEngineData::QueryHeap & search_heap,
|
||||
const NodeID middle_node_id,
|
||||
std::vector<NodeID>& packed_path
|
||||
) const {
|
||||
NodeID current_node_id = middle_node_id;
|
||||
while(current_node_id != search_heap.GetData(current_node_id).parent) {
|
||||
current_node_id = search_heap.GetData(current_node_id).parent;
|
||||
packed_path.push_back(current_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
int ComputeEdgeOffset(const PhantomNode & phantom) const {
|
||||
return phantom.weight1 + (phantom.isBidirected() ? phantom.weight2 : 0);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* BASICROUTINGINTERFACE_H_ */
|
||||
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHORTESTPATHROUTING_H_
|
||||
#define SHORTESTPATHROUTING_H_
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include "BasicRoutingInterface.h"
|
||||
#include "../DataStructures/SearchEngineData.h"
|
||||
|
||||
template<class DataFacadeT>
|
||||
class ShortestPathRouting : public BasicRoutingInterface<DataFacadeT>{
|
||||
typedef BasicRoutingInterface<DataFacadeT> super;
|
||||
typedef SearchEngineData::QueryHeap QueryHeap;
|
||||
SearchEngineData & engine_working_data;
|
||||
|
||||
public:
|
||||
ShortestPathRouting(
|
||||
DataFacadeT * facade,
|
||||
SearchEngineData & engine_working_data
|
||||
) :
|
||||
super(facade),
|
||||
engine_working_data(engine_working_data)
|
||||
{}
|
||||
|
||||
~ShortestPathRouting() {}
|
||||
|
||||
void operator()(
|
||||
std::vector<PhantomNodes> & phantom_nodes_vector,
|
||||
RawRouteData & raw_route_data
|
||||
) const {
|
||||
BOOST_FOREACH(
|
||||
const PhantomNodes & phantom_node_pair,
|
||||
phantom_nodes_vector
|
||||
){
|
||||
if(!phantom_node_pair.AtLeastOnePhantomNodeIsUINTMAX()) {
|
||||
raw_route_data.lengthOfShortestPath = INT_MAX;
|
||||
raw_route_data.lengthOfAlternativePath = INT_MAX;
|
||||
return;
|
||||
}
|
||||
}
|
||||
int distance1 = 0;
|
||||
int distance2 = 0;
|
||||
|
||||
bool search_from_1st_node = true;
|
||||
bool search_from_2nd_node = true;
|
||||
NodeID middle1 = UINT_MAX;
|
||||
NodeID middle2 = UINT_MAX;
|
||||
std::vector<NodeID> packed_path1;
|
||||
std::vector<NodeID> packed_path2;
|
||||
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
engine_working_data.InitializeOrClearThirdThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes()
|
||||
);
|
||||
|
||||
QueryHeap & forward_heap1 = *(engine_working_data.forwardHeap);
|
||||
QueryHeap & reverse_heap1 = *(engine_working_data.backwardHeap);
|
||||
QueryHeap & forward_heap2 = *(engine_working_data.forwardHeap2);
|
||||
QueryHeap & reverse_heap2 = *(engine_working_data.backwardHeap2);
|
||||
|
||||
//Get distance to next pair of target nodes.
|
||||
BOOST_FOREACH(
|
||||
const PhantomNodes & phantom_node_pair,
|
||||
phantom_nodes_vector
|
||||
){
|
||||
forward_heap1.Clear(); forward_heap2.Clear();
|
||||
reverse_heap1.Clear(); reverse_heap2.Clear();
|
||||
int local_upper_bound1 = INT_MAX;
|
||||
int local_upper_bound2 = INT_MAX;
|
||||
|
||||
middle1 = UINT_MAX;
|
||||
middle2 = UINT_MAX;
|
||||
|
||||
//insert new starting nodes into forward heap, adjusted by previous distances.
|
||||
if(search_from_1st_node) {
|
||||
forward_heap1.Insert(
|
||||
phantom_node_pair.startPhantom.edgeBasedNode,
|
||||
distance1-phantom_node_pair.startPhantom.weight1,
|
||||
phantom_node_pair.startPhantom.edgeBasedNode
|
||||
);
|
||||
// INFO("fw1: " << phantom_node_pair.startPhantom.edgeBasedNode << "´, w: " << -phantomNodePair.startPhantom.weight1);
|
||||
forward_heap2.Insert(
|
||||
phantom_node_pair.startPhantom.edgeBasedNode,
|
||||
distance1-phantom_node_pair.startPhantom.weight1,
|
||||
phantom_node_pair.startPhantom.edgeBasedNode
|
||||
);
|
||||
// INFO("fw2: " << phantom_node_pair.startPhantom.edgeBasedNode << "´, w: " << -phantomNodePair.startPhantom.weight1);
|
||||
}
|
||||
if(phantom_node_pair.startPhantom.isBidirected() && search_from_2nd_node) {
|
||||
forward_heap1.Insert(
|
||||
phantom_node_pair.startPhantom.edgeBasedNode+1,
|
||||
distance2-phantom_node_pair.startPhantom.weight2,
|
||||
phantom_node_pair.startPhantom.edgeBasedNode+1
|
||||
);
|
||||
// INFO("fw1: " << phantom_node_pair.startPhantom.edgeBasedNode+1 << "´, w: " << -phantomNodePair.startPhantom.weight2);
|
||||
forward_heap2.Insert(
|
||||
phantom_node_pair.startPhantom.edgeBasedNode+1,
|
||||
distance2-phantom_node_pair.startPhantom.weight2,
|
||||
phantom_node_pair.startPhantom.edgeBasedNode+1
|
||||
);
|
||||
// INFO("fw2: " << phantom_node_pair.startPhantom.edgeBasedNode+1 << "´, w: " << -phantomNodePair.startPhantom.weight2);
|
||||
}
|
||||
|
||||
//insert new backward nodes into backward heap, unadjusted.
|
||||
reverse_heap1.Insert(
|
||||
phantom_node_pair.targetPhantom.edgeBasedNode,
|
||||
phantom_node_pair.targetPhantom.weight1,
|
||||
phantom_node_pair.targetPhantom.edgeBasedNode
|
||||
);
|
||||
// INFO("rv1: " << phantom_node_pair.targetPhantom.edgeBasedNode << ", w;" << phantom_node_pair.targetPhantom.weight1 );
|
||||
if(phantom_node_pair.targetPhantom.isBidirected() ) {
|
||||
reverse_heap2.Insert(
|
||||
phantom_node_pair.targetPhantom.edgeBasedNode+1,
|
||||
phantom_node_pair.targetPhantom.weight2,
|
||||
phantom_node_pair.targetPhantom.edgeBasedNode+1
|
||||
);
|
||||
// INFO("rv2: " << phantom_node_pair.targetPhantom.edgeBasedNode+1 << ", w;" << phantom_node_pair.targetPhantom.weight2 );
|
||||
}
|
||||
const int forward_offset = super::ComputeEdgeOffset(
|
||||
phantom_node_pair.startPhantom
|
||||
);
|
||||
const int reverse_offset = super::ComputeEdgeOffset(
|
||||
phantom_node_pair.targetPhantom
|
||||
);
|
||||
|
||||
//run two-Target Dijkstra routing step.
|
||||
while(0 < (forward_heap1.Size() + reverse_heap1.Size() )){
|
||||
if( !forward_heap1.Empty()){
|
||||
super::RoutingStep(
|
||||
forward_heap1,
|
||||
reverse_heap1,
|
||||
&middle1,
|
||||
&local_upper_bound1,
|
||||
forward_offset,
|
||||
true
|
||||
);
|
||||
}
|
||||
if( !reverse_heap1.Empty() ){
|
||||
super::RoutingStep(
|
||||
reverse_heap1,
|
||||
forward_heap1,
|
||||
&middle1,
|
||||
&local_upper_bound1,
|
||||
reverse_offset,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
if( !reverse_heap2.Empty() ) {
|
||||
while(0 < (forward_heap2.Size() + reverse_heap2.Size() )){
|
||||
if( !forward_heap2.Empty() ){
|
||||
super::RoutingStep(
|
||||
forward_heap2,
|
||||
reverse_heap2,
|
||||
&middle2,
|
||||
&local_upper_bound2,
|
||||
forward_offset,
|
||||
true
|
||||
);
|
||||
}
|
||||
if( !reverse_heap2.Empty() ){
|
||||
super::RoutingStep(
|
||||
reverse_heap2,
|
||||
forward_heap2,
|
||||
&middle2,
|
||||
&local_upper_bound2,
|
||||
reverse_offset,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//No path found for both target nodes?
|
||||
if(
|
||||
(INT_MAX == local_upper_bound1) &&
|
||||
(INT_MAX == local_upper_bound2)
|
||||
) {
|
||||
raw_route_data.lengthOfShortestPath = INT_MAX;
|
||||
raw_route_data.lengthOfAlternativePath = INT_MAX;
|
||||
return;
|
||||
}
|
||||
if(UINT_MAX == middle1) {
|
||||
search_from_1st_node = false;
|
||||
}
|
||||
if(UINT_MAX == middle2) {
|
||||
search_from_2nd_node = false;
|
||||
}
|
||||
|
||||
//Was at most one of the two paths not found?
|
||||
BOOST_ASSERT_MSG(
|
||||
(INT_MAX != distance1 || INT_MAX != distance2),
|
||||
"no path found"
|
||||
);
|
||||
|
||||
//Unpack paths if they exist
|
||||
std::vector<NodeID> temporary_packed_path1;
|
||||
std::vector<NodeID> temporary_packed_path2;
|
||||
if(INT_MAX != local_upper_bound1) {
|
||||
super::RetrievePackedPathFromHeap(
|
||||
forward_heap1,
|
||||
reverse_heap1,
|
||||
middle1,
|
||||
temporary_packed_path1
|
||||
);
|
||||
}
|
||||
|
||||
if(INT_MAX != local_upper_bound2) {
|
||||
super::RetrievePackedPathFromHeap(
|
||||
forward_heap2,
|
||||
reverse_heap2,
|
||||
middle2,
|
||||
temporary_packed_path2
|
||||
);
|
||||
}
|
||||
|
||||
//if one of the paths was not found, replace it with the other one.
|
||||
if( temporary_packed_path1.empty() ) {
|
||||
temporary_packed_path1.insert(
|
||||
temporary_packed_path1.end(),
|
||||
temporary_packed_path2.begin(),
|
||||
temporary_packed_path2.end()
|
||||
);
|
||||
local_upper_bound1 = local_upper_bound2;
|
||||
}
|
||||
if( temporary_packed_path2.empty() ) {
|
||||
temporary_packed_path2.insert(
|
||||
temporary_packed_path2.end(),
|
||||
temporary_packed_path1.begin(),
|
||||
temporary_packed_path1.end()
|
||||
);
|
||||
local_upper_bound2 = local_upper_bound1;
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(
|
||||
!temporary_packed_path1.empty() ||
|
||||
!temporary_packed_path2.empty(),
|
||||
"tempory packed paths empty"
|
||||
);
|
||||
|
||||
//Plug paths together, s.t. end of packed path is begin of temporary packed path
|
||||
if( !packed_path1.empty() && !packed_path2.empty() ) {
|
||||
if(
|
||||
temporary_packed_path1.front() ==
|
||||
temporary_packed_path2.front()
|
||||
) {
|
||||
//both new route segments start with the same node
|
||||
//thus, one of the packedPath must go.
|
||||
BOOST_ASSERT_MSG(
|
||||
(packed_path1.size() == packed_path2.size() ) ||
|
||||
(packed_path1.back() != packed_path2.back() ),
|
||||
"packed paths must be different"
|
||||
);
|
||||
|
||||
if( packed_path1.back() == temporary_packed_path1.front()) {
|
||||
packed_path2.clear();
|
||||
packed_path2.insert(
|
||||
packed_path2.end(),
|
||||
packed_path1.begin(),
|
||||
packed_path1.end()
|
||||
);
|
||||
} else {
|
||||
packed_path1.clear();
|
||||
packed_path1.insert(
|
||||
packed_path1.end(),
|
||||
packed_path2.begin(),
|
||||
packed_path2.end()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
//packed paths 1 and 2 may need to switch.
|
||||
if( packed_path1.back() != temporary_packed_path1.front()) {
|
||||
packed_path1.swap(packed_path2);
|
||||
std::swap(distance1, distance2);
|
||||
}
|
||||
}
|
||||
}
|
||||
packed_path1.insert(
|
||||
packed_path1.end(),
|
||||
temporary_packed_path1.begin(),
|
||||
temporary_packed_path1.end()
|
||||
);
|
||||
packed_path2.insert(
|
||||
packed_path2.end(),
|
||||
temporary_packed_path2.begin(),
|
||||
temporary_packed_path2.end()
|
||||
);
|
||||
|
||||
if(
|
||||
(packed_path1.back() == packed_path2.back()) &&
|
||||
phantom_node_pair.targetPhantom.isBidirected()
|
||||
) {
|
||||
const NodeID last_node_id = packed_path2.back();
|
||||
search_from_1st_node &= !(last_node_id == phantom_node_pair.targetPhantom.edgeBasedNode+1);
|
||||
search_from_2nd_node &= !(last_node_id == phantom_node_pair.targetPhantom.edgeBasedNode);
|
||||
}
|
||||
|
||||
distance1 = local_upper_bound1;
|
||||
distance2 = local_upper_bound2;
|
||||
}
|
||||
|
||||
if( distance1 > distance2 ) {
|
||||
std::swap( packed_path1, packed_path2 );
|
||||
}
|
||||
remove_consecutive_duplicates_from_vector(packed_path1);
|
||||
super::UnpackPath(packed_path1, raw_route_data.computedShortestPath);
|
||||
raw_route_data.lengthOfShortestPath = std::min(distance1, distance2);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SHORTESTPATHROUTING_H_ */
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef APIGRAMMAR_H_
|
||||
#define APIGRAMMAR_H_
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/spirit/include/qi_action.hpp>
|
||||
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
template <typename Iterator, class HandlerT>
|
||||
struct APIGrammar : qi::grammar<Iterator> {
|
||||
APIGrammar(HandlerT * h) : APIGrammar::base_type(api_call), handler(h) {
|
||||
api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >> *(query);
|
||||
query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | cmp | language | instruction | geometry | alt_route | old_API) ) ;
|
||||
|
||||
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >> qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
|
||||
output = (-qi::lit('&')) >> qi::lit("output") >> '=' >> string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
|
||||
jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >> stringwithDot[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
|
||||
checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::int_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
|
||||
instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >> qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
|
||||
geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >> qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
|
||||
cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >> qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
|
||||
location = (-qi::lit('&')) >> qi::lit("loc") >> '=' >> (qi::double_ >> qi::lit(',') >> qi::double_)[boost::bind(&HandlerT::addCoordinate, handler, ::_1)];
|
||||
hint = (-qi::lit('&')) >> qi::lit("hint") >> '=' >> stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
|
||||
language = (-qi::lit('&')) >> qi::lit("hl") >> '=' >> string[boost::bind(&HandlerT::setLanguage, handler, ::_1)];
|
||||
alt_route = (-qi::lit('&')) >> qi::lit("alt") >> '=' >> qi::bool_[boost::bind(&HandlerT::setAlternateRouteFlag, handler, ::_1)];
|
||||
old_API = (-qi::lit('&')) >> qi::lit("geomformat") >> '=' >> string[boost::bind(&HandlerT::setDeprecatedAPIFlag, handler, ::_1)];
|
||||
|
||||
string = +(qi::char_("a-zA-Z"));
|
||||
stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
|
||||
}
|
||||
qi::rule<Iterator> api_call, query;
|
||||
qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location, hint,
|
||||
stringwithDot, language, instruction, geometry,
|
||||
cmp, alt_route, old_API;
|
||||
|
||||
HandlerT * handler;
|
||||
};
|
||||
|
||||
|
||||
#endif /* APIGRAMMAR_H_ */
|
||||
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CONNECTION_H
|
||||
#define CONNECTION_H
|
||||
|
||||
#include "Http/CompressionType.h"
|
||||
#include "RequestHandler.h"
|
||||
#include "RequestParser.h"
|
||||
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
#include <boost/iostreams/filter/gzip.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
|
||||
// #include <zlib.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace http {
|
||||
|
||||
/// Represents a single connection from a client.
|
||||
class Connection : public boost::enable_shared_from_this<Connection>,
|
||||
private boost::noncopyable {
|
||||
public:
|
||||
explicit Connection(
|
||||
boost::asio::io_service& io_service,
|
||||
RequestHandler& handler
|
||||
) : strand(io_service), TCP_socket(io_service), request_handler(handler) { }
|
||||
|
||||
boost::asio::ip::tcp::socket& socket() {
|
||||
return TCP_socket;
|
||||
}
|
||||
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
void start() {
|
||||
TCP_socket.async_read_some(
|
||||
boost::asio::buffer(incoming_data_buffer),
|
||||
strand.wrap( boost::bind(
|
||||
&Connection::handle_read,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
void handle_read(
|
||||
const boost::system::error_code& e,
|
||||
std::size_t bytes_transferred
|
||||
) {
|
||||
if( !e ) {
|
||||
CompressionType compression_type(noCompression);
|
||||
boost::tribool result;
|
||||
boost::tie(result, boost::tuples::ignore) = request_parser.Parse(
|
||||
request,
|
||||
incoming_data_buffer.data(),
|
||||
incoming_data_buffer.data() + bytes_transferred,
|
||||
&compression_type
|
||||
);
|
||||
|
||||
if( result ) {
|
||||
request.endpoint = TCP_socket.remote_endpoint().address();
|
||||
request_handler.handle_request(request, reply);
|
||||
|
||||
Header compression_header;
|
||||
std::vector<char> compressed_output;
|
||||
std::vector<boost::asio::const_buffer> output_buffer;
|
||||
switch(compression_type) {
|
||||
case deflateRFC1951:
|
||||
compression_header.name = "Content-Encoding";
|
||||
compression_header.value = "deflate";
|
||||
reply.headers.insert(
|
||||
reply.headers.begin(),
|
||||
compression_header
|
||||
);
|
||||
compressBufferCollection(
|
||||
reply.content,
|
||||
compression_type,
|
||||
compressed_output
|
||||
);
|
||||
reply.setSize(compressed_output.size());
|
||||
output_buffer = reply.HeaderstoBuffers();
|
||||
output_buffer.push_back(
|
||||
boost::asio::buffer(compressed_output)
|
||||
);
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
output_buffer,
|
||||
strand.wrap(
|
||||
boost::bind(
|
||||
&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
)
|
||||
);
|
||||
break;
|
||||
case gzipRFC1952:
|
||||
compression_header.name = "Content-Encoding";
|
||||
compression_header.value = "gzip";
|
||||
reply.headers.insert(
|
||||
reply.headers.begin(),
|
||||
compression_header
|
||||
);
|
||||
compressBufferCollection(
|
||||
reply.content,
|
||||
compression_type,
|
||||
compressed_output
|
||||
);
|
||||
reply.setSize(compressed_output.size());
|
||||
output_buffer = reply.HeaderstoBuffers();
|
||||
output_buffer.push_back(
|
||||
boost::asio::buffer(compressed_output)
|
||||
);
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
output_buffer,
|
||||
strand.wrap(
|
||||
boost::bind(
|
||||
&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
)
|
||||
);
|
||||
break;
|
||||
case noCompression:
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
reply.toBuffers(),
|
||||
strand.wrap(
|
||||
boost::bind(
|
||||
&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
} else if (!result) {
|
||||
reply = Reply::StockReply(Reply::badRequest);
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
reply.toBuffers(),
|
||||
strand.wrap(
|
||||
boost::bind(
|
||||
&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
TCP_socket.async_read_some(
|
||||
boost::asio::buffer(incoming_data_buffer),
|
||||
strand.wrap(
|
||||
boost::bind(
|
||||
&Connection::handle_read,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle completion of a write operation.
|
||||
void handle_write(const boost::system::error_code& e) {
|
||||
if (!e) {
|
||||
// Initiate graceful connection closure.
|
||||
boost::system::error_code ignoredEC;
|
||||
TCP_socket.shutdown(
|
||||
boost::asio::ip::tcp::socket::shutdown_both,
|
||||
ignoredEC
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void compressBufferCollection(
|
||||
std::vector<std::string> uncompressed_data,
|
||||
CompressionType compression_type,
|
||||
std::vector<char> & compressed_data
|
||||
) {
|
||||
boost::iostreams::gzip_params compression_parameters;
|
||||
|
||||
compression_parameters.level = boost::iostreams::zlib::best_speed;
|
||||
if ( deflateRFC1951 == compression_type ) {
|
||||
compression_parameters.noheader = true;
|
||||
}
|
||||
|
||||
BOOST_ASSERT( compressed_data.empty() );
|
||||
boost::iostreams::filtering_ostream compressing_stream;
|
||||
|
||||
compressing_stream.push(
|
||||
boost::iostreams::gzip_compressor(compression_parameters)
|
||||
);
|
||||
compressing_stream.push(
|
||||
boost::iostreams::back_inserter(compressed_data)
|
||||
);
|
||||
|
||||
BOOST_FOREACH( const std::string & line, uncompressed_data) {
|
||||
compressing_stream << line;
|
||||
}
|
||||
|
||||
compressing_stream.reset();
|
||||
}
|
||||
|
||||
// Big thanks to deusty who explains how to use gzip compression by
|
||||
// the right call to deflateInit2():
|
||||
// http://deusty.blogspot.com/2007/07/gzip-compressiondecompression.html
|
||||
// void compressCharArray(
|
||||
// const char * in_data,
|
||||
// size_t in_data_size,
|
||||
// std::vector<unsigned char> & buffer,
|
||||
// CompressionType type
|
||||
// ) {
|
||||
// const size_t BUFSIZE = 128 * 1024;
|
||||
// unsigned char temp_buffer[BUFSIZE];
|
||||
|
||||
// z_stream strm;
|
||||
// strm.zalloc = Z_NULL;
|
||||
// strm.zfree = Z_NULL;
|
||||
// strm.opaque = Z_NULL;
|
||||
// strm.total_out = 0;
|
||||
// strm.next_in = (unsigned char *)(in_data);
|
||||
// strm.avail_in = in_data_size;
|
||||
// strm.next_out = temp_buffer;
|
||||
// strm.avail_out = BUFSIZE;
|
||||
// strm.data_type = Z_ASCII;
|
||||
|
||||
// switch(type){
|
||||
// case deflateRFC1951:
|
||||
// deflateInit(&strm, Z_BEST_SPEED);
|
||||
// break;
|
||||
// case gzipRFC1952:
|
||||
// deflateInit2(
|
||||
// &strm,
|
||||
// Z_DEFAULT_COMPRESSION,
|
||||
// Z_DEFLATED,
|
||||
// (15+16),
|
||||
// 9,
|
||||
// Z_DEFAULT_STRATEGY
|
||||
// );
|
||||
// break;
|
||||
// default:
|
||||
// BOOST_ASSERT_MSG(false, "should not happen");
|
||||
// break;
|
||||
// }
|
||||
|
||||
// int deflate_res = Z_OK;
|
||||
// do {
|
||||
// if ( 0 == strm.avail_out ) {
|
||||
// buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUFSIZE);
|
||||
// strm.next_out = temp_buffer;
|
||||
// strm.avail_out = BUFSIZE;
|
||||
// }
|
||||
// deflate_res = deflate(&strm, Z_FINISH);
|
||||
|
||||
// } while (deflate_res == Z_OK);
|
||||
|
||||
// BOOST_ASSERT_MSG(
|
||||
// deflate_res == Z_STREAM_END,
|
||||
// "compression not properly finished"
|
||||
// );
|
||||
|
||||
// buffer.insert(
|
||||
// buffer.end(),
|
||||
// temp_buffer,
|
||||
// temp_buffer + BUFSIZE - strm.avail_out
|
||||
// );
|
||||
// deflateEnd(&strm);
|
||||
// }
|
||||
|
||||
boost::asio::io_service::strand strand;
|
||||
boost::asio::ip::tcp::socket TCP_socket;
|
||||
RequestHandler& request_handler;
|
||||
boost::array<char, 8192> incoming_data_buffer;
|
||||
Request request;
|
||||
RequestParser request_parser;
|
||||
Reply reply;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif // CONNECTION_H
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef QUERY_DATA_FACADE_H
|
||||
#define QUERY_DATA_FACADE_H
|
||||
|
||||
//Exposes all data access interfaces to the algorithms via base class ptr
|
||||
|
||||
#include "../../DataStructures/Coordinate.h"
|
||||
#include "../../DataStructures/EdgeBasedNode.h"
|
||||
#include "../../DataStructures/ImportNode.h"
|
||||
#include "../../DataStructures/PhantomNodes.h"
|
||||
#include "../../DataStructures/TurnInstructions.h"
|
||||
#include "../../Util/OSRMException.h"
|
||||
#include "../../Util/StringUtil.h"
|
||||
#include "../../typedefs.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
template<class EdgeDataT>
|
||||
class BaseDataFacade {
|
||||
public:
|
||||
typedef EdgeBasedNode RTreeLeaf;
|
||||
typedef EdgeDataT EdgeData;
|
||||
BaseDataFacade( ) { }
|
||||
virtual ~BaseDataFacade() { }
|
||||
|
||||
//search graph access
|
||||
virtual unsigned GetNumberOfNodes() const = 0;
|
||||
|
||||
virtual unsigned GetNumberOfEdges() const = 0;
|
||||
|
||||
virtual unsigned GetOutDegree( const NodeID n ) const = 0;
|
||||
|
||||
virtual NodeID GetTarget( const EdgeID e ) const = 0;
|
||||
|
||||
virtual EdgeDataT &GetEdgeData( const EdgeID e ) = 0;
|
||||
|
||||
// virtual const EdgeDataT &GetEdgeData( const EdgeID e ) const = 0;
|
||||
|
||||
virtual EdgeID BeginEdges( const NodeID n ) const = 0;
|
||||
|
||||
virtual EdgeID EndEdges( const NodeID n ) const = 0;
|
||||
|
||||
//searches for a specific edge
|
||||
virtual EdgeID FindEdge( const NodeID from, const NodeID to ) const = 0;
|
||||
|
||||
virtual EdgeID FindEdgeInEitherDirection(
|
||||
const NodeID from,
|
||||
const NodeID to
|
||||
) const = 0;
|
||||
|
||||
virtual EdgeID FindEdgeIndicateIfReverse(
|
||||
const NodeID from,
|
||||
const NodeID to,
|
||||
bool & result
|
||||
) const = 0;
|
||||
|
||||
//node and edge information access
|
||||
virtual FixedPointCoordinate GetCoordinateOfNode(
|
||||
const unsigned id
|
||||
) const = 0;
|
||||
|
||||
virtual TurnInstruction GetTurnInstructionForEdgeID(
|
||||
const unsigned id
|
||||
) const = 0;
|
||||
|
||||
virtual bool LocateClosestEndPointForCoordinate(
|
||||
const FixedPointCoordinate& input_coordinate,
|
||||
FixedPointCoordinate& result,
|
||||
const unsigned zoom_level = 18
|
||||
) const = 0;
|
||||
|
||||
virtual bool FindPhantomNodeForCoordinate(
|
||||
const FixedPointCoordinate & input_coordinate,
|
||||
PhantomNode & resulting_phantom_node,
|
||||
const unsigned zoom_level
|
||||
) const = 0;
|
||||
|
||||
virtual unsigned GetCheckSum() const = 0;
|
||||
|
||||
virtual unsigned GetNameIndexFromEdgeID(const unsigned id) const = 0;
|
||||
|
||||
virtual void GetName(
|
||||
const unsigned name_id,
|
||||
std::string & result
|
||||
) const = 0;
|
||||
|
||||
std::string GetEscapedNameForNameID(const unsigned name_id) const {
|
||||
std::string temporary_string;
|
||||
GetName(name_id, temporary_string);
|
||||
return HTMLEntitize(temporary_string);
|
||||
}
|
||||
|
||||
virtual std::string GetTimestamp() const = 0;
|
||||
};
|
||||
|
||||
#endif // QUERY_DATA_FACADE_H
|
||||
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INTERNAL_DATA_FACADE
|
||||
#define INTERNAL_DATA_FACADE
|
||||
|
||||
//implements all data storage when shared memory is _NOT_ used
|
||||
|
||||
#include "BaseDataFacade.h"
|
||||
|
||||
#include "../../DataStructures/Coordinate.h"
|
||||
#include "../../DataStructures/QueryNode.h"
|
||||
#include "../../DataStructures/QueryEdge.h"
|
||||
#include "../../DataStructures/SharedMemoryVectorWrapper.h"
|
||||
#include "../../DataStructures/StaticGraph.h"
|
||||
#include "../../DataStructures/StaticRTree.h"
|
||||
#include "../../Util/BoostFileSystemFix.h"
|
||||
#include "../../Util/GraphLoader.h"
|
||||
#include "../../Util/IniFile.h"
|
||||
#include "../../Util/ProgramOptions.h"
|
||||
#include "../../Util/SimpleLogger.h"
|
||||
|
||||
template<class EdgeDataT>
|
||||
class InternalDataFacade : public BaseDataFacade<EdgeDataT> {
|
||||
|
||||
private:
|
||||
typedef BaseDataFacade<EdgeDataT> super;
|
||||
typedef StaticGraph<typename super::EdgeData> QueryGraph;
|
||||
typedef typename QueryGraph::InputEdge InputEdge;
|
||||
typedef typename super::RTreeLeaf RTreeLeaf;
|
||||
|
||||
InternalDataFacade() { }
|
||||
|
||||
unsigned m_check_sum;
|
||||
unsigned m_number_of_nodes;
|
||||
QueryGraph * m_query_graph;
|
||||
std::string m_timestamp;
|
||||
|
||||
ShM<FixedPointCoordinate, false>::vector m_coordinate_list;
|
||||
ShM<NodeID, false>::vector m_via_node_list;
|
||||
ShM<unsigned, false>::vector m_name_ID_list;
|
||||
ShM<TurnInstruction, false>::vector m_turn_instruction_list;
|
||||
ShM<char, false>::vector m_names_char_list;
|
||||
ShM<unsigned, false>::vector m_name_begin_indices;
|
||||
|
||||
StaticRTree<RTreeLeaf, false> * m_static_rtree;
|
||||
|
||||
|
||||
void LoadTimestamp(const boost::filesystem::path & timestamp_path) {
|
||||
if( boost::filesystem::exists(timestamp_path) ) {
|
||||
SimpleLogger().Write() << "Loading Timestamp";
|
||||
boost::filesystem::ifstream timestampInStream( timestamp_path );
|
||||
if(!timestampInStream) {
|
||||
SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
|
||||
}
|
||||
getline(timestampInStream, m_timestamp);
|
||||
timestampInStream.close();
|
||||
}
|
||||
if(m_timestamp.empty()) {
|
||||
m_timestamp = "n/a";
|
||||
}
|
||||
if(25 < m_timestamp.length()) {
|
||||
m_timestamp.resize(25);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadGraph(const boost::filesystem::path & hsgr_path) {
|
||||
typename ShM<typename QueryGraph::_StrNode, false>::vector node_list;
|
||||
typename ShM<typename QueryGraph::_StrEdge, false>::vector edge_list;
|
||||
|
||||
SimpleLogger().Write() << "loading graph from " << hsgr_path.string();
|
||||
|
||||
m_number_of_nodes = readHSGRFromStream(
|
||||
hsgr_path,
|
||||
node_list,
|
||||
edge_list,
|
||||
&m_check_sum
|
||||
);
|
||||
|
||||
BOOST_ASSERT_MSG(0 != node_list.size(), "node list empty");
|
||||
BOOST_ASSERT_MSG(0 != edge_list.size(), "edge list empty");
|
||||
SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and " << edge_list.size() << " edges";
|
||||
m_query_graph = new QueryGraph(node_list, edge_list);
|
||||
|
||||
BOOST_ASSERT_MSG(0 == node_list.size(), "node list not flushed");
|
||||
BOOST_ASSERT_MSG(0 == edge_list.size(), "edge list not flushed");
|
||||
SimpleLogger().Write() << "Data checksum is " << m_check_sum;
|
||||
}
|
||||
|
||||
void LoadNodeAndEdgeInformation(
|
||||
const boost::filesystem::path nodes_file,
|
||||
const boost::filesystem::path edges_file
|
||||
) {
|
||||
boost::filesystem::ifstream nodes_input_stream(
|
||||
nodes_file,
|
||||
std::ios::binary
|
||||
);
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "Loading node data";
|
||||
NodeInfo current_node;
|
||||
unsigned number_of_coordinates = 0;
|
||||
nodes_input_stream.read(
|
||||
(char *)&number_of_coordinates,
|
||||
sizeof(unsigned)
|
||||
);
|
||||
m_coordinate_list.resize(number_of_coordinates);
|
||||
for(unsigned i = 0; i < number_of_coordinates; ++i) {
|
||||
nodes_input_stream.read((char *)¤t_node, sizeof(NodeInfo));
|
||||
m_coordinate_list[i] = FixedPointCoordinate(
|
||||
current_node.lat,
|
||||
current_node.lon
|
||||
);
|
||||
}
|
||||
std::vector<FixedPointCoordinate>(m_coordinate_list).swap(m_coordinate_list);
|
||||
nodes_input_stream.close();
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "Loading edge data";
|
||||
boost::filesystem::ifstream edges_input_stream(
|
||||
edges_file,
|
||||
std::ios::binary
|
||||
);
|
||||
unsigned number_of_edges = 0;
|
||||
edges_input_stream.read((char*)&number_of_edges, sizeof(unsigned));
|
||||
m_via_node_list.resize(number_of_edges);
|
||||
m_name_ID_list.resize(number_of_edges);
|
||||
m_turn_instruction_list.resize(number_of_edges);
|
||||
|
||||
OriginalEdgeData current_edge_data;
|
||||
for(unsigned i = 0; i < number_of_edges; ++i) {
|
||||
edges_input_stream.read(
|
||||
(char*)&(current_edge_data),
|
||||
sizeof(OriginalEdgeData)
|
||||
);
|
||||
m_via_node_list[i] = current_edge_data.viaNode;
|
||||
m_name_ID_list[i] = current_edge_data.nameID;
|
||||
m_turn_instruction_list[i] = current_edge_data.turnInstruction;
|
||||
}
|
||||
edges_input_stream.close();
|
||||
}
|
||||
|
||||
void LoadRTree(
|
||||
const boost::filesystem::path & ram_index_path,
|
||||
const boost::filesystem::path & file_index_path
|
||||
) {
|
||||
m_static_rtree = new StaticRTree<RTreeLeaf>(
|
||||
ram_index_path,
|
||||
file_index_path
|
||||
);
|
||||
}
|
||||
|
||||
void LoadStreetNames(
|
||||
const boost::filesystem::path & names_file
|
||||
) {
|
||||
boost::filesystem::ifstream name_stream(names_file, std::ios::binary);
|
||||
unsigned number_of_names = 0;
|
||||
unsigned number_of_chars = 0;
|
||||
name_stream.read((char *)&number_of_names, sizeof(unsigned));
|
||||
name_stream.read((char *)&number_of_chars, sizeof(unsigned));
|
||||
BOOST_ASSERT_MSG(0 != number_of_names, "name file broken");
|
||||
BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
|
||||
|
||||
m_name_begin_indices.resize(number_of_names);
|
||||
name_stream.read(
|
||||
(char*)&m_name_begin_indices[0],
|
||||
number_of_names*sizeof(unsigned)
|
||||
);
|
||||
|
||||
m_names_char_list.resize(number_of_chars+1); //+1 gives sentinel element
|
||||
name_stream.read(
|
||||
(char *)&m_names_char_list[0],
|
||||
number_of_chars*sizeof(char)
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
0 != m_names_char_list.size(),
|
||||
"could not load any names"
|
||||
);
|
||||
name_stream.close();
|
||||
}
|
||||
public:
|
||||
~InternalDataFacade() {
|
||||
delete m_query_graph;
|
||||
delete m_static_rtree;
|
||||
}
|
||||
|
||||
InternalDataFacade( const ServerPaths & server_paths ) {
|
||||
//generate paths of data files
|
||||
if( server_paths.find("hsgrdata") == server_paths.end() ) {
|
||||
throw OSRMException("no hsgr file given in ini file");
|
||||
}
|
||||
if( server_paths.find("ramindex") == server_paths.end() ) {
|
||||
throw OSRMException("no ram index file given in ini file");
|
||||
}
|
||||
if( server_paths.find("fileindex") == server_paths.end() ) {
|
||||
throw OSRMException("no leaf index file given in ini file");
|
||||
}
|
||||
if( server_paths.find("nodesdata") == server_paths.end() ) {
|
||||
throw OSRMException("no nodes file given in ini file");
|
||||
}
|
||||
if( server_paths.find("edgesdata") == server_paths.end() ) {
|
||||
throw OSRMException("no edges file given in ini file");
|
||||
}
|
||||
if( server_paths.find("namesdata") == server_paths.end() ) {
|
||||
throw OSRMException("no names file given in ini file");
|
||||
}
|
||||
|
||||
ServerPaths::const_iterator paths_iterator = server_paths.find("hsgrdata");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & hsgr_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("timestamp");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & timestamp_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("ramindex");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & ram_index_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("fileindex");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & file_index_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("nodesdata");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & nodes_data_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("edgesdata");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & edges_data_path = paths_iterator->second;
|
||||
paths_iterator = server_paths.find("namesdata");
|
||||
BOOST_ASSERT(server_paths.end() != paths_iterator);
|
||||
const boost::filesystem::path & names_data_path = paths_iterator->second;
|
||||
|
||||
//load data
|
||||
SimpleLogger().Write() << "loading graph data";
|
||||
LoadGraph(hsgr_path);
|
||||
SimpleLogger().Write() << "loading egde information";
|
||||
LoadNodeAndEdgeInformation(nodes_data_path, edges_data_path);
|
||||
SimpleLogger().Write() << "loading r-tree";
|
||||
LoadRTree(ram_index_path, file_index_path);
|
||||
SimpleLogger().Write() << "loading timestamp";
|
||||
LoadTimestamp(timestamp_path);
|
||||
SimpleLogger().Write() << "loading street names";
|
||||
LoadStreetNames(names_data_path);
|
||||
}
|
||||
|
||||
//search graph access
|
||||
unsigned GetNumberOfNodes() const {
|
||||
return m_query_graph->GetNumberOfNodes();
|
||||
}
|
||||
|
||||
unsigned GetNumberOfEdges() const {
|
||||
return m_query_graph->GetNumberOfEdges();
|
||||
}
|
||||
|
||||
unsigned GetOutDegree( const NodeID n ) const {
|
||||
return m_query_graph->GetOutDegree(n);
|
||||
}
|
||||
|
||||
NodeID GetTarget( const EdgeID e ) const {
|
||||
return m_query_graph->GetTarget(e); }
|
||||
|
||||
EdgeDataT &GetEdgeData( const EdgeID e ) {
|
||||
return m_query_graph->GetEdgeData(e);
|
||||
}
|
||||
|
||||
const EdgeDataT &GetEdgeData( const EdgeID e ) const {
|
||||
return m_query_graph->GetEdgeData(e);
|
||||
}
|
||||
|
||||
EdgeID BeginEdges( const NodeID n ) const {
|
||||
return m_query_graph->BeginEdges(n);
|
||||
}
|
||||
|
||||
EdgeID EndEdges( const NodeID n ) const {
|
||||
return m_query_graph->EndEdges(n);
|
||||
}
|
||||
|
||||
//searches for a specific edge
|
||||
EdgeID FindEdge( const NodeID from, const NodeID to ) const {
|
||||
return m_query_graph->FindEdge(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeInEitherDirection(
|
||||
const NodeID from,
|
||||
const NodeID to
|
||||
) const {
|
||||
return m_query_graph->FindEdgeInEitherDirection(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeIndicateIfReverse(
|
||||
const NodeID from,
|
||||
const NodeID to,
|
||||
bool & result
|
||||
) const {
|
||||
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
||||
}
|
||||
|
||||
//node and edge information access
|
||||
FixedPointCoordinate GetCoordinateOfNode(
|
||||
const unsigned id
|
||||
) const {
|
||||
const NodeID node = m_via_node_list.at(id);
|
||||
return m_coordinate_list.at(node);
|
||||
};
|
||||
|
||||
TurnInstruction GetTurnInstructionForEdgeID(
|
||||
const unsigned id
|
||||
) const {
|
||||
return m_turn_instruction_list.at(id);
|
||||
}
|
||||
|
||||
bool LocateClosestEndPointForCoordinate(
|
||||
const FixedPointCoordinate& input_coordinate,
|
||||
FixedPointCoordinate& result,
|
||||
const unsigned zoom_level = 18
|
||||
) const {
|
||||
return m_static_rtree->LocateClosestEndPointForCoordinate(
|
||||
input_coordinate,
|
||||
result,
|
||||
zoom_level
|
||||
);
|
||||
}
|
||||
|
||||
bool FindPhantomNodeForCoordinate(
|
||||
const FixedPointCoordinate & input_coordinate,
|
||||
PhantomNode & resulting_phantom_node,
|
||||
const unsigned zoom_level
|
||||
) const {
|
||||
return m_static_rtree->FindPhantomNodeForCoordinate(
|
||||
input_coordinate,
|
||||
resulting_phantom_node,
|
||||
zoom_level
|
||||
);
|
||||
}
|
||||
|
||||
unsigned GetCheckSum() const { return m_check_sum; }
|
||||
|
||||
unsigned GetNameIndexFromEdgeID(const unsigned id) const {
|
||||
return m_name_ID_list.at(id);
|
||||
};
|
||||
|
||||
void GetName( const unsigned name_id, std::string & result ) const {
|
||||
if(UINT_MAX == name_id) {
|
||||
result = "";
|
||||
return;
|
||||
}
|
||||
BOOST_ASSERT_MSG(
|
||||
name_id < m_name_begin_indices.size(),
|
||||
"name id too high"
|
||||
);
|
||||
unsigned begin_index = m_name_begin_indices[name_id];
|
||||
unsigned end_index = m_name_begin_indices[name_id+1];
|
||||
BOOST_ASSERT_MSG(
|
||||
begin_index < m_names_char_list.size(),
|
||||
"begin index of name too high"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
end_index < m_names_char_list.size(),
|
||||
"end index of name too high"
|
||||
);
|
||||
|
||||
BOOST_ASSERT_MSG(begin_index <= end_index, "string ends before begin");
|
||||
result.clear();
|
||||
result.resize(end_index - begin_index);
|
||||
std::copy(
|
||||
m_names_char_list.begin() + begin_index,
|
||||
m_names_char_list.begin() + end_index,
|
||||
result.begin()
|
||||
);
|
||||
}
|
||||
|
||||
std::string GetTimestamp() const {
|
||||
return m_timestamp;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // INTERNAL_DATA_FACADE
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ROUTE_PARAMETERS_H
|
||||
#define ROUTE_PARAMETERS_H
|
||||
|
||||
#include "../../DataStructures/Coordinate.h"
|
||||
#include "../../DataStructures/HashTable.h"
|
||||
|
||||
#include <boost/fusion/container/vector.hpp>
|
||||
#include <boost/fusion/sequence/intrinsic.hpp>
|
||||
#include <boost/fusion/include/at_c.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct RouteParameters {
|
||||
RouteParameters() :
|
||||
zoomLevel(18),
|
||||
printInstructions(false),
|
||||
alternateRoute(true),
|
||||
geometry(true),
|
||||
compression(true),
|
||||
deprecatedAPI(false),
|
||||
checkSum(-1) {}
|
||||
short zoomLevel;
|
||||
bool printInstructions;
|
||||
bool alternateRoute;
|
||||
bool geometry;
|
||||
bool compression;
|
||||
bool deprecatedAPI;
|
||||
unsigned checkSum;
|
||||
std::string service;
|
||||
std::string outputFormat;
|
||||
std::string jsonpParameter;
|
||||
std::string language;
|
||||
std::vector<std::string> hints;
|
||||
std::vector<FixedPointCoordinate> coordinates;
|
||||
typedef HashTable<std::string, std::string>::const_iterator OptionsIterator;
|
||||
|
||||
void setZoomLevel(const short i) {
|
||||
if (18 > i && 0 < i) {
|
||||
zoomLevel = i;
|
||||
}
|
||||
}
|
||||
|
||||
void setAlternateRouteFlag(const bool b) {
|
||||
alternateRoute = b;
|
||||
}
|
||||
|
||||
void setDeprecatedAPIFlag(const std::string &) {
|
||||
deprecatedAPI = true;
|
||||
}
|
||||
|
||||
void setChecksum(const unsigned c) {
|
||||
checkSum = c;
|
||||
}
|
||||
|
||||
void setInstructionFlag(const bool b) {
|
||||
printInstructions = b;
|
||||
}
|
||||
|
||||
void setService( const std::string & s) {
|
||||
service = s;
|
||||
}
|
||||
|
||||
void setOutputFormat(const std::string & s) {
|
||||
outputFormat = s;
|
||||
}
|
||||
|
||||
void setJSONpParameter(const std::string & s) {
|
||||
jsonpParameter = s;
|
||||
}
|
||||
|
||||
void addHint(const std::string & s) {
|
||||
hints.resize(coordinates.size());
|
||||
hints.back() = s;
|
||||
}
|
||||
|
||||
void setLanguage(const std::string & s) {
|
||||
language = s;
|
||||
}
|
||||
|
||||
void setGeometryFlag(const bool b) {
|
||||
geometry = b;
|
||||
}
|
||||
|
||||
void setCompressionFlag(const bool b) {
|
||||
compression = b;
|
||||
}
|
||||
|
||||
void addCoordinate(const boost::fusion::vector < double, double > & arg_) {
|
||||
int lat = COORDINATE_PRECISION*boost::fusion::at_c < 0 > (arg_);
|
||||
int lon = COORDINATE_PRECISION*boost::fusion::at_c < 1 > (arg_);
|
||||
coordinates.push_back(FixedPointCoordinate(lat, lon));
|
||||
}
|
||||
};
|
||||
|
||||
#endif /*ROUTE_PARAMETERS_H*/
|
||||
@@ -0,0 +1,40 @@
|
||||
#include <boost/interprocess/sync/named_mutex.hpp>
|
||||
#include <boost/interprocess/sync/named_condition.hpp>
|
||||
|
||||
struct SharedBarriers {
|
||||
|
||||
SharedBarriers ()
|
||||
:
|
||||
pending_update_mutex(
|
||||
boost::interprocess::open_or_create,
|
||||
"pending_update"
|
||||
),
|
||||
update_mutex(
|
||||
boost::interprocess::open_or_create,
|
||||
"update"
|
||||
),
|
||||
query_mutex(
|
||||
boost::interprocess::open_or_create,
|
||||
"query"
|
||||
),
|
||||
no_running_queries_condition(
|
||||
boost::interprocess::open_or_create,
|
||||
"no_running_queries"
|
||||
),
|
||||
update_ongoing(false),
|
||||
number_of_queries(0)
|
||||
{ }
|
||||
|
||||
// Mutex to protect access to the boolean variable
|
||||
boost::interprocess::named_mutex pending_update_mutex;
|
||||
boost::interprocess::named_mutex update_mutex;
|
||||
boost::interprocess::named_mutex query_mutex;
|
||||
|
||||
// Condition that no update is running
|
||||
boost::interprocess::named_condition no_running_queries_condition;
|
||||
|
||||
// Is there an ongoing update?
|
||||
bool update_ongoing;
|
||||
// Is there any query?
|
||||
int number_of_queries;
|
||||
};
|
||||
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHARED_DATA_FACADE_H
|
||||
#define SHARED_DATA_FACADE_H
|
||||
|
||||
//implements all data storage when shared memory is _NOT_ used
|
||||
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "BaseDataFacade.h"
|
||||
#include "SharedDataType.h"
|
||||
|
||||
#include "../../DataStructures/StaticGraph.h"
|
||||
#include "../../DataStructures/StaticRTree.h"
|
||||
#include "../../Util/BoostFileSystemFix.h"
|
||||
#include "../../Util/ProgramOptions.h"
|
||||
#include "../../Util/SimpleLogger.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
template<class EdgeDataT>
|
||||
class SharedDataFacade : public BaseDataFacade<EdgeDataT> {
|
||||
|
||||
private:
|
||||
typedef EdgeDataT EdgeData;
|
||||
typedef BaseDataFacade<EdgeData> super;
|
||||
typedef StaticGraph<EdgeData, true> QueryGraph;
|
||||
typedef typename StaticGraph<EdgeData, true>::_StrNode GraphNode;
|
||||
typedef typename StaticGraph<EdgeData, true>::_StrEdge GraphEdge;
|
||||
typedef typename QueryGraph::InputEdge InputEdge;
|
||||
typedef typename super::RTreeLeaf RTreeLeaf;
|
||||
typedef typename StaticRTree<RTreeLeaf, true>::TreeNode RTreeNode;
|
||||
|
||||
SharedDataLayout * data_layout;
|
||||
char * shared_memory;
|
||||
SharedDataTimestamp * data_timestamp_ptr;
|
||||
|
||||
SharedDataType CURRENT_LAYOUT;
|
||||
SharedDataType CURRENT_DATA;
|
||||
unsigned CURRENT_TIMESTAMP;
|
||||
|
||||
unsigned m_check_sum;
|
||||
unsigned m_number_of_nodes;
|
||||
boost::shared_ptr<QueryGraph> m_query_graph;
|
||||
boost::shared_ptr<SharedMemory> m_layout_memory;
|
||||
boost::shared_ptr<SharedMemory> m_large_memory;
|
||||
std::string m_timestamp;
|
||||
|
||||
ShM<FixedPointCoordinate, true>::vector m_coordinate_list;
|
||||
ShM<NodeID, true>::vector m_via_node_list;
|
||||
ShM<unsigned, true>::vector m_name_ID_list;
|
||||
ShM<TurnInstruction, true>::vector m_turn_instruction_list;
|
||||
ShM<char, true>::vector m_names_char_list;
|
||||
ShM<unsigned, true>::vector m_name_begin_indices;
|
||||
boost::shared_ptr<StaticRTree<RTreeLeaf, true> > m_static_rtree;
|
||||
|
||||
// SharedDataFacade() { }
|
||||
|
||||
void LoadTimestamp() {
|
||||
char * timestamp_ptr = shared_memory + data_layout->GetTimeStampOffset();
|
||||
m_timestamp.resize(data_layout->timestamp_length);
|
||||
std::copy(
|
||||
timestamp_ptr,
|
||||
timestamp_ptr+data_layout->timestamp_length,
|
||||
m_timestamp.begin()
|
||||
);
|
||||
}
|
||||
|
||||
void LoadRTree(
|
||||
const boost::filesystem::path & file_index_path
|
||||
) {
|
||||
RTreeNode * tree_ptr = (RTreeNode *)(
|
||||
shared_memory + data_layout->GetRSearchTreeOffset()
|
||||
);
|
||||
m_static_rtree = boost::make_shared<StaticRTree<RTreeLeaf, true> >(
|
||||
tree_ptr,
|
||||
data_layout->r_search_tree_size,
|
||||
file_index_path
|
||||
);
|
||||
}
|
||||
|
||||
void LoadGraph() {
|
||||
m_number_of_nodes = data_layout->graph_node_list_size;
|
||||
GraphNode * graph_nodes_ptr = (GraphNode *)(
|
||||
shared_memory + data_layout->GetGraphNodeListOffset()
|
||||
);
|
||||
|
||||
GraphEdge * graph_edges_ptr = (GraphEdge *)(
|
||||
shared_memory + data_layout->GetGraphEdgeListOffsett()
|
||||
);
|
||||
|
||||
typename ShM<GraphNode, true>::vector node_list(
|
||||
graph_nodes_ptr,
|
||||
data_layout->graph_node_list_size
|
||||
);
|
||||
typename ShM<GraphEdge, true>::vector edge_list(
|
||||
graph_edges_ptr,
|
||||
data_layout->graph_edge_list_size
|
||||
);
|
||||
m_query_graph.reset(
|
||||
new QueryGraph(node_list, edge_list)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void LoadNodeAndEdgeInformation() {
|
||||
|
||||
FixedPointCoordinate * coordinate_list_ptr = (FixedPointCoordinate *)(
|
||||
shared_memory + data_layout->GetCoordinateListOffset()
|
||||
);
|
||||
typename ShM<FixedPointCoordinate, true>::vector coordinate_list(
|
||||
coordinate_list_ptr,
|
||||
data_layout->coordinate_list_size
|
||||
);
|
||||
m_coordinate_list.swap( coordinate_list );
|
||||
|
||||
TurnInstruction * turn_instruction_list_ptr = (TurnInstruction *)(
|
||||
shared_memory + data_layout->GetTurnInstructionListOffset()
|
||||
);
|
||||
typename ShM<TurnInstruction, true>::vector turn_instruction_list(
|
||||
turn_instruction_list_ptr,
|
||||
data_layout->turn_instruction_list_size
|
||||
);
|
||||
m_turn_instruction_list.swap(turn_instruction_list);
|
||||
|
||||
unsigned * name_id_list_ptr = (unsigned *)(
|
||||
shared_memory + data_layout->GetNameIDListOffset()
|
||||
);
|
||||
typename ShM<unsigned, true>::vector name_id_list(
|
||||
name_id_list_ptr,
|
||||
data_layout->name_id_list_size
|
||||
);
|
||||
m_name_ID_list.swap(name_id_list);
|
||||
}
|
||||
|
||||
void LoadViaNodeList() {
|
||||
NodeID * via_node_list_ptr = (NodeID *)(
|
||||
shared_memory + data_layout->GetViaNodeListOffset()
|
||||
);
|
||||
typename ShM<NodeID, true>::vector via_node_list(
|
||||
via_node_list_ptr,
|
||||
data_layout->via_node_list_size
|
||||
);
|
||||
m_via_node_list.swap(via_node_list);
|
||||
}
|
||||
|
||||
void LoadNames() {
|
||||
unsigned * street_names_index_ptr = (unsigned *)(
|
||||
shared_memory + data_layout->GetNameIndexOffset()
|
||||
);
|
||||
typename ShM<unsigned, true>::vector name_begin_indices(
|
||||
street_names_index_ptr,
|
||||
data_layout->name_index_list_size
|
||||
);
|
||||
m_name_begin_indices.swap(name_begin_indices);
|
||||
|
||||
char * names_list_ptr = (char *)(
|
||||
shared_memory + data_layout->GetNameListOffset()
|
||||
);
|
||||
typename ShM<char, true>::vector names_char_list(
|
||||
names_list_ptr,
|
||||
data_layout->name_char_list_size
|
||||
);
|
||||
m_names_char_list.swap(names_char_list);
|
||||
}
|
||||
|
||||
public:
|
||||
SharedDataFacade( ) {
|
||||
data_timestamp_ptr = (SharedDataTimestamp *)SharedMemoryFactory::Get(
|
||||
CURRENT_REGIONS,
|
||||
sizeof(SharedDataTimestamp),
|
||||
false,
|
||||
false
|
||||
)->Ptr();
|
||||
|
||||
CURRENT_LAYOUT = LAYOUT_NONE;
|
||||
CURRENT_DATA = DATA_NONE;
|
||||
CURRENT_TIMESTAMP = 0;
|
||||
|
||||
//load data
|
||||
CheckAndReloadFacade();
|
||||
}
|
||||
|
||||
void CheckAndReloadFacade() {
|
||||
if(
|
||||
CURRENT_LAYOUT != data_timestamp_ptr->layout ||
|
||||
CURRENT_DATA != data_timestamp_ptr->data ||
|
||||
CURRENT_TIMESTAMP != data_timestamp_ptr->timestamp
|
||||
) {
|
||||
// release the previous shared memory segments
|
||||
SharedMemory::Remove(CURRENT_LAYOUT);
|
||||
SharedMemory::Remove(CURRENT_DATA);
|
||||
|
||||
CURRENT_LAYOUT = data_timestamp_ptr->layout;
|
||||
CURRENT_DATA = data_timestamp_ptr->data;
|
||||
CURRENT_TIMESTAMP = data_timestamp_ptr->timestamp;
|
||||
|
||||
m_layout_memory.reset( SharedMemoryFactory::Get(CURRENT_LAYOUT) );
|
||||
|
||||
data_layout = (SharedDataLayout *)(
|
||||
m_layout_memory->Ptr()
|
||||
);
|
||||
boost::filesystem::path ram_index_path(data_layout->ram_index_file_name);
|
||||
if( !boost::filesystem::exists(ram_index_path) ) {
|
||||
throw OSRMException(
|
||||
"no leaf index file given. "
|
||||
"Is any data loaded into shared memory?"
|
||||
);
|
||||
}
|
||||
|
||||
m_large_memory.reset( SharedMemoryFactory::Get(CURRENT_DATA) );
|
||||
shared_memory = (char *)(
|
||||
m_large_memory->Ptr()
|
||||
);
|
||||
|
||||
LoadGraph();
|
||||
LoadNodeAndEdgeInformation();
|
||||
LoadRTree(ram_index_path);
|
||||
LoadTimestamp();
|
||||
LoadViaNodeList();
|
||||
LoadNames();
|
||||
|
||||
data_layout->PrintInformation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//search graph access
|
||||
unsigned GetNumberOfNodes() const {
|
||||
return m_query_graph->GetNumberOfNodes();
|
||||
}
|
||||
|
||||
unsigned GetNumberOfEdges() const {
|
||||
return m_query_graph->GetNumberOfEdges();
|
||||
}
|
||||
|
||||
unsigned GetOutDegree( const NodeID n ) const {
|
||||
return m_query_graph->GetOutDegree(n);
|
||||
}
|
||||
|
||||
NodeID GetTarget( const EdgeID e ) const {
|
||||
return m_query_graph->GetTarget(e); }
|
||||
|
||||
EdgeDataT &GetEdgeData( const EdgeID e ) {
|
||||
return m_query_graph->GetEdgeData(e);
|
||||
}
|
||||
|
||||
// const EdgeDataT &GetEdgeData( const EdgeID e ) const {
|
||||
// return m_query_graph->GetEdgeData(e);
|
||||
// }
|
||||
|
||||
EdgeID BeginEdges( const NodeID n ) const {
|
||||
return m_query_graph->BeginEdges(n);
|
||||
}
|
||||
|
||||
EdgeID EndEdges( const NodeID n ) const {
|
||||
return m_query_graph->EndEdges(n);
|
||||
}
|
||||
|
||||
//searches for a specific edge
|
||||
EdgeID FindEdge( const NodeID from, const NodeID to ) const {
|
||||
return m_query_graph->FindEdge(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeInEitherDirection(
|
||||
const NodeID from,
|
||||
const NodeID to
|
||||
) const {
|
||||
return m_query_graph->FindEdgeInEitherDirection(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeIndicateIfReverse(
|
||||
const NodeID from,
|
||||
const NodeID to,
|
||||
bool & result
|
||||
) const {
|
||||
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
||||
}
|
||||
|
||||
//node and edge information access
|
||||
FixedPointCoordinate GetCoordinateOfNode(
|
||||
const unsigned id
|
||||
) const {
|
||||
const NodeID node = m_via_node_list.at(id);
|
||||
return m_coordinate_list.at(node);
|
||||
};
|
||||
|
||||
TurnInstruction GetTurnInstructionForEdgeID(
|
||||
const unsigned id
|
||||
) const {
|
||||
return m_turn_instruction_list.at(id);
|
||||
}
|
||||
|
||||
bool LocateClosestEndPointForCoordinate(
|
||||
const FixedPointCoordinate& input_coordinate,
|
||||
FixedPointCoordinate& result,
|
||||
const unsigned zoom_level = 18
|
||||
) const {
|
||||
return m_static_rtree->LocateClosestEndPointForCoordinate(
|
||||
input_coordinate,
|
||||
result,
|
||||
zoom_level
|
||||
);
|
||||
}
|
||||
|
||||
bool FindPhantomNodeForCoordinate(
|
||||
const FixedPointCoordinate & input_coordinate,
|
||||
PhantomNode & resulting_phantom_node,
|
||||
const unsigned zoom_level
|
||||
) const {
|
||||
return m_static_rtree->FindPhantomNodeForCoordinate(
|
||||
input_coordinate,
|
||||
resulting_phantom_node,
|
||||
zoom_level
|
||||
);
|
||||
}
|
||||
|
||||
unsigned GetCheckSum() const { return m_check_sum; }
|
||||
|
||||
unsigned GetNameIndexFromEdgeID(const unsigned id) const {
|
||||
return m_name_ID_list.at(id);
|
||||
};
|
||||
|
||||
void GetName( const unsigned name_id, std::string & result ) const {
|
||||
if(UINT_MAX == name_id) {
|
||||
result = "";
|
||||
return;
|
||||
}
|
||||
BOOST_ASSERT_MSG(
|
||||
name_id < m_name_begin_indices.size(),
|
||||
"name id too high"
|
||||
);
|
||||
unsigned begin_index = m_name_begin_indices[name_id];
|
||||
unsigned end_index = m_name_begin_indices[name_id+1];
|
||||
BOOST_ASSERT_MSG(
|
||||
begin_index < m_names_char_list.size(),
|
||||
"begin index of name too high"
|
||||
);
|
||||
BOOST_ASSERT_MSG(
|
||||
end_index < m_names_char_list.size(),
|
||||
"end index of name too high"
|
||||
);
|
||||
|
||||
BOOST_ASSERT_MSG(begin_index <= end_index, "string ends before begin");
|
||||
result.clear();
|
||||
result.resize(end_index - begin_index);
|
||||
std::copy(
|
||||
m_names_char_list.begin() + begin_index,
|
||||
m_names_char_list.begin() + end_index,
|
||||
result.begin()
|
||||
);
|
||||
}
|
||||
|
||||
std::string GetTimestamp() const {
|
||||
return m_timestamp;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SHARED_DATA_FACADE_H
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SHARED_DATA_TYPE_H_
|
||||
#define SHARED_DATA_TYPE_H_
|
||||
|
||||
#include "BaseDataFacade.h"
|
||||
|
||||
#include "../../DataStructures/Coordinate.h"
|
||||
#include "../../DataStructures/QueryEdge.h"
|
||||
#include "../../DataStructures/StaticGraph.h"
|
||||
#include "../../DataStructures/StaticRTree.h"
|
||||
#include "../../DataStructures/TurnInstructions.h"
|
||||
|
||||
#include "../../typedefs.h"
|
||||
|
||||
#include <boost/integer.hpp>
|
||||
|
||||
typedef BaseDataFacade<QueryEdge::EdgeData>::RTreeLeaf RTreeLeaf;
|
||||
typedef StaticRTree<RTreeLeaf, true>::TreeNode RTreeNode;
|
||||
typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;
|
||||
|
||||
struct SharedDataLayout {
|
||||
uint64_t name_index_list_size;
|
||||
uint64_t name_char_list_size;
|
||||
uint64_t name_id_list_size;
|
||||
uint64_t via_node_list_size;
|
||||
uint64_t graph_node_list_size;
|
||||
uint64_t graph_edge_list_size;
|
||||
uint64_t coordinate_list_size;
|
||||
uint64_t turn_instruction_list_size;
|
||||
uint64_t r_search_tree_size;
|
||||
|
||||
unsigned checksum;
|
||||
unsigned timestamp_length;
|
||||
|
||||
char ram_index_file_name[1024];
|
||||
|
||||
SharedDataLayout() :
|
||||
name_index_list_size(0),
|
||||
name_char_list_size(0),
|
||||
name_id_list_size(0),
|
||||
via_node_list_size(0),
|
||||
graph_node_list_size(0),
|
||||
graph_edge_list_size(0),
|
||||
coordinate_list_size(0),
|
||||
turn_instruction_list_size(0),
|
||||
r_search_tree_size(0),
|
||||
checksum(0),
|
||||
timestamp_length(0)
|
||||
{
|
||||
ram_index_file_name[0] = '\0';
|
||||
}
|
||||
|
||||
void PrintInformation() const {
|
||||
SimpleLogger().Write(logDEBUG) << "-";
|
||||
SimpleLogger().Write(logDEBUG) << "name_index_list_size: " << name_index_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "name_char_list_size: " << name_char_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "name_id_list_size: " << name_id_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "via_node_list_size: " << via_node_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "graph_node_list_size: " << graph_node_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "graph_edge_list_size: " << graph_edge_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "timestamp_length: " << timestamp_length;
|
||||
SimpleLogger().Write(logDEBUG) << "coordinate_list_size: " << coordinate_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "turn_instruction_list_size: " << turn_instruction_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "r_search_tree_size: " << r_search_tree_size;
|
||||
SimpleLogger().Write(logDEBUG) << "sizeof(checksum): " << sizeof(checksum);
|
||||
SimpleLogger().Write(logDEBUG) << "ram index file name: " << ram_index_file_name;
|
||||
}
|
||||
|
||||
uint64_t GetSizeOfLayout() const {
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned) ) +
|
||||
(name_char_list_size * sizeof(char) ) +
|
||||
(name_id_list_size * sizeof(unsigned) ) +
|
||||
(via_node_list_size * sizeof(NodeID) ) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::_StrNode)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::_StrEdge)) +
|
||||
(timestamp_length * sizeof(char) ) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructions) ) +
|
||||
(r_search_tree_size * sizeof(RTreeNode) ) +
|
||||
sizeof(checksum) +
|
||||
1024*sizeof(char);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t GetNameIndexOffset() const {
|
||||
return 0;
|
||||
}
|
||||
uint64_t GetNameListOffset() const {
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned) );
|
||||
return result;
|
||||
}
|
||||
uint64_t GetNameIDListOffset() const {
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned) ) +
|
||||
(name_char_list_size * sizeof(char) );
|
||||
return result;
|
||||
}
|
||||
uint64_t GetViaNodeListOffset() const {
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned) ) +
|
||||
(name_char_list_size * sizeof(char) ) +
|
||||
(name_id_list_size * sizeof(unsigned) );
|
||||
return result;
|
||||
}
|
||||
uint64_t GetGraphNodeListOffset() const {
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned) ) +
|
||||
(name_char_list_size * sizeof(char) ) +
|
||||
(name_id_list_size * sizeof(unsigned) ) +
|
||||
(via_node_list_size * sizeof(NodeID) );
|
||||
return result;
|
||||
}
|
||||
uint64_t GetGraphEdgeListOffsett() const {
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned) ) +
|
||||
(name_char_list_size * sizeof(char) ) +
|
||||
(name_id_list_size * sizeof(unsigned) ) +
|
||||
(via_node_list_size * sizeof(NodeID) ) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::_StrNode)) ;
|
||||
return result;
|
||||
}
|
||||
uint64_t GetTimeStampOffset() const {
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned) ) +
|
||||
(name_char_list_size * sizeof(char) ) +
|
||||
(name_id_list_size * sizeof(unsigned) ) +
|
||||
(via_node_list_size * sizeof(NodeID) ) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::_StrNode)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::_StrEdge));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetCoordinateListOffset() const {
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned) ) +
|
||||
(name_char_list_size * sizeof(char) ) +
|
||||
(name_id_list_size * sizeof(unsigned) ) +
|
||||
(via_node_list_size * sizeof(NodeID) ) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::_StrNode)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::_StrEdge)) +
|
||||
(timestamp_length * sizeof(char) );
|
||||
return result;
|
||||
}
|
||||
uint64_t GetTurnInstructionListOffset() const {
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned) ) +
|
||||
(name_char_list_size * sizeof(char) ) +
|
||||
(name_id_list_size * sizeof(unsigned) ) +
|
||||
(via_node_list_size * sizeof(NodeID) ) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::_StrNode)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::_StrEdge)) +
|
||||
(timestamp_length * sizeof(char) ) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetRSearchTreeOffset() const {
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned) ) +
|
||||
(name_char_list_size * sizeof(char) ) +
|
||||
(name_id_list_size * sizeof(unsigned) ) +
|
||||
(via_node_list_size * sizeof(NodeID) ) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::_StrNode)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::_StrEdge)) +
|
||||
(timestamp_length * sizeof(char) ) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructions) );
|
||||
return result;
|
||||
}
|
||||
uint64_t GetChecksumOffset() const {
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned) ) +
|
||||
(name_char_list_size * sizeof(char) ) +
|
||||
(name_id_list_size * sizeof(unsigned) ) +
|
||||
(via_node_list_size * sizeof(NodeID) ) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::_StrNode)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::_StrEdge)) +
|
||||
(timestamp_length * sizeof(char) ) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructions) ) +
|
||||
(r_search_tree_size * sizeof(RTreeNode) );
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
enum SharedDataType {
|
||||
CURRENT_REGIONS,
|
||||
LAYOUT_1,
|
||||
DATA_1,
|
||||
LAYOUT_2,
|
||||
DATA_2,
|
||||
LAYOUT_NONE,
|
||||
DATA_NONE
|
||||
};
|
||||
|
||||
struct SharedDataTimestamp {
|
||||
SharedDataType layout;
|
||||
SharedDataType data;
|
||||
unsigned timestamp;
|
||||
};
|
||||
|
||||
#endif /* SHARED_DATA_TYPE_H_ */
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BASIC_DATASTRUCTURES_H
|
||||
#define BASIC_DATASTRUCTURES_H
|
||||
|
||||
namespace http {
|
||||
|
||||
enum CompressionType {
|
||||
noCompression,
|
||||
gzipRFC1952,
|
||||
deflateRFC1951
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif //BASIC_DATASTRUCTURES_H
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HTTP_HEADER_H
|
||||
#define HTTP_HEADER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace http {
|
||||
|
||||
struct Header {
|
||||
std::string name;
|
||||
std::string value;
|
||||
void Clear() {
|
||||
name.clear();
|
||||
value.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //HTTP_HEADER_H
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "Reply.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
void Reply::setSize(const unsigned size) {
|
||||
BOOST_FOREACH ( Header& h, headers) {
|
||||
if("Content-Length" == h.name) {
|
||||
std::string sizeString;
|
||||
intToString(size,h.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<boost::asio::const_buffer> Reply::toBuffers(){
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
buffers.push_back(ToBuffer(status));
|
||||
BOOST_FOREACH(const Header & h, headers) {
|
||||
buffers.push_back(boost::asio::buffer(h.name));
|
||||
buffers.push_back(boost::asio::buffer(seperators));
|
||||
buffers.push_back(boost::asio::buffer(h.value));
|
||||
buffers.push_back(boost::asio::buffer(crlf));
|
||||
}
|
||||
buffers.push_back(boost::asio::buffer(crlf));
|
||||
BOOST_FOREACH(const std::string & line, content) {
|
||||
buffers.push_back(boost::asio::buffer(line));
|
||||
}
|
||||
return buffers;
|
||||
}
|
||||
|
||||
std::vector<boost::asio::const_buffer> Reply::HeaderstoBuffers(){
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
buffers.push_back(ToBuffer(status));
|
||||
for (std::size_t i = 0; i < headers.size(); ++i) {
|
||||
Header& h = headers[i];
|
||||
buffers.push_back(boost::asio::buffer(h.name));
|
||||
buffers.push_back(boost::asio::buffer(seperators));
|
||||
buffers.push_back(boost::asio::buffer(h.value));
|
||||
buffers.push_back(boost::asio::buffer(crlf));
|
||||
}
|
||||
buffers.push_back(boost::asio::buffer(crlf));
|
||||
return buffers;
|
||||
}
|
||||
|
||||
Reply Reply::StockReply(Reply::status_type status) {
|
||||
Reply rep;
|
||||
rep.status = status;
|
||||
rep.content.clear();
|
||||
rep.content.push_back( ToString(status) );
|
||||
rep.headers.resize(3);
|
||||
rep.headers[0].name = "Access-Control-Allow-Origin";
|
||||
rep.headers[0].value = "*";
|
||||
rep.headers[1].name = "Content-Length";
|
||||
|
||||
std::string s;
|
||||
intToString(rep.content.size(), s);
|
||||
|
||||
rep.headers[1].value = s;
|
||||
rep.headers[2].name = "Content-Type";
|
||||
rep.headers[2].value = "text/html";
|
||||
return rep;
|
||||
}
|
||||
|
||||
std::string Reply::ToString(Reply::status_type status) {
|
||||
switch (status) {
|
||||
case Reply::ok:
|
||||
return okHTML;
|
||||
case Reply::badRequest:
|
||||
return badRequestHTML;
|
||||
default:
|
||||
return internalServerErrorHTML;
|
||||
}
|
||||
}
|
||||
|
||||
boost::asio::const_buffer Reply::ToBuffer(Reply::status_type status) {
|
||||
switch (status) {
|
||||
case Reply::ok:
|
||||
return boost::asio::buffer(okString);
|
||||
case Reply::internalServerError:
|
||||
return boost::asio::buffer(internalServerErrorString);
|
||||
default:
|
||||
return boost::asio::buffer(badRequestString);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reply::Reply() : status(ok) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef REPLY_H
|
||||
#define REPLY_H
|
||||
|
||||
#include "Header.h"
|
||||
#include "../../Util/StringUtil.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace http {
|
||||
|
||||
const char okHTML[] = "";
|
||||
const char badRequestHTML[] = "<html><head><title>Bad Request</title></head><body><h1>400 Bad Request</h1></body></html>";
|
||||
const char internalServerErrorHTML[] = "<html><head><title>Internal Server Error</title></head><body><h1>500 Internal Server Error</h1></body></html>";
|
||||
const char seperators[] = { ':', ' ' };
|
||||
const char crlf[] = { '\r', '\n' };
|
||||
const std::string okString = "HTTP/1.0 200 OK\r\n";
|
||||
const std::string badRequestString = "HTTP/1.0 400 Bad Request\r\n";
|
||||
const std::string internalServerErrorString = "HTTP/1.0 500 Internal Server Error\r\n";
|
||||
|
||||
class Reply {
|
||||
public:
|
||||
enum status_type {
|
||||
ok = 200,
|
||||
badRequest = 400,
|
||||
internalServerError = 500
|
||||
} status;
|
||||
|
||||
|
||||
std::vector<Header> headers;
|
||||
std::vector<boost::asio::const_buffer> toBuffers();
|
||||
std::vector<boost::asio::const_buffer> HeaderstoBuffers();
|
||||
std::vector<std::string> content;
|
||||
static Reply StockReply(status_type status);
|
||||
void setSize(const unsigned size);
|
||||
Reply();
|
||||
private:
|
||||
static std::string ToString(Reply::status_type status);
|
||||
boost::asio::const_buffer ToBuffer(Reply::status_type status);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //REPLY_H
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef REQUEST_H
|
||||
#define REQUEST_H
|
||||
|
||||
#include "../../Util/StringUtil.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace http {
|
||||
|
||||
struct Request {
|
||||
std::string uri;
|
||||
std::string referrer;
|
||||
std::string agent;
|
||||
boost::asio::ip::address endpoint;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif //REQUEST_H
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef REQUEST_HANDLER_H
|
||||
#define REQUEST_HANDLER_H
|
||||
|
||||
#include "APIGrammar.h"
|
||||
#include "DataStructures/RouteParameters.h"
|
||||
#include "Http/Request.h"
|
||||
#include "../Library/OSRM.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
|
||||
class RequestHandler : private boost::noncopyable {
|
||||
public:
|
||||
typedef APIGrammar<std::string::iterator, RouteParameters> APIGrammarParser;
|
||||
explicit RequestHandler() : routing_machine(NULL) { }
|
||||
|
||||
void handle_request(const http::Request& req, http::Reply& rep){
|
||||
//parse command
|
||||
try {
|
||||
std::string request(req.uri);
|
||||
|
||||
time_t ltime;
|
||||
struct tm *Tm;
|
||||
|
||||
ltime=time(NULL);
|
||||
Tm=localtime(<ime);
|
||||
|
||||
SimpleLogger().Write() <<
|
||||
(Tm->tm_mday < 10 ? "0" : "" ) << Tm->tm_mday << "-" <<
|
||||
(Tm->tm_mon+1 < 10 ? "0" : "" ) << (Tm->tm_mon+1) << "-" <<
|
||||
1900+Tm->tm_year << " " << (Tm->tm_hour < 10 ? "0" : "" ) <<
|
||||
Tm->tm_hour << ":" << (Tm->tm_min < 10 ? "0" : "" ) <<
|
||||
Tm->tm_min << ":" << (Tm->tm_sec < 10 ? "0" : "" ) <<
|
||||
Tm->tm_sec << " " << req.endpoint.to_string() << " " <<
|
||||
req.referrer << ( 0 == req.referrer.length() ? "- " :" ") <<
|
||||
req.agent << ( 0 == req.agent.length() ? "- " :" ") << req.uri;
|
||||
|
||||
RouteParameters routeParameters;
|
||||
APIGrammarParser apiParser(&routeParameters);
|
||||
|
||||
std::string::iterator it = request.begin();
|
||||
const bool result = boost::spirit::qi::parse(
|
||||
it,
|
||||
request.end(),
|
||||
apiParser
|
||||
);
|
||||
|
||||
if ( !result || (it != request.end()) ) {
|
||||
rep = http::Reply::StockReply(http::Reply::badRequest);
|
||||
const int position = std::distance(request.begin(), it);
|
||||
std::string tmp_position_string;
|
||||
intToString(position, tmp_position_string);
|
||||
rep.content.push_back(
|
||||
"Input seems to be malformed close to position "
|
||||
"<br><pre>"
|
||||
);
|
||||
rep.content.push_back( request );
|
||||
rep.content.push_back(tmp_position_string);
|
||||
rep.content.push_back("<br>");
|
||||
const unsigned end = std::distance(request.begin(), it);
|
||||
for(unsigned i = 0; i < end; ++i) {
|
||||
rep.content.push_back(" ");
|
||||
}
|
||||
rep.content.push_back("^<br></pre>");
|
||||
} else {
|
||||
//parsing done, lets call the right plugin to handle the request
|
||||
BOOST_ASSERT_MSG(
|
||||
routing_machine != NULL,
|
||||
"pointer not init'ed"
|
||||
);
|
||||
routing_machine->RunQuery(routeParameters, rep);
|
||||
return;
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
rep = http::Reply::StockReply(http::Reply::internalServerError);
|
||||
SimpleLogger().Write(logWARNING) <<
|
||||
"[server error] code: " << e.what() << ", uri: " << req.uri;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
void RegisterRoutingMachine(OSRM * osrm) {
|
||||
routing_machine = osrm;
|
||||
}
|
||||
|
||||
private:
|
||||
OSRM * routing_machine;
|
||||
};
|
||||
|
||||
#endif // REQUEST_HANDLER_H
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "RequestParser.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
RequestParser::RequestParser() : state_(method_start) { }
|
||||
|
||||
void RequestParser::Reset() { state_ = method_start; }
|
||||
|
||||
boost::tuple<boost::tribool, char*> RequestParser::Parse(
|
||||
Request& req,
|
||||
char* begin,
|
||||
char* end,
|
||||
http::CompressionType * compressionType
|
||||
) {
|
||||
while (begin != end) {
|
||||
boost::tribool result = consume(req, *begin++, compressionType);
|
||||
if (result || !result){
|
||||
return boost::make_tuple(result, begin);
|
||||
}
|
||||
}
|
||||
boost::tribool result = boost::indeterminate;
|
||||
return boost::make_tuple(result, begin);
|
||||
}
|
||||
|
||||
boost::tribool RequestParser::consume(
|
||||
Request& req, char input,
|
||||
http::CompressionType * compressionType
|
||||
) {
|
||||
switch (state_) {
|
||||
case method_start:
|
||||
if (!isChar(input) || isCTL(input) || isTSpecial(input)) {
|
||||
return false;
|
||||
} else {
|
||||
state_ = method;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case method:
|
||||
if (input == ' ') {
|
||||
state_ = uri;
|
||||
return boost::indeterminate;
|
||||
} else if (!isChar(input) || isCTL(input) || isTSpecial(input)) {
|
||||
return false;
|
||||
} else {
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case uri_start:
|
||||
if (isCTL(input)) {
|
||||
return false;
|
||||
} else {
|
||||
state_ = uri;
|
||||
req.uri.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case uri:
|
||||
if (input == ' ') {
|
||||
state_ = http_version_h;
|
||||
return boost::indeterminate;
|
||||
} else if (isCTL(input)) {
|
||||
return false;
|
||||
} else {
|
||||
req.uri.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case http_version_h:
|
||||
if (input == 'H') {
|
||||
state_ = http_version_t_1;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_t_1:
|
||||
if (input == 'T') {
|
||||
state_ = http_version_t_2;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_t_2:
|
||||
if (input == 'T') {
|
||||
state_ = http_version_p;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_p:
|
||||
if (input == 'P') {
|
||||
state_ = http_version_slash;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_slash:
|
||||
if (input == '/') {
|
||||
state_ = http_version_major_start;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_major_start:
|
||||
if (isDigit(input)) {
|
||||
state_ = http_version_major;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_major:
|
||||
if (input == '.') {
|
||||
state_ = http_version_minor_start;
|
||||
return boost::indeterminate;
|
||||
} else if (isDigit(input)) {
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_minor_start:
|
||||
if (isDigit(input)) {
|
||||
state_ = http_version_minor;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_minor:
|
||||
if (input == '\r') {
|
||||
state_ = expecting_newline_1;
|
||||
return boost::indeterminate;
|
||||
} else if (isDigit(input)) {
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
case expecting_newline_1:
|
||||
if (input == '\n') {
|
||||
state_ = header_line_start;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case header_line_start:
|
||||
if(header.name == "Accept-Encoding") {
|
||||
/* giving gzip precedence over deflate */
|
||||
if(header.value.find("deflate") != std::string::npos)
|
||||
*compressionType = deflateRFC1951;
|
||||
if(header.value.find("gzip") != std::string::npos)
|
||||
*compressionType = gzipRFC1952;
|
||||
}
|
||||
|
||||
if("Referer" == header.name)
|
||||
req.referrer = header.value;
|
||||
|
||||
if("User-Agent" == header.name)
|
||||
req.agent = header.value;
|
||||
|
||||
if (input == '\r') {
|
||||
state_ = expecting_newline_3;
|
||||
return boost::indeterminate;
|
||||
} else if (!isChar(input) || isCTL(input) || isTSpecial(input)) {
|
||||
return false;
|
||||
} else {
|
||||
state_ = header_name;
|
||||
header.Clear();
|
||||
header.name.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case header_lws:
|
||||
if (input == '\r') {
|
||||
state_ = expecting_newline_2;
|
||||
return boost::indeterminate;
|
||||
} else if (input == ' ' || input == '\t') {
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (isCTL(input)) {
|
||||
return false;
|
||||
} else {
|
||||
state_ = header_value;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case header_name:
|
||||
if (input == ':') {
|
||||
state_ = space_before_header_value;
|
||||
return boost::indeterminate;
|
||||
} else if (!isChar(input) || isCTL(input) || isTSpecial(input)) {
|
||||
return false;
|
||||
} else {
|
||||
header.name.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case space_before_header_value:
|
||||
if (input == ' ') {
|
||||
state_ = header_value;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case header_value:
|
||||
if (input == '\r') {
|
||||
state_ = expecting_newline_2;
|
||||
return boost::indeterminate;
|
||||
} else if (isCTL(input)) {
|
||||
return false;
|
||||
} else {
|
||||
header.value.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case expecting_newline_2:
|
||||
if (input == '\n') {
|
||||
state_ = header_line_start;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case expecting_newline_3:
|
||||
return (input == '\n');
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool RequestParser::isChar(int c) {
|
||||
return c >= 0 && c <= 127;
|
||||
}
|
||||
|
||||
inline bool RequestParser::isCTL(int c) {
|
||||
return (c >= 0 && c <= 31) || (c == 127);
|
||||
}
|
||||
|
||||
inline bool RequestParser::isTSpecial(int c) {
|
||||
switch (c) {
|
||||
case '(': case ')': case '<': case '>': case '@':
|
||||
case ',': case ';': case ':': case '\\': case '"':
|
||||
case '/': case '[': case ']': case '?': case '=':
|
||||
case '{': case '}': case ' ': case '\t':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool RequestParser::isDigit(int c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef REQUEST_PARSER_H
|
||||
#define REQUEST_PARSER_H
|
||||
|
||||
#include "Http/CompressionType.h"
|
||||
#include "Http/Header.h"
|
||||
#include "Http/Request.h"
|
||||
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
namespace http {
|
||||
|
||||
class RequestParser {
|
||||
public:
|
||||
RequestParser();
|
||||
void Reset();
|
||||
|
||||
boost::tuple<boost::tribool, char*> Parse(
|
||||
Request& req,
|
||||
char* begin,
|
||||
char* end,
|
||||
CompressionType * compressionType
|
||||
);
|
||||
|
||||
private:
|
||||
boost::tribool consume(
|
||||
Request& req,
|
||||
char input,
|
||||
CompressionType * compressionType
|
||||
);
|
||||
|
||||
inline bool isChar(int c);
|
||||
|
||||
inline bool isCTL(int c);
|
||||
|
||||
inline bool isTSpecial(int c);
|
||||
|
||||
inline bool isDigit(int c);
|
||||
|
||||
enum state {
|
||||
method_start,
|
||||
method,
|
||||
uri_start,
|
||||
uri,
|
||||
http_version_h,
|
||||
http_version_t_1,
|
||||
http_version_t_2,
|
||||
http_version_p,
|
||||
http_version_slash,
|
||||
http_version_major_start,
|
||||
http_version_major,
|
||||
http_version_minor_start,
|
||||
http_version_minor,
|
||||
expecting_newline_1,
|
||||
header_line_start,
|
||||
header_lws,
|
||||
header_name,
|
||||
space_before_header_value,
|
||||
header_value,
|
||||
expecting_newline_2,
|
||||
expecting_newline_3
|
||||
} state_;
|
||||
|
||||
Header header;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif // REQUEST_PARSER_H
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
|
||||
#include "Connection.h"
|
||||
#include "RequestHandler.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Server: private boost::noncopyable {
|
||||
public:
|
||||
explicit Server(
|
||||
const std::string& address,
|
||||
const std::string& port,
|
||||
unsigned thread_pool_size
|
||||
) :
|
||||
threadPoolSize(thread_pool_size),
|
||||
acceptor(ioService),
|
||||
newConnection(new http::Connection(ioService, requestHandler)),
|
||||
requestHandler()
|
||||
{
|
||||
boost::asio::ip::tcp::resolver resolver(ioService);
|
||||
boost::asio::ip::tcp::resolver::query query(address, port);
|
||||
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
|
||||
|
||||
acceptor.open(endpoint.protocol());
|
||||
acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||
acceptor.bind(endpoint);
|
||||
acceptor.listen();
|
||||
acceptor.async_accept(
|
||||
newConnection->socket(),
|
||||
boost::bind(
|
||||
&Server::handleAccept,
|
||||
this,
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void Run() {
|
||||
std::vector<boost::shared_ptr<boost::thread> > threads;
|
||||
for (unsigned i = 0; i < threadPoolSize; ++i) {
|
||||
boost::shared_ptr<boost::thread> thread(new boost::thread(boost::bind(&boost::asio::io_service::run, &ioService)));
|
||||
threads.push_back(thread);
|
||||
}
|
||||
for (unsigned i = 0; i < threads.size(); ++i)
|
||||
threads[i]->join();
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
ioService.stop();
|
||||
}
|
||||
|
||||
RequestHandler & GetRequestHandlerPtr() {
|
||||
return requestHandler;
|
||||
}
|
||||
|
||||
private:
|
||||
void handleAccept(const boost::system::error_code& e) {
|
||||
if (!e) {
|
||||
newConnection->start();
|
||||
newConnection.reset(
|
||||
new http::Connection(ioService, requestHandler)
|
||||
);
|
||||
acceptor.async_accept(
|
||||
newConnection->socket(),
|
||||
boost::bind(
|
||||
&Server::handleAccept,
|
||||
this,
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned threadPoolSize;
|
||||
boost::asio::io_service ioService;
|
||||
boost::asio::ip::tcp::acceptor acceptor;
|
||||
boost::shared_ptr<http::Connection> newConnection;
|
||||
RequestHandler requestHandler;
|
||||
};
|
||||
|
||||
#endif // SERVER_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user