Skip to content
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

Parameter for keep waypoints on the left/right #4039

Merged
merged 13 commits into from
May 30, 2017

Conversation

fijemax
Copy link
Contributor

@fijemax fijemax commented May 12, 2017

Description :

This PR adds a parameter for each point to chose the start/stop side.
Three option can be used :

  • DEFAULT to start/stop at the drive side
  • OPPOSITE to start/stop at the opposite of default (cross the road)
  • BOTH each side can be used (old behavior).

The default depending at the country.

Issue

This pull request is linking to this issue :
#2201

Tasklist

  • Adding sides parameter into base parameters, it can take the values DEFAULT, OPPOSITE or BOTH.
  • Adding url parser for "sides" parameter, url values are "d" for DEFAULT, "o" for OPPOSITE and "b" for BOTH, example : "sides=s;s".
  • Checking parameters, if "sides" parameter is used, the number of parameter is the same as number of location.
  • Create a phantom to start/stop at side drive or opposite drive side.
  • Retrieve the country's drive side for apply the DEFAULT.

For the moment the country's drive side is set to right by default, we can find this parameter in the lua file.
How can access this parameter in the osrm-routed ?

Example for DEFAULT on start and stop route point value :
Here start and stop
capture d ecran de 2017-05-12 16-07-54
capture d ecran de 2017-05-12 16-07-32

Another example :
capture d ecran de 2017-05-12 18-00-44 capture d ecran de 2017-05-12 18-00-51

For the one-way roads :
The algorythm do not use the "side" parameter for the phantom node option because the driver hasn't the choice.
capture d ecran de 2017-05-12 16-11-29
capture d ecran de 2017-05-12 16-11-37

@fijemax fijemax changed the title New "sides" setting in base parameters for phantom nodes. Parameter for keep waypoints on the left/right May 12, 2017
@fijemax
Copy link
Contributor Author

fijemax commented May 12, 2017

@frodrigo

@fijemax fijemax force-pushed the mt-start-side branch 4 times, most recently from 61548fd to 078b238 Compare May 15, 2017 09:17
@TheMarex
Copy link
Member

Thank you for taking a stab at this! 🎉 I just skimmed the diff quickly some things that I noticed:

  1. No test coverage, this should have a cucumber test
  2. No URL parser test, this should have a unit-test
  3. NodeJS bindings are not extended yet.

I can put a real review on my TODO for later today, I need to think a little bit about parameter naming and such.

@TheMarex TheMarex added this to the 5.8.0 milestone May 15, 2017
@fijemax
Copy link
Contributor Author

fijemax commented May 17, 2017

Hi @TheMarex
I extended the NodeJS for the sides parameter.
I added the cucumber test.

Copy link
Contributor

@oxidase oxidase left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! AFAIU, DEFAULT side should be used as a parameter for re-routing

@@ -149,10 +159,13 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
qi::lit("bearings=") >
(-(qi::short_ > ',' > qi::short_))[ph::bind(add_bearing, qi::_r1, qi::_1)] % ';';

sides_rule = qi::lit("sides=") >
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sides_rule can be qi::symbols, so add_side is not needed.
Also BOTH can be used for empty boost::optional values with std::vector<Side> sides

Copy link
Contributor Author

@fijemax fijemax May 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tryed to change by this code :

        side_default = qi::char_("a-zA-Z")[qi::_val = engine::Side{engine::BOTH}];
        struct StartSideValues: qi::symbols<char, engine::Side>
        {
            StartSideValues() {add("b", engine::Side{engine::BOTH})("d", engine::Side{engine::DEFAULT})("o", engine::Side{engine::OPPOSITE})("", engine::Side{engine::OPPOSITE}); }
        };
        StartSideValues values;
        sides_rule = qi::lit("sides=") >
                        (-(values | side_default) %
                         ';')[ph::bind(&engine::api::BaseParameters::sides, qi::_r1) = qi::_1];

But it provokes segfault.
I am trying to analyse with gdb but it's a really complicated backtrace.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fijemax it crashes because grammars are local variables in the constructor.

What i suggest is to use in the way as in commit oxidase@301a1cc It contains more restrictive grammar [bod|eps]

Please add also some unit tests for parsing incorrect URLs as suggested by @TheMarex


