New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Random Round Tours #582
Random Round Tours #582
Conversation
I tried this branch out because it sounds interesting. But it does not work for me. Whenever I add This is the trace:
|
@ratrun haven't tested it for Austria. This might happen sometimes, but shouldn't happen regularly. What area did you use? |
The first log line contains the coordinates and the exact URL. It looks as you can choose any. I tried at least 8 times with differnt start and end point and never got a result. |
@ratrun thanks for pointing out that there was a mistake. I fixed it and got rid of the Attached is a screenshot of the generated route (thats actually a good one - took me about 10 repetitions - but you should get a result every time). Currently edges are taken twice, but this should be fixed by #579. |
Thank you. I can confirm that now I always get a result. |
Thanks for the work. I would like to integrate #420 in the next days first and then adapt this solution to integrate as second alternative to round trip calculation and see which is better in terms of speed and quality or algorithmical approach etc, maybe then combine two approaches or keep them as they are. The unique path calculation should be done in the weighting, where we have to improve the API to allow combination of weightings like suggested by @boldtrn in the other PR. Furthermore we will definitely deploy this to the API at some point, even if it is load intense, also probably to the GraphHopper Maps demo. That will happen once we have the flexibilty work improved and production ready. |
The parts to integrate this into GH are now mostly done: https://github.com/graphhopper/graphhopper/tree/alternate_route2 Would you mind to integrate this? Currently you need to trigger alternative calculation via |
@boldtrn The alternative routing and 'round trip alt' algorithm are now integrated in the master - enable via And you can now easily integrate this algorithm (or any improved version you might have) via adding it to RoutingAlgorithmFactorySimple ... and |
@boldtrn Do you plan to integrate your solution as suggested by Peter? I was thinking about if I should give it a try. But I'm sure it would be much easier for you and if you already started that would make sense at all. |
@ratrun Yes, this is planned. I might work a bit on this issue today. I hope it's quite straight forward. I wanted to integrate this in the next time. |
Thanks. Great. |
…d Algorithm Factory
e3d71d7
to
06c8ab5
Compare
@ratrun I updated my branch. Let me know what you think. |
Thanks @boldtrn that you took the time to reintegrate it!
I would use meters as this is the same unit we use for the response We also need at least one unit and one integration test e.g. in GraphHopperIT for this round trip algo.
Can we avoid somehow the prepare? The 'lat,lon' stuff is meant for the higher level API and lower level should always use node or edge IDs. Why do you have only 'lat,lon' available when generating the random points? Or could you create the random points at the higher level layer instead? Especially for the unit tests and other integrations it is harder to handle 'lat,lon's instead of IDs. Can we reduce the complexity a bit? E.g. remove TourStrategyFactory, merge the TourStrategy classes into one and moving TourWayPointGenerator methods into the RoundtripAlgo class? I would avoid introducing an abstraction layer if there is just one implementation or do you have already alternates for them (then it would be okay). And is the method in CoordinateProjection maybe already covered from a DistanceCalcXY method? If not, I would put the method into an existing Helper class to avoid classes just for one method (?) |
@boldtrn Thank you. This really works very well and the feature is great. I intend to use it for planning of cycle tours in spring. My tests from my location look promising. It chooses very similar cycle routes which I would take. I'll try to implement a web interface for it based on my master, such that the usage becomes more simple.
I believe that kilometers are what users would expect, so this would be more user friendly. But as the end users will not manually mangle URI parameters, I don't care. |
I merged your branch into my master, implemented the WEB UI and pushed the changes. |
Yes sure, we can change this. I started with km since that's usually the unit the user is interested in.
Yes, you are right. I will add some tests.
For the round trip generation I use a technique that is called point projection. I use the starting point and project this point into a certain direction over a certain distance. Then I use the locationIndex to find the closest node. We could do it in the GraphHopper.java class but than we have to pass the generated points to the roundtrip algorithm via RoutingOptions. If we want to generate multiple roundtrips (for alternative paths), we need to generate all these points beforehand. What do you think, should where and how should we generate these points?
The current strategy is not the best, but with this layer adding new strategies is really easy and straight forward. I think we will see a lot of interesting strategies in the future. @ratrun just requested adding a second point. This could be easily done by just adding another strategy. In the StrategyFactory on could define what strategy should be picked according to the current situation (e.g. using the two-point strategy only if distance > 50km).
I haven't found something like that. Sure, where would you move it?
@ratrun Yes both should be quite straight forward. Just create a new TourStrategy. Probably you have to extend everything a bit to set an initialBearing. But should be quite easy. Let me know if you need more details. I will add another helper method to the TourStrategy, which should make it easier to generate several points.
Great news :) Thanks. |
I just committed the helper function and some tests (not enough). |
Yes, but developers do not care about the unit either as long as it is documented or consistent :) (IMHO)
I would put it into DistanceCalcEarth as the earth radius is also there (or could be also related to AngleCalc as it is the 'opposite' of calcOrientation). Furthermore the Maybe also 'bearing' should be renamed to 'heading' for more consistency to the existent functionality.
Okay, I'm fine with it if there are already two strategies :) but it is overhead if we just plan for them as then it is nearly always the case that refactorings etc are necessary.
Okay, that sounds doable. Will have to think about it, because an algo setup which requires the location index is too heavyweight and should be 'somehow decoupled' ;). In the worst case instead of passing the locationindex I would provide a lookup hook. |
Kind of related a post on HN regarding abstractions vs. unhandleable mess https://news.ycombinator.com/item?id=11093733 |
When thinking about this more ... we should move the point creation out of the algorithm and e.g. provide the created points as input for the algorithm or let clients explicitly define points or just one point and a heading etc either with some simple ifs or with the TourStrategy class. Also the randomness should move out of the algorithm if not even to the client itself e.g. providing a random heading direction. What do you think? Should I make a branch to show what I mean (when I find time ;))? |
@karussell Ok, I am excited. Moving the generated points as input to the algorithm is a good idea (even though the algorithm won't do very much right now if there are no points to generate). For a simple single point strategy generating a random heading by the user seems appropriate. I am not sure about more complex strategies, but I am excited about your branch :). |
Here is the basic workflow: |
Thanks for explaining. That is actually a nice idea to work with the two points. I don't know if you have made any progress here? I just recently added the roundtrip feature to a project of mine. There is use https://github.com/aterrien/jQuery-Knob to allow a user to set the bearing. A distance and starting point has to be entered additionally. |
@boldtrn Thanks for the feedback on the GUI idea. I haven't implemented anything as this PR unfortunately is still not accepted and a numerical entry field of the bearing was good enough for me. |
Please have a look at this branch: https://github.com/graphhopper/graphhopper/compare/issue_582 What I did:
Please question naming and everything. This is for now a rough sketch of what I meant. Still missing is the part where one calculates the initial heading from the second point. Also I would somehow use the |
Thanks. Looks nice. Unfortunately I cannot comment in the code, so I'll just add my comments here.
Something I personally would love to improve is the I am still a fan of the strategy, since this makes the whole approach customizable. |
Uhm, ugly. And I cannot push and add to your commits so I've created the branch ... probably I should have opened yet another PR to make it the 'github way'
From the API usage I prefer the "point&heading" parameters but the current system prefers "2 points" as with 1 point we get a bit problems with the QueryResult. Still we can workaround this with duplicating the first QueryResult as the second... I'll do that and try to avoid the currently required second point and also we should try to read the (first)
👍 I really like that :)
Yes. That was necessary to avoid the special cast. A better approach to put it into the hints but this is only usable for string values :(. And that is by intention as I wanted all 'real objects' being explicit in the AlgorithmOptions or being later created from the strings. Hmmh. Now the Object serve the generic purpose and could be used from any algo. Not sure how to solve this better, a specific class would not make sense too.
You want to improve the implementation details? That should indeed go into another issue :) |
Regarding the 'algoControl': what if we calculate the points already and assign the new points and do the regular routing all in the GraphHopper class (point calculation delegated to the point generator). And in the GraphHopper class we would need to intercept the weighting change somehow. Maybe with a custom RoutingAlgorithmFactory? I mean this part here (except the AvoidPathWeighting) is duplicate to the loop in GraphHopper, and if we can somehow merge this into the normal process we do not need a new roundtrip class, maybe just a factory and the point creation strategy. A further benefit would be that the used algorithm would stay customizable and not fixed to DijkstraBidirectionRef and we could even specify 'pass_through' etc for the round trip segments |
Yes, probably you should have created a PR to my PR :D.
Yes, could be a nice workaround.
Could we maybe create an empty Interface called
Yes you are right. I think I it copied from the GraphHopper class ;). I did not do this for two reasons. I would love to implement it in the GraphHopper class, but I thought you would not like it. |
Good idea. And yes, that is allowed and called 'marker interface'
I would not convolute the GraphHopper with round trip specific stuff, that is right. But if we could find a way to abstract this away and bundle it in a round trip algo factory or something that this would be nice. But maybe also part of another PR :) |
I've applied the suggestions to the branch. Please have a look. |
Thanks I didn't know that.
Looks nice, but tests are failing?
Mhm, if we want to do that, I think we should do it now. |
Fixed
Okay, sure. I'll have a look. |
The route method has kind of 3 parts: 1. points lookup, 2. route loop and 3. path merger. Now if I understood this correctly for the round trip we need:
|
Exactly. |
I had a bit success in moving 2 and 3 out into another class (probably step 1 is also possible soonish), but then for a new 'round trip implementation' we would need to copy and paste most of this. Hmmh, tricky |
@boldtrn I had a look at your kurvinger.de, since I was interested in the roundtrip work. I'm not fluent in german, but this is for motorbikes? Is the intention to generate round-trips which are of approximately the length (double-headed arrow) in km? I ask since I've used it in some cases and got ones which are eg. 22km instead of "3", though some generated routes were about 3... should it do that? :) |
@karussell Yes it's really tricky. @neiljp Yes this is true. The algorithm works best for distances greater than 50km. The usual input is at around 200km. Motorcyclists often ride round tours as day trips. So the intention was to easily generate round trips. |
@boldtrn Ah, shame it doesn't work well for shorter, as it'd be great to have time/distance-guided routes for walking/cycling too :) |
@karussell That's great news - I look forward to seeing it in action :) |
You can easily check the branch #709 out - we would love to get feedback as early as possible :) Also we do not yet have a UI for this, so it will not be directly available on GraphHopper Maps. Maybe we need something similar like @boldtrn did on kurviger or also @ratrun had something if I remember correctly. |
This PR contains the possibility to create random round tours. When passing
tour_length=APPROX_DISTANCE_IN_KM
to the request it returns a roundtour of approximately the requested distance. The actual distances can vary a lot, since I only calculate the beeline distance of the waypoints.The current results are ok, but not good. Especially because the unique_paths PR is not included here (this will probably improve the results.
Currently this feature is not available in the GUI. We just use the first waypoint and create a route.
Something that could be added as well is to calculate a number of tours and select the best one, to remove bad results created by this approach.