When I route I should get
| from | to | sides | route |
| s | e | b o | ab,bc,bc |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it possible to add a turn instructions check? to see explicitly a u-turn

// |
// input_coordinate

bool input_coordinate_is_at_right = !util::coordinate_calculation::isCCW(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

util::coordinate_calculation::isCCW(coordinates[segment.data.u], input_coordinate, coordinates[segment.data.v]); to correspond the figure above

@fijemax
Copy link
Contributor Author

fijemax commented May 17, 2017

I just added the nodeJS binding and url tests.

@fijemax fijemax force-pushed the mt-start-side branch 2 times, most recently from d2b3514 to 6e55692 Compare May 18, 2017 15:14
@fijemax
Copy link
Contributor Author

fijemax commented May 19, 2017

Hi @oxidase, thanks for parser example.
I refactored the code

  • Simple enumerator for Side
  • Change gi::lit to qi::symbol for side parser
    I added URL tests in the unit_tests

Copy link
Contributor

@oxidase oxidase left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, some small cleanup comments

@@ -46,7 +46,7 @@ BOOST_AUTO_TEST_CASE(invalid_route_urls)
BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&radiuses=foo"),
32UL);
BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&sides=foo"),
30UL);
29UL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

#ifndef OSRM_ENGINE_SIDE_HPP
#define OSRM_ENGINE_SIDE_HPP

#include <string>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not needed

sides_rule = qi::lit("sides=") >
(-(side_type | qi::attr(engine::Side::BOTH)) %
';')[ph::bind(&engine::api::BaseParameters::sides, qi::_r1) = qi::_1];
//(-qi::symbols[qi::char_("aA-zZ")])[ph::bind(add_side, qi::_r1, qi::_1)] % ';';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed

@@ -149,10 +149,17 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
qi::lit("bearings=") >
(-(qi::short_ > ',' > qi::short_))[ph::bind(add_bearing, qi::_r1, qi::_1)] % ';';

side_type.add("d", engine::Side::DEFAULT)("o", engine::Side::OPPOSITE)("b", engine::Side::BOTH);
sides_rule = qi::lit("sides=") >
(-(side_type | qi::attr(engine::Side::BOTH)) %
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here must be either - for vector<optional<Side>> or qi::attr(engine::Side::BOTH) for vector<Side>
- will place empty optionals for empty values, but attr(BOTH) will place BOTH.

(-side_type %';')[...] is enough for vector of optionals

@TheMarex
Copy link
Member

Thanks for adding the tests! Some API features need a quick discussion:

  1. Is there a real use-case for opposite? I feel the actual feature here is the ability to force the curb approach.
  2. Parameter name. I feel something like approach={curb,unrestriced} might be more descriptive.
  3. Do we need the ability to configure this on per-waypoint basis? The scenarios I could come up with (taxi, garbage can pickup) would only need this to be a global flag that applies to all waypoints.

@frodrigo
Copy link
Member

  1. Is there a real use-case for opposite? I feel the actual feature here is the ability to force the curb approach.

Yes we build it for a use case where we need the curb approach. We do not have use case the opposite. But why implement half an option as we can easily make it for both sides? Nevertheless we can remove opposite if you want.

  1. Do we need the ability to configure this on per-waypoint basis? The scenarios I could come up with (taxi, garbage can pickup) would only need this to be a global flag that applies to all waypoints.

We need it per waypoint. E.g. on garbage pickup, the pickup point must be done with the curb approach, but at the depot the side does not matter.

We also plan to add to this PR the support of the approach to other plugins. Especially on the table plugin (approach per waypoint make even more sens on it).

@fijemax fijemax force-pushed the mt-start-side branch 2 times, most recently from 33b0389 to 1f83b36 Compare May 19, 2017 13:08
@TheMarex
Copy link
Member

But why implement half an option as we can easily make it for both sides?

One of the main concerns with adding stuff is usually API-surface area. The fewer options we have, the less likely it is that we need to do a breaking API change. Would be cool if we could limit this to only unrestricted and curb.

We need it per waypoint. E.g. on garbage pickup, the pickup point must be done with the curb approach, but at the depot the side does not matter.

Okay thanks for the explanation. /cc @daniel-j-h because he has been doing a lot of VRP stuff lately and this might be useful for him too?

We also plan to add to this PR the support of the approach to other plugins.

🤔 I think that should already work if the right method was extended, all plugins rely on GetPhantomNodes() which should operate on the BaseParameter (hence works for all plugins, similar to how we handle bearings and radiuses)


I would like to propose the following API:

HTTP

  • approaches={approach}[;{approach}; ...] where approach is a String of either curb or unrestricted (default: unrestricted). Needs to have the same length as the number of coordinates given.

Example: ?approaches=curb;unrestricted;curb;curb;curb;unrestricted or?approaches=curb;;curb;curb;curb;

Node JS

  • approaches Array of Strings that can either be curb or unrestricted. Needs to have the same length as the number of coordinates given. (default: null, which means unrestricted)

Example: {approaches: ["curb", "unrestricted", "curb", "curb"]} or {approaches: ["curb", null, "curb", "curb"]}

@fijemax
Copy link
Contributor Author

fijemax commented May 22, 2017

Hi @TheMarex ,
Thank you for the review, I going to make the changes as respecting your API descriptions.
Also, I will don't know how to retrieve the country's drive side for apply the curb option, is this actually possible ?
For the moment I apply right side by default for curb approach.

@TheMarex
Copy link
Member

Also, I will don't know how to retrieve the country's drive side for apply the curb option, is this actually possible?

Ah this is part of ProfileProperties::left_hand_driving. To use this you would need to extend ContiguousInternalMemoryDataFacadeBase and BaseDataFacade with a new function like bool IsLeftHandDriving() { return m_profile_properties.left_hand_driving; }.

It can be configured in the profile via properties.left_hand_driving = true.

@daniel-j-h
Copy link
Member

We need it per waypoint. E.g. on garbage pickup, the pickup point must be done with the curb approach, but at the depot the side does not matter.

Okay thanks for the explanation. /cc @daniel-j-h because he has been doing a lot of VRP stuff lately and this might be useful for him too?

Yeah I can totally see how this is useful. You can somewhat fake it already setting bearings - but then you need to do some pre-processing / set the bearing constraints manually.

@emiltin
Copy link
Contributor

emiltin commented May 22, 2017

note that ProfileProperties::left_hand_driving is a global property set once by the profile. it doesn't take into account what country the current request (and and waypoint) is located in. so if you're working with a g planet dataset, the api will be wrong in some countries, and right in others.

FILLAU Jean-Maxime added 2 commits May 22, 2017 14:56
 - Adding sides parameter into base parameters, it can take the values SIDE, OPPOSITE or DEFAULT.
 - Adding url parser for "sides" parameter, url values are "s" for SIDE, "o" for OPPOSITE and "d" for DEFAULT, example : "sides=s;s".
 - Checking parameters, if "sides" parameter is used, the number of parameter is the same as number of location.
 - Create a phantom to start at side driving or Opposite side driving.

Signed-off-by: FILLAU Jean-Maxime <[email protected]>
FILLAU Jean-Maxime added 2 commits May 22, 2017 16:07
Signed-off-by: FILLAU Jean-Maxime <[email protected]>
Propagating approach parameter for plugins :
 - tabler
 - nearest
 - trip

Signed-off-by: FILLAU Jean-Maxime <[email protected]>
@fijemax
Copy link
Contributor Author

fijemax commented May 23, 2017

@oxidase
I refactored the API and propagate the param for every phantom nodes search function.
The support for left hand driving is ok.
Cucumber tests are ok and url unit tests too.

@TheMarex
Copy link
Member

@fijemax looks like the only thing that is failing right now is the formating check. Can you try:

./scripts/format.sh

That requires clang-format 3.8.

Copy link
Member

@TheMarex TheMarex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor things need to be fixed. A test for the node bindings would be great too, there seems to be a bug right now.

Thanks for this! Looking forward to shipping this in 5.8.

namespace engine
{

enum Approach
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enum class Approach : std::uint8_t would be better here, for one to remove implicit conversions and to limit the storage requirements to one byte per coordinate.

}

std::vector<PhantomNodeWithDistance>
NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
const float max_distance,
const int bearing,
const int bearing_range) const override final
const int bearing_range,
const engine::Approach approach) const override final
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

engine:: is unnecessary.

}

std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results) const override final
const unsigned max_results,
const engine::Approach approach) const override final
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

engine::

}

std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const double max_distance) const override final
const double max_distance,
const engine::Approach approach) const override final
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

engine::

}

std::vector<PhantomNodeWithDistance>
NearestPhantomNodes(const util::Coordinate input_coordinate,
const unsigned max_results,
const int bearing,
const int bearing_range) const override final
const int bearing_range,
const engine::Approach approach) const override final
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

engine::

@@ -15,6 +16,8 @@
#include <memory>
#include <vector>

#include <util/log.hpp>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed anymore?

@@ -545,6 +578,32 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
return datafacade.GetComponentID(data.forward_segment_id.id).is_tiny;
}

std::pair<bool, bool> approach_usage(const util::Coordinate &input_coordinate,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to ApproachUsage for camel-case. A better name could be CheckApproach.


if (approach_raw->IsNull())
{
params->bearings.emplace_back();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy&Paste error, should be params->approaches.


if (!approaches->IsArray())
{
Nan::ThrowError("Approaches must be an array of arrays of numbers");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error message is wrong: Should be arrays of strings

}
else
{
Nan::ThrowError("'approach' param must be one of [curb, unrestricted]");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approach -> approaches

FILLAU Jean-Maxime added 2 commits May 29, 2017 14:46
Signed-off-by: FILLAU Jean-Maxime <[email protected]>
Suppress "engine::"

Signed-off-by: FILLAU Jean-Maxime <[email protected]>
@fijemax
Copy link
Contributor Author

fijemax commented May 29, 2017

Hi @TheMarex
Change was done.
I don't konw how testing the nodejs binding ?

@TheMarex
Copy link
Member

@fijemax for some examples look at test/nodejs/route.js. What you basically want is to create a request that uses your parameter and try a few permutations that would create an error.

@fijemax
Copy link
Contributor Author

fijemax commented May 30, 2017

@TheMarex When I run nodejs test/nodes/index.js or nodejs test/nodes/route.js I have the following error :
Error: Cannot find module './binding/node_osrm.node'

@fijemax
Copy link
Contributor Author

fijemax commented May 30, 2017

It's ok, I hadn't activate ENABLE_NODE_BINDINGS during cmake compilation.

Signed-off-by: FILLAU Jean-Maxime <[email protected]>
@fijemax
Copy link
Contributor Author

fijemax commented May 30, 2017

@TheMarex the nodejs binding tests was done

@TheMarex
Copy link
Member

@fijemax awesome, this looks good to merge for me. 🎉

@TheMarex TheMarex merged commit 15a1e10 into Project-OSRM:master May 30, 2017
@daniel-j-h
Copy link
Member

Very cool - looking forward to having this in a stable release!

What I just now realized after this was merged is we need

  • a changelog entry (changelog.md)
  • docs for the http api (docs/http.md)
  • docs for the node bindings (docs/nodejs/api.md)

could you run this out or ticket and tag it for the next release @fijemax so we don't forget about it.

(also feel free to write a osm diary / blog post about this if you have the time for it, I can totally see people being interested in this feature :) I wrote a bit about bearings - this one would fit right in)

@fijemax
Copy link
Contributor Author

fijemax commented May 30, 2017

@daniel-j-h I just created this PR #4104.

@fijemax
Copy link
Contributor Author

fijemax commented Jun 19, 2017

Hi @daniel-j-h, i wrote this about the new feature.

@daniel-j-h
Copy link
Member

Sweet, thank you!

@asaveljevs
Copy link
Contributor

  1. Is there a real use-case for opposite? I feel the actual feature here is the ability to force the curb approach.

We have tried to describe our use case for opposite in #5616, which is needed for solving a VRP problem.

@geocept
Copy link

geocept commented Feb 10, 2024

Is there a reason why this great feature is not in the stable release of OSRM?? I mean 6,5 years have passed now and many many people are waiting for it. Would be great if someone would bring it to stable release.

@frodrigo
Copy link
Member

Is there a reason why this great feature is not in the stable release of OSRM?? I mean 6,5 years have passed now and many many people are waiting for it. Would be great if someone would bring it to stable release.

It was released in 5.8.0
https://github.com/Project-OSRM/osrm-backend/blob/master/CHANGELOG.md#580

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants