modify turn angles and instructions
This commit is contained in:
		
							parent
							
								
									ab9426e260
								
							
						
					
					
						commit
						f14352f494
					
				@ -62,13 +62,13 @@ Feature: Bike - Mode flag
 | 
				
			|||||||
     	 | cd    | primary |        |
 | 
					     	 | cd    | primary |        |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     	When I route I should get
 | 
					     	When I route I should get
 | 
				
			||||||
     	 | from | to | route    | turns                       | modes |
 | 
					     	 | from | to | route    | turns                                      | modes |
 | 
				
			||||||
     	 | a    | d  | ab,bc,cd | head,right,left,destination | 1,1,1 |
 | 
					     	 | a    | d  | ab,bc,cd | head,straight,straight,destination         | 1,1,1 |
 | 
				
			||||||
     	 | d    | a  | cd,bc,ab | head,right,left,destination | 1,2,1 |
 | 
					     	 | d    | a  | cd,bc,ab | head,right,left,destination                | 1,2,1 |
 | 
				
			||||||
     	 | c    | a  | bc,ab    | head,left,destination       | 2,1   |
 | 
					     	 | c    | a  | bc,ab    | head,left,destination                      | 2,1   |
 | 
				
			||||||
     	 | d    | b  | cd,bc    | head,right,destination      | 1,2   |
 | 
					     	 | d    | b  | cd,bc    | head,right,destination                     | 1,2   |
 | 
				
			||||||
     	 | a    | c  | ab,bc    | head,right,destination      | 1,1   |
 | 
					     	 | a    | c  | ab,bc    | head,straight,destination                  | 1,1   |
 | 
				
			||||||
     	 | b    | d  | bc,cd    | head,left,destination       | 1,1   |
 | 
					     	 | b    | d  | bc,cd    | head,straight,destination                  | 1,1   |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     Scenario: Bike - Mode when pushing on pedestrain streets
 | 
					     Scenario: Bike - Mode when pushing on pedestrain streets
 | 
				
			||||||
     	Given the node map
 | 
					     	Given the node map
 | 
				
			||||||
 | 
				
			|||||||
@ -98,11 +98,11 @@ Feature: Bike - Accessability of different way types
 | 
				
			|||||||
            | cd    | primary |        |
 | 
					            | cd    | primary |        |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        When I route I should get
 | 
					        When I route I should get
 | 
				
			||||||
            | from | to | route    | turns                       |
 | 
					            | from | to | route    | turns                                      |
 | 
				
			||||||
            | a    | d  | ab,bc,cd | head,right,left,destination |
 | 
					            | a    | d  | ab,bc,cd | head,straight,straight,destination         |
 | 
				
			||||||
            | d    | a  | cd,bc,ab | head,right,left,destination |
 | 
					            | d    | a  | cd,bc,ab | head,right,left,destination                |
 | 
				
			||||||
            | c    | a  | bc,ab    | head,left,destination       |
 | 
					            | c    | a  | bc,ab    | head,left,destination                      |
 | 
				
			||||||
            | d    | b  | cd,bc    | head,right,destination      |
 | 
					            | d    | b  | cd,bc    | head,right,destination                     |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @todo
 | 
					    @todo
 | 
				
			||||||
    Scenario: Bike - Instructions when pushing bike on footway/pedestrian, etc.
 | 
					    Scenario: Bike - Instructions when pushing bike on footway/pedestrian, etc.
 | 
				
			||||||
 | 
				
			|||||||
@ -155,8 +155,9 @@ def turn_list instructions
 | 
				
			|||||||
      13 => :stay_roundabout,
 | 
					      13 => :stay_roundabout,
 | 
				
			||||||
      14 => :start_end_of_street,
 | 
					      14 => :start_end_of_street,
 | 
				
			||||||
      15 => :destination,
 | 
					      15 => :destination,
 | 
				
			||||||
      16 => :enter_contraflow,
 | 
					      16 => :name_changes,
 | 
				
			||||||
      17 => :leave_contraflow
 | 
					      17 => :enter_contraflow,
 | 
				
			||||||
 | 
					      18 => :leave_contraflow
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    # replace instructions codes with strings
 | 
					    # replace instructions codes with strings
 | 
				
			||||||
    # "11-3" (enter roundabout and leave a 3rd exit) gets converted to "enter_roundabout-3"
 | 
					    # "11-3" (enter roundabout and leave a 3rd exit) gets converted to "enter_roundabout-3"
 | 
				
			||||||
 | 
				
			|||||||
@ -36,5 +36,5 @@ Feature: Basic Routing
 | 
				
			|||||||
            | fy     | last  |
 | 
					            | fy     | last  |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        When I route I should get
 | 
					        When I route I should get
 | 
				
			||||||
            | from | to | route            | turns                       |
 | 
					            | from | to | route            | turns                              |
 | 
				
			||||||
            | x    | y  | first,compr,last | head,right,left,destination |
 | 
					            | x    | y  | first,compr,last | head,straight,straight,destination |
 | 
				
			||||||
 | 
				
			|||||||
@ -92,6 +92,6 @@ Feature: Avoid weird loops caused by rounding errors
 | 
				
			|||||||
            | cf    | primary     |
 | 
					            | cf    | primary     |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        When I route I should get
 | 
					        When I route I should get
 | 
				
			||||||
            | waypoints | route             | turns                                      |
 | 
					            | waypoints | route             | turns                                            |
 | 
				
			||||||
            | a,2,d     | ab,be,ef,ef,cf,cd | head,left,right,via,right,left,destination |
 | 
					            | a,2,d     | ab,be,ef,ef,cf,cd | head,left,straight,via,straight,left,destination |
 | 
				
			||||||
            | a,1,d     | ab,be,ef,ef,cf,cd | head,left,right,via,right,left,destination |
 | 
					            | a,1,d     | ab,be,ef,ef,cf,cd | head,left,straight,via,straight,left,destination |
 | 
				
			||||||
 | 
				
			|||||||
@ -17,21 +17,13 @@ Feature: Turn directions/codes
 | 
				
			|||||||
        And the ways
 | 
					        And the ways
 | 
				
			||||||
            | nodes |
 | 
					            | nodes |
 | 
				
			||||||
            | xa    |
 | 
					            | xa    |
 | 
				
			||||||
            | xb    |
 | 
					 | 
				
			||||||
            | xc    |
 | 
					            | xc    |
 | 
				
			||||||
            | xd    |
 | 
					 | 
				
			||||||
            | xe    |
 | 
					            | xe    |
 | 
				
			||||||
            | xf    |
 | 
					 | 
				
			||||||
            | xg    |
 | 
					            | xg    |
 | 
				
			||||||
            | xh    |
 | 
					 | 
				
			||||||
            | xi    |
 | 
					            | xi    |
 | 
				
			||||||
            | xj    |
 | 
					 | 
				
			||||||
            | xk    |
 | 
					            | xk    |
 | 
				
			||||||
            | xl    |
 | 
					 | 
				
			||||||
            | xm    |
 | 
					            | xm    |
 | 
				
			||||||
            | xn    |
 | 
					 | 
				
			||||||
            | xo    |
 | 
					            | xo    |
 | 
				
			||||||
            | xp    |
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        When I match I should get
 | 
					        When I match I should get
 | 
				
			||||||
            | trace | route | turns                         | matchings |
 | 
					            | trace | route | turns                         | matchings |
 | 
				
			||||||
@ -40,7 +32,7 @@ Feature: Turn directions/codes
 | 
				
			|||||||
            | ia    | xi,xa | head,straight,destination     | ia        |
 | 
					            | ia    | xi,xa | head,straight,destination     | ia        |
 | 
				
			||||||
            | ic    | xi,xc | head,slight_right,destination | ic        |
 | 
					            | ic    | xi,xc | head,slight_right,destination | ic        |
 | 
				
			||||||
            | ie    | xi,xe | head,right,destination        | ie        |
 | 
					            | ie    | xi,xe | head,right,destination        | ie        |
 | 
				
			||||||
            
 | 
					
 | 
				
			||||||
            | ko    | xk,xo | head,left,destination         | ko        |
 | 
					            | ko    | xk,xo | head,left,destination         | ko        |
 | 
				
			||||||
            | ka    | xk,xa | head,slight_left,destination  | ka        |
 | 
					            | ka    | xk,xa | head,slight_left,destination  | ka        |
 | 
				
			||||||
            | kc    | xk,xc | head,straight,destination     | kc        |
 | 
					            | kc    | xk,xc | head,straight,destination     | kc        |
 | 
				
			||||||
@ -96,21 +88,13 @@ Feature: Turn directions/codes
 | 
				
			|||||||
        And the ways
 | 
					        And the ways
 | 
				
			||||||
            | nodes |
 | 
					            | nodes |
 | 
				
			||||||
            | xa    |
 | 
					            | xa    |
 | 
				
			||||||
            | xb    |
 | 
					 | 
				
			||||||
            | xc    |
 | 
					            | xc    |
 | 
				
			||||||
            | xd    |
 | 
					 | 
				
			||||||
            | xe    |
 | 
					            | xe    |
 | 
				
			||||||
            | xf    |
 | 
					 | 
				
			||||||
            | xg    |
 | 
					            | xg    |
 | 
				
			||||||
            | xh    |
 | 
					 | 
				
			||||||
            | xi    |
 | 
					            | xi    |
 | 
				
			||||||
            | xj    |
 | 
					 | 
				
			||||||
            | xk    |
 | 
					            | xk    |
 | 
				
			||||||
            | xl    |
 | 
					 | 
				
			||||||
            | xm    |
 | 
					            | xm    |
 | 
				
			||||||
            | xn    |
 | 
					 | 
				
			||||||
            | xo    |
 | 
					            | xo    |
 | 
				
			||||||
            | xp    |
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        When I match I should get
 | 
					        When I match I should get
 | 
				
			||||||
            | trace | route | turns                         | matchings | duration |
 | 
					            | trace | route | turns                         | matchings | duration |
 | 
				
			||||||
 | 
				
			|||||||
@ -174,14 +174,14 @@ Feature: Testbot - Travel mode
 | 
				
			|||||||
            | ef    | primary |       |          |
 | 
					            | ef    | primary |       |          |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
       When I route I should get
 | 
					       When I route I should get
 | 
				
			||||||
            | from | to | route          | turns                                         | modes     |
 | 
					            | from | to | route          | turns                                                 | modes     |
 | 
				
			||||||
            | a    | d  | ab,bc,cd       | head,right,left,destination                   | 1,2,1     |
 | 
					            | a    | d  | ab,bc,cd       | head,right,left,destination                           | 1,2,1     |
 | 
				
			||||||
            | d    | a  | cd,bc,ab       | head,right,left,destination                   | 1,2,1     |
 | 
					            | d    | a  | cd,bc,ab       | head,right,left,destination                           | 1,2,1     |
 | 
				
			||||||
            | c    | a  | bc,ab          | head,left,destination                         | 2,1       |
 | 
					            | c    | a  | bc,ab          | head,left,destination                                 | 2,1       |
 | 
				
			||||||
            | d    | b  | cd,bc          | head,right,destination                        | 1,2       |
 | 
					            | d    | b  | cd,bc          | head,right,destination                                | 1,2       |
 | 
				
			||||||
            | a    | c  | ab,bc          | head,right,destination                        | 1,2       |
 | 
					            | a    | c  | ab,bc          | head,right,destination                                | 1,2       |
 | 
				
			||||||
            | b    | d  | bc,cd          | head,left,destination                         | 2,1       |
 | 
					            | b    | d  | bc,cd          | head,left,destination                                 | 2,1       |
 | 
				
			||||||
            | a    | f  | ab,bc,cd,de,ef | head,right,left,straight,straight,destination | 1,2,1,1,1 |
 | 
					            | a    | f  | ab,bc,cd,de,ef | head,right,left,straight,straight,destination         | 1,2,1,1,1 |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Scenario: Testbot - Modes, triangle map
 | 
					    Scenario: Testbot - Modes, triangle map
 | 
				
			||||||
        Given the node map
 | 
					        Given the node map
 | 
				
			||||||
 | 
				
			|||||||
@ -21,13 +21,13 @@ Feature: POST request
 | 
				
			|||||||
            | bc    |
 | 
					            | bc    |
 | 
				
			||||||
            | xy    |
 | 
					            | xy    |
 | 
				
			||||||
            | yz    |
 | 
					            | yz    |
 | 
				
			||||||
            
 | 
					
 | 
				
			||||||
        When I route I should get
 | 
					        When I route I should get
 | 
				
			||||||
            | from | to | route | turns                  |
 | 
					            | from | to | route | turns                     |
 | 
				
			||||||
            | a    | c  | ab,bc | head,left,destination  |
 | 
					            | a    | c  | ab,bc | head,straight,destination |
 | 
				
			||||||
            | c    | a  | bc,ab | head,right,destination |
 | 
					            | c    | a  | bc,ab | head,straight,destination |
 | 
				
			||||||
            | x    | z  | xy,yz | head,right,destination |
 | 
					            | x    | z  | xy,yz | head,straight,destination |
 | 
				
			||||||
            | z    | x  | yz,xy | head,left,destination  |
 | 
					            | z    | x  | yz,xy | head,straight,destination |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Scenario: Testbot - match POST request
 | 
					    Scenario: Testbot - match POST request
 | 
				
			||||||
        Given a grid size of 10 meters
 | 
					        Given a grid size of 10 meters
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										74
									
								
								features/testbot/turn_angles.feature
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								features/testbot/turn_angles.feature
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					@routing @testbot @via
 | 
				
			||||||
 | 
					Feature: Via points
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Background:
 | 
				
			||||||
 | 
					        Given the profile "testbot"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        And a grid size of 4 meters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Scenario: Basic Right Turn
 | 
				
			||||||
 | 
					        Given the node map
 | 
				
			||||||
 | 
					            | a | b | c | d | e | f | g |
 | 
				
			||||||
 | 
					            |   |   |   |   |   | h |   |
 | 
				
			||||||
 | 
					            |   |   |   |   |   | i |   |
 | 
				
			||||||
 | 
					            |   |   |   |   |   | j |   |
 | 
				
			||||||
 | 
					            |   |   |   |   |   | k |   |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        And the ways
 | 
				
			||||||
 | 
					            | nodes   | oneway |
 | 
				
			||||||
 | 
					            | abcdefg | yes    |
 | 
				
			||||||
 | 
					            | ehijk   | yes    |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        When I route I should get
 | 
				
			||||||
 | 
					            | from | to | route                      | distance  | turns                  |
 | 
				
			||||||
 | 
					            | a    | k  | abcdefg,ehijk              |  34m +-1  | head,right,destination |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Scenario: Slight Turn
 | 
				
			||||||
 | 
					        Given the node map
 | 
				
			||||||
 | 
					            | a | b | c | d | e | f | g |   |
 | 
				
			||||||
 | 
					            |   |   |   |   |   | h | i |   |
 | 
				
			||||||
 | 
					            |   |   |   |   |   |   |   | j |
 | 
				
			||||||
 | 
					            |   |   |   |   |   |   |   | k |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        And the ways
 | 
				
			||||||
 | 
					            | nodes   | oneway |
 | 
				
			||||||
 | 
					            | abcdefg | yes    |
 | 
				
			||||||
 | 
					            | ehijk   | yes    |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        When I route I should get
 | 
				
			||||||
 | 
					            | from | to | route                      | distance  | turns                         |
 | 
				
			||||||
 | 
					            | a    | k  | abcdefg,ehijk              |  34m +-1  | head,slight_right,destination |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Scenario: Nearly Slight Turn
 | 
				
			||||||
 | 
					        Given the node map
 | 
				
			||||||
 | 
					            | a | b | c | d | e | f | g |   |
 | 
				
			||||||
 | 
					            |   |   |   |   |   | h |   |   |
 | 
				
			||||||
 | 
					            |   |   |   |   |   |   | i |   |
 | 
				
			||||||
 | 
					            |   |   |   |   |   |   |   | j |
 | 
				
			||||||
 | 
					            |   |   |   |   |   |   |   | k |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        And the ways
 | 
				
			||||||
 | 
					            | nodes   | oneway |
 | 
				
			||||||
 | 
					            | abcdefg | yes    |
 | 
				
			||||||
 | 
					            | ehijk   | yes    |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        When I route I should get
 | 
				
			||||||
 | 
					            | from | to | route                      | distance  | turns                         |
 | 
				
			||||||
 | 
					            | a    | k  | abcdefg,ehijk              |  37m +-1  | head,right,destination        |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Scenario: Nearly Slight Turn (Variation)
 | 
				
			||||||
 | 
					        Given the node map
 | 
				
			||||||
 | 
					            | a | b | c | d | e | f | g |   |
 | 
				
			||||||
 | 
					            |   |   |   |   |   | h |   |   |
 | 
				
			||||||
 | 
					            |   |   |   |   |   |   | i |   |
 | 
				
			||||||
 | 
					            |   |   |   |   |   |   | j |   |
 | 
				
			||||||
 | 
					            |   |   |   |   |   |   |   | k |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        And the ways
 | 
				
			||||||
 | 
					            | nodes   | oneway |
 | 
				
			||||||
 | 
					            | abcdefg | yes    |
 | 
				
			||||||
 | 
					            | ehijk   | yes    |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        When I route I should get
 | 
				
			||||||
 | 
					            | from | to | route                      | distance  | turns                         |
 | 
				
			||||||
 | 
					            | a    | k  | abcdefg,ehijk              |  37m +-1  | head,right,destination        |
 | 
				
			||||||
@ -14,22 +14,14 @@ Feature: Turn directions/codes
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        And the ways
 | 
					        And the ways
 | 
				
			||||||
            | nodes |
 | 
					            | nodes |
 | 
				
			||||||
            | xa    |
 | 
					 | 
				
			||||||
            | xb    |
 | 
					 | 
				
			||||||
            | xc    |
 | 
					 | 
				
			||||||
            | xd    |
 | 
					 | 
				
			||||||
            | xe    |
 | 
					 | 
				
			||||||
            | xf    |
 | 
					 | 
				
			||||||
            | xg    |
 | 
					 | 
				
			||||||
            | xh    |
 | 
					 | 
				
			||||||
            | xi    |
 | 
					            | xi    |
 | 
				
			||||||
            | xj    |
 | 
					 | 
				
			||||||
            | xk    |
 | 
					            | xk    |
 | 
				
			||||||
            | xl    |
 | 
					 | 
				
			||||||
            | xm    |
 | 
					            | xm    |
 | 
				
			||||||
            | xn    |
 | 
					 | 
				
			||||||
            | xo    |
 | 
					            | xo    |
 | 
				
			||||||
            | xp    |
 | 
					            | xa    |
 | 
				
			||||||
 | 
					            | xc    |
 | 
				
			||||||
 | 
					            | xe    |
 | 
				
			||||||
 | 
					            | xg    |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        When I route I should get
 | 
					        When I route I should get
 | 
				
			||||||
            | from | to | route | turns                         |
 | 
					            | from | to | route | turns                         |
 | 
				
			||||||
@ -116,8 +108,8 @@ Feature: Turn directions/codes
 | 
				
			|||||||
            | yz    |
 | 
					            | yz    |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        When I route I should get
 | 
					        When I route I should get
 | 
				
			||||||
            | from | to | route | turns                  |
 | 
					            | from | to | route | turns                     |
 | 
				
			||||||
            | a    | c  | ab,bc | head,left,destination  |
 | 
					            | a    | c  | ab,bc | head,straight,destination |
 | 
				
			||||||
            | c    | a  | bc,ab | head,right,destination |
 | 
					            | c    | a  | bc,ab | head,straight,destination |
 | 
				
			||||||
            | x    | z  | xy,yz | head,right,destination |
 | 
					            | x    | z  | xy,yz | head,straight,destination |
 | 
				
			||||||
            | z    | x  | yz,xy | head,left,destination  |
 | 
					            | z    | x  | yz,xy | head,straight,destination |
 | 
				
			||||||
 | 
				
			|||||||
@ -20,8 +20,8 @@ Feature: U-turns at via points
 | 
				
			|||||||
            | fg    |
 | 
					            | fg    |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        When I route I should get
 | 
					        When I route I should get
 | 
				
			||||||
            | waypoints | route             | turns                                          |
 | 
					            | waypoints | route                | turns                                                          |
 | 
				
			||||||
            | a,e,c     | ab,be,be,ef,fg,dg,cd | head,right,via,left,straight,left,left,destination |
 | 
					            | a,e,c     | ab,be,be,ef,fg,dg,cd | head,right,via,straight,straight,straight,straight,destination |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Scenario: Query param to allow U-turns at all via points
 | 
					    Scenario: Query param to allow U-turns at all via points
 | 
				
			||||||
        Given the node map
 | 
					        Given the node map
 | 
				
			||||||
 | 
				
			|||||||
@ -86,12 +86,12 @@ Feature: Via points
 | 
				
			|||||||
            | fa    | yes    |
 | 
					            | fa    | yes    |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        When I route I should get
 | 
					        When I route I should get
 | 
				
			||||||
            | waypoints | route                      | distance  | turns                                                               |
 | 
					            | waypoints | route                               | distance  | turns                                                                                                    |
 | 
				
			||||||
            | 1,3       | ab,bc,cd                   |  400m +-1 | head,straight,straight,destination                                  |
 | 
					            | 1,3       | ab,bc,cd                            |  400m +-1 | head,straight,straight,destination                                                                       |
 | 
				
			||||||
            | 3,1       | cd,de,ef,fa,ab             | 1000m +-1 | head,right,right,right,right,destination                            |
 | 
					            | 3,1       | cd,de,ef,fa,ab                      | 1000m +-1 | head,straight,straight,straight,right,destination                                                        |
 | 
				
			||||||
            | 1,2,3     | ab,bc,bc,cd                |  400m +-1 | head,straight,via,straight,destination                              |
 | 
					            | 1,2,3     | ab,bc,bc,cd                         |  400m +-1 | head,straight,via,straight,destination                                                                   |
 | 
				
			||||||
            | 1,3,2     | ab,bc,cd,cd,de,ef,fa,ab,bc | 1600m +-1 | head,straight,straight,via,right,right,right,right,straight,destination |
 | 
					            | 1,3,2     | ab,bc,cd,cd,de,ef,fa,ab,bc          | 1600m +-1 | head,straight,straight,via,straight,straight,straight,right,straight,destination                         |
 | 
				
			||||||
            | 3,2,1     | cd,de,ef,fa,ab,bc,bc,cd,de,ef,fa,ab | 2400m +-1 | head,right,right,right,right,straight,via,straight,right,right,right,right,destination |
 | 
					            | 3,2,1     | cd,de,ef,fa,ab,bc,bc,cd,de,ef,fa,ab | 2400m +-1 | head,straight,straight,straight,right,straight,via,straight,straight,straight,straight,right,destination |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Scenario: Via points on ring on the same oneway
 | 
					    Scenario: Via points on ring on the same oneway
 | 
				
			||||||
    # xa it to avoid only having a single ring, which cna trigger edge cases
 | 
					    # xa it to avoid only having a single ring, which cna trigger edge cases
 | 
				
			||||||
@ -109,12 +109,12 @@ Feature: Via points
 | 
				
			|||||||
            | da    | yes    |
 | 
					            | da    | yes    |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        When I route I should get
 | 
					        When I route I should get
 | 
				
			||||||
            | waypoints | route                      | distance  | turns                                                            |
 | 
					            | waypoints | route                         | distance  | turns                                                                                  |
 | 
				
			||||||
            | 1,3       | ab                         | 200m +-1  | head,destination                                                 |
 | 
					            | 1,3       | ab                            | 200m +-1  | head,destination                                                                       |
 | 
				
			||||||
            | 3,1       | ab,bc,cd,da,ab             | 800m +-1  | head,right,right,right,right,destination                         |
 | 
					            | 3,1       | ab,bc,cd,da,ab                | 800m +-1  | head,straight,straight,straight,right,destination                                      |
 | 
				
			||||||
            | 1,2,3     | ab,ab                      | 200m +-1  | head,via,destination                                             |
 | 
					            | 1,2,3     | ab,ab                         | 200m +-1  | head,via,destination                                                                   |
 | 
				
			||||||
            | 1,3,2     | ab,ab,bc,cd,da,ab          | 1100m +-1 | head,via,right,right,right,right,destination                     |
 | 
					            | 1,3,2     | ab,ab,bc,cd,da,ab             | 1100m +-1 | head,via,straight,straight,straight,right,destination                                  |
 | 
				
			||||||
            | 3,2,1     | ab,bc,cd,da,ab,ab,bc,cd,da,ab | 1800m     | head,right,right,right,right,via,right,right,right,right,destination |
 | 
					            | 3,2,1     | ab,bc,cd,da,ab,ab,bc,cd,da,ab | 1800m     | head,straight,straight,straight,right,via,straight,straight,straight,right,destination |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # See issue #1896
 | 
					    # See issue #1896
 | 
				
			||||||
    Scenario: Via point at a dead end with oneway
 | 
					    Scenario: Via point at a dead end with oneway
 | 
				
			||||||
@ -175,11 +175,11 @@ Feature: Via points
 | 
				
			|||||||
            | da    | yes    |
 | 
					            | da    | yes    |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        When I route I should get
 | 
					        When I route I should get
 | 
				
			||||||
            | waypoints | route                      | distance  | turns                                                            |
 | 
					            | waypoints | route                      | distance   | turns                                                                        |
 | 
				
			||||||
            | 2,1       | ab,bc,cd,da,ab             | 1100m +-1  | head,right,right,right,right,destination                         |
 | 
					            | 2,1       | ab,bc,cd,da,ab             | 1100m +-1  | head,straight,straight,straight,straight,destination                         |
 | 
				
			||||||
            | 4,3       | bc,cd,da,ab,bc             | 1100m +-1  | head,right,right,right,right,destination                         |
 | 
					            | 4,3       | bc,cd,da,ab,bc             | 1100m +-1  | head,straight,straight,straight,straight,destination                         |
 | 
				
			||||||
            | 6,5       | cd,da,ab,bc,cd             | 1100m +-1  | head,right,right,right,right,destination                         |
 | 
					            | 6,5       | cd,da,ab,bc,cd             | 1100m +-1  | head,straight,straight,straight,straight,destination                         |
 | 
				
			||||||
            | 8,7       | da,ab,bc,cd,da             | 1100m +-1  | head,right,right,right,right,destination                         |
 | 
					            | 8,7       | da,ab,bc,cd,da             | 1100m +-1  | head,straight,straight,straight,straight,destination                         |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Scenario: Multiple Via points on ring on the same oneway, forces one of the vertices to be top node
 | 
					    Scenario: Multiple Via points on ring on the same oneway, forces one of the vertices to be top node
 | 
				
			||||||
        Given the node map
 | 
					        Given the node map
 | 
				
			||||||
@ -197,7 +197,7 @@ Feature: Via points
 | 
				
			|||||||
            | da    | yes    |
 | 
					            | da    | yes    |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        When I route I should get
 | 
					        When I route I should get
 | 
				
			||||||
            | waypoints | route                      | distance  | turns                                                            |
 | 
					            | waypoints | route                         | distance     | turns                                                                                        |
 | 
				
			||||||
            | 3,2,1     | ab,bc,cd,da,ab,ab,bc,cd,da,ab | 3000m +-1    | head,right,right,right,right,via,right,right,right,right,destination |
 | 
					            | 3,2,1     | ab,bc,cd,da,ab,ab,bc,cd,da,ab | 3000m +-1    | head,straight,straight,straight,straight,via,straight,straight,straight,straight,destination |
 | 
				
			||||||
            | 6,5,4     | bc,cd,da,ab,bc,bc,cd,da,ab,bc | 3000m +-1    | head,right,right,right,right,via,right,right,right,right,destination |
 | 
					            | 6,5,4     | bc,cd,da,ab,bc,bc,cd,da,ab,bc | 3000m +-1    | head,straight,straight,straight,straight,via,straight,straight,straight,straight,destination |
 | 
				
			||||||
            | 9,8,7     | cd,da,ab,bc,cd,cd,da,ab,bc,cd | 3000m +-1    | head,right,right,right,right,via,right,right,right,right,destination |
 | 
					            | 9,8,7     | cd,da,ab,bc,cd,cd,da,ab,bc,cd | 3000m +-1    | head,straight,straight,straight,straight,via,straight,straight,straight,straight,destination |
 | 
				
			||||||
 | 
				
			|||||||
@ -106,7 +106,8 @@ SegmentList<DataFacadeT>::SegmentList(const InternalRouteResult &raw_route,
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                const auto &source_phantom =
 | 
					                const auto &source_phantom =
 | 
				
			||||||
                    raw_route.segment_end_coordinates[raw_index].target_phantom;
 | 
					                    raw_route.segment_end_coordinates[raw_index].target_phantom;
 | 
				
			||||||
                if (raw_route.target_traversed_in_reverse[raw_index] != raw_route.source_traversed_in_reverse[raw_index+1])
 | 
					                if (raw_route.target_traversed_in_reverse[raw_index] !=
 | 
				
			||||||
 | 
					                    raw_route.source_traversed_in_reverse[raw_index + 1])
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    bool traversed_in_reverse = raw_route.target_traversed_in_reverse[raw_index];
 | 
					                    bool traversed_in_reverse = raw_route.target_traversed_in_reverse[raw_index];
 | 
				
			||||||
                    const extractor::TravelMode travel_mode =
 | 
					                    const extractor::TravelMode travel_mode =
 | 
				
			||||||
@ -264,6 +265,12 @@ void SegmentList<DataFacadeT>::Finalize(const bool extract_alternative,
 | 
				
			|||||||
            segment_length = 0;
 | 
					            segment_length = 0;
 | 
				
			||||||
            segment_duration = 0;
 | 
					            segment_duration = 0;
 | 
				
			||||||
            segment_start_index = i;
 | 
					            segment_start_index = i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (segments[i].turn_instruction == extractor::TurnInstruction::NameChanges)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                segments[i].turn_instruction =
 | 
				
			||||||
 | 
					                    extractor::TurnInstruction::GoStraight; // to not break the api
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,6 @@
 | 
				
			|||||||
#include "engine/search_engine.hpp"
 | 
					#include "engine/search_engine.hpp"
 | 
				
			||||||
#include "util/for_each_pair.hpp"
 | 
					#include "util/for_each_pair.hpp"
 | 
				
			||||||
#include "util/integer_range.hpp"
 | 
					#include "util/integer_range.hpp"
 | 
				
			||||||
#include "util/json_renderer.hpp"
 | 
					 | 
				
			||||||
#include "util/make_unique.hpp"
 | 
					#include "util/make_unique.hpp"
 | 
				
			||||||
#include "util/simple_logger.hpp"
 | 
					#include "util/simple_logger.hpp"
 | 
				
			||||||
#include "util/timing_util.hpp"
 | 
					#include "util/timing_util.hpp"
 | 
				
			||||||
@ -166,7 +165,6 @@ template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
 | 
				
			|||||||
                return Status::Error;
 | 
					                return Status::Error;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        return Status::Ok;
 | 
					        return Status::Ok;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,8 @@
 | 
				
			|||||||
#include "extractor/restriction_map.hpp"
 | 
					#include "extractor/restriction_map.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					#include <cstddef>
 | 
				
			||||||
#include <iosfwd>
 | 
					#include <iosfwd>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <queue>
 | 
					#include <queue>
 | 
				
			||||||
@ -23,6 +25,7 @@
 | 
				
			|||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
#include <unordered_set>
 | 
					#include <unordered_set>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <boost/filesystem/fstream.hpp>
 | 
					#include <boost/filesystem/fstream.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -70,10 +73,18 @@ class EdgeBasedGraphFactory
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    unsigned GetHighestEdgeID();
 | 
					    unsigned GetHighestEdgeID();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TurnInstruction
 | 
					    // Basic analysis of a turn (u --(e1)-- v --(e2)-- w)
 | 
				
			||||||
    AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, const double angle) const;
 | 
					    // with known angle.
 | 
				
			||||||
 | 
					    // Handles special cases like u-turns and roundabouts
 | 
				
			||||||
 | 
					    // For basic turns, the turn based on the angle-classification is returned
 | 
				
			||||||
 | 
					    TurnInstruction AnalyzeTurn(const NodeID u,
 | 
				
			||||||
 | 
					                                const EdgeID e1,
 | 
				
			||||||
 | 
					                                const NodeID v,
 | 
				
			||||||
 | 
					                                const EdgeID e2,
 | 
				
			||||||
 | 
					                                const NodeID w,
 | 
				
			||||||
 | 
					                                const double angle) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int GetTurnPenalty(double angle, lua_State *lua_state) const;
 | 
					    std::int32_t GetTurnPenalty(double angle, lua_State *lua_state) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private:
 | 
					  private:
 | 
				
			||||||
    using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
 | 
					    using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
 | 
				
			||||||
@ -123,8 +134,54 @@ class EdgeBasedGraphFactory
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void FlushVectorToStream(std::ofstream &edge_data_file,
 | 
					    void FlushVectorToStream(std::ofstream &edge_data_file,
 | 
				
			||||||
                             std::vector<OriginalEdgeData> &original_edge_data_vector) const;
 | 
					                             std::vector<OriginalEdgeData> &original_edge_data_vector) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct TurnCandidate
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        EdgeID eid; // the id of the arc
 | 
				
			||||||
 | 
					        bool valid; // a turn may be relevant to good instructions, even if we cannot take the road
 | 
				
			||||||
 | 
					        double angle;                // the approximated angle of the turn
 | 
				
			||||||
 | 
					        TurnInstruction instruction; // a proposed instruction
 | 
				
			||||||
 | 
					        double confidence;           // how close to the border is the turn?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::string toString() const
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            std::string result = "[turn] ";
 | 
				
			||||||
 | 
					            result += std::to_string(eid);
 | 
				
			||||||
 | 
					            result += " valid: ";
 | 
				
			||||||
 | 
					            result += std::to_string(valid);
 | 
				
			||||||
 | 
					            result += " angle: ";
 | 
				
			||||||
 | 
					            result += std::to_string(angle);
 | 
				
			||||||
 | 
					            result += " instruction: ";
 | 
				
			||||||
 | 
					            result += std::to_string(static_cast<std::int32_t>(instruction));
 | 
				
			||||||
 | 
					            result += " confidence: ";
 | 
				
			||||||
 | 
					            result += std::to_string(confidence);
 | 
				
			||||||
 | 
					            return result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Use In Order to generate base turns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // cannot be const due to the counters...
 | 
				
			||||||
 | 
					    std::vector<TurnCandidate> getTurnCandidates(NodeID from, EdgeID via_edge);
 | 
				
			||||||
 | 
					    std::vector<TurnCandidate> optimizeCandidates(NodeID via_edge,
 | 
				
			||||||
 | 
					                                                  std::vector<TurnCandidate> turn_candidates) const;
 | 
				
			||||||
 | 
					    std::vector<TurnCandidate> suppressTurns(EdgeID via_edge,
 | 
				
			||||||
 | 
					                                             std::vector<TurnCandidate> turn_candidates) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QueryNode getRepresentativeCoordinate(const NodeID src,
 | 
				
			||||||
 | 
					                                          const NodeID tgt,
 | 
				
			||||||
 | 
					                                          const EdgeID via_eid,
 | 
				
			||||||
 | 
					                                          bool INVERTED) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool isObviousChoice(EdgeID coming_from_eid,
 | 
				
			||||||
 | 
					                         std::size_t turn_index,
 | 
				
			||||||
 | 
					                         const std::vector<TurnCandidate> &turn_candidates) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::size_t restricted_turns_counter;
 | 
				
			||||||
 | 
					    std::size_t skipped_uturns_counter;
 | 
				
			||||||
 | 
					    std::size_t skipped_barrier_turns_counter;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					} // namespace extractor
 | 
				
			||||||
}
 | 
					} // namespace osrm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* EDGE_BASED_GRAPH_FACTORY_HPP_ */
 | 
					#endif /* EDGE_BASED_GRAPH_FACTORY_HPP_ */
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ struct QueryNode
 | 
				
			|||||||
    using key_type = OSMNodeID; // type of NodeID
 | 
					    using key_type = OSMNodeID; // type of NodeID
 | 
				
			||||||
    using value_type = int;     // type of lat,lons
 | 
					    using value_type = int;     // type of lat,lons
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    explicit QueryNode(int lat, int lon, OSMNodeID node_id)
 | 
					    explicit QueryNode(int lat, int lon, key_type node_id)
 | 
				
			||||||
        : lat(lat), lon(lon), node_id(std::move(node_id))
 | 
					        : lat(lat), lon(lon), node_id(std::move(node_id))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -29,7 +29,7 @@ struct QueryNode
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    int lat;
 | 
					    int lat;
 | 
				
			||||||
    int lon;
 | 
					    int lon;
 | 
				
			||||||
    OSMNodeID node_id;
 | 
					    key_type node_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static QueryNode min_value()
 | 
					    static QueryNode min_value()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,11 @@
 | 
				
			|||||||
#ifndef TURN_INSTRUCTIONS_HPP
 | 
					#ifndef TURN_INSTRUCTIONS_HPP
 | 
				
			||||||
#define TURN_INSTRUCTIONS_HPP
 | 
					#define TURN_INSTRUCTIONS_HPP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <cmath>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <boost/assert.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace osrm
 | 
					namespace osrm
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
namespace extractor
 | 
					namespace extractor
 | 
				
			||||||
@ -24,6 +29,7 @@ enum class TurnInstruction : unsigned char
 | 
				
			|||||||
    StayOnRoundAbout,
 | 
					    StayOnRoundAbout,
 | 
				
			||||||
    StartAtEndOfStreet,
 | 
					    StartAtEndOfStreet,
 | 
				
			||||||
    ReachedYourDestination,
 | 
					    ReachedYourDestination,
 | 
				
			||||||
 | 
					    NameChanges,
 | 
				
			||||||
    EnterAgainstAllowedDirection,
 | 
					    EnterAgainstAllowedDirection,
 | 
				
			||||||
    LeaveAgainstAllowedDirection,
 | 
					    LeaveAgainstAllowedDirection,
 | 
				
			||||||
    InverseAccessRestrictionFlag = 127,
 | 
					    InverseAccessRestrictionFlag = 127,
 | 
				
			||||||
@ -31,37 +37,87 @@ enum class TurnInstruction : unsigned char
 | 
				
			|||||||
    AccessRestrictionPenalty = 129
 | 
					    AccessRestrictionPenalty = 129
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// shiftable turns to left and right
 | 
				
			||||||
 | 
					const constexpr bool shiftable_left[] = {false, false, true, true, true, false, false, true, true};
 | 
				
			||||||
 | 
					const constexpr bool shiftable_right[] = {false, false, true, true, false, false, true, true, true};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline TurnInstruction shiftTurnToLeft(TurnInstruction turn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BOOST_ASSERT_MSG(static_cast<int>(turn) < 9,
 | 
				
			||||||
 | 
					                     "Shift turn only supports basic turn instructions");
 | 
				
			||||||
 | 
					    if (turn > TurnInstruction::TurnSlightLeft)
 | 
				
			||||||
 | 
					        return turn;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        return shiftable_left[static_cast<int>(turn)]
 | 
				
			||||||
 | 
					                   ? (static_cast<TurnInstruction>(static_cast<int>(turn) - 1))
 | 
				
			||||||
 | 
					                   : turn;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline TurnInstruction shiftTurnToRight(TurnInstruction turn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BOOST_ASSERT_MSG(static_cast<int>(turn) < 9,
 | 
				
			||||||
 | 
					                     "Shift turn only supports basic turn instructions");
 | 
				
			||||||
 | 
					    if (turn > TurnInstruction::TurnSlightLeft)
 | 
				
			||||||
 | 
					        return turn;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        return shiftable_right[static_cast<int>(turn)]
 | 
				
			||||||
 | 
					                   ? (static_cast<TurnInstruction>(static_cast<int>(turn) + 1))
 | 
				
			||||||
 | 
					                   : turn;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline double angularDeviation(const double angle, const double from)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const double deviation = std::abs(angle - from);
 | 
				
			||||||
 | 
					    return std::min(360 - deviation, deviation);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline double getAngularPenalty(const double angle, TurnInstruction instruction)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BOOST_ASSERT_MSG(static_cast<int>(instruction) < 9,
 | 
				
			||||||
 | 
					                     "Angular penalty only supports basic turn instructions");
 | 
				
			||||||
 | 
					    const double center[] = {180, 180, 135, 90, 45,
 | 
				
			||||||
 | 
					                             0,   315, 270, 225}; // centers of turns from getTurnDirection
 | 
				
			||||||
 | 
					    return angularDeviation(center[static_cast<int>(instruction)], angle);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline double getTurnConfidence(const double angle, TurnInstruction instruction)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // special handling of U-Turns and Roundabout
 | 
				
			||||||
 | 
					    if (instruction >= TurnInstruction::HeadOn || instruction == TurnInstruction::UTurn ||
 | 
				
			||||||
 | 
					        instruction == TurnInstruction::NoTurn || instruction == TurnInstruction::EnterRoundAbout ||
 | 
				
			||||||
 | 
					        instruction == TurnInstruction::StayOnRoundAbout || instruction == TurnInstruction::LeaveRoundAbout )
 | 
				
			||||||
 | 
					        return 1.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BOOST_ASSERT_MSG(static_cast<int>(instruction) < 9,
 | 
				
			||||||
 | 
					                     "Turn confidence only supports basic turn instructions");
 | 
				
			||||||
 | 
					    const double deviations[] = {10, 10, 35, 50, 45, 0, 45, 50, 35};
 | 
				
			||||||
 | 
					    const double difference = getAngularPenalty(angle, instruction);
 | 
				
			||||||
 | 
					    const double max_deviation = deviations[static_cast<int>(instruction)];
 | 
				
			||||||
 | 
					    return 1.0 - (difference / max_deviation) * (difference / max_deviation);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Translates between angles and their human-friendly directional representation
 | 
					// Translates between angles and their human-friendly directional representation
 | 
				
			||||||
inline TurnInstruction getTurnDirection(const double angle)
 | 
					inline TurnInstruction getTurnDirection(const double angle)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (angle >= 23 && angle < 67)
 | 
					    // An angle of zero is a u-turn
 | 
				
			||||||
    {
 | 
					    // 180 goes perfectly straight
 | 
				
			||||||
 | 
					    // 0-180 are right turns
 | 
				
			||||||
 | 
					    // 180-360 are left turns
 | 
				
			||||||
 | 
					    if (angle > 0 && angle < 60)
 | 
				
			||||||
        return TurnInstruction::TurnSharpRight;
 | 
					        return TurnInstruction::TurnSharpRight;
 | 
				
			||||||
    }
 | 
					    if (angle >= 60 && angle < 140)
 | 
				
			||||||
    if (angle >= 67 && angle < 113)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return TurnInstruction::TurnRight;
 | 
					        return TurnInstruction::TurnRight;
 | 
				
			||||||
    }
 | 
					    if (angle >= 140 && angle < 170)
 | 
				
			||||||
    if (angle >= 113 && angle < 158)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return TurnInstruction::TurnSlightRight;
 | 
					        return TurnInstruction::TurnSlightRight;
 | 
				
			||||||
    }
 | 
					    if (angle >= 170 && angle <= 190)
 | 
				
			||||||
    if (angle >= 158 && angle < 202)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return TurnInstruction::GoStraight;
 | 
					        return TurnInstruction::GoStraight;
 | 
				
			||||||
    }
 | 
					    if (angle > 190 && angle <= 220)
 | 
				
			||||||
    if (angle >= 202 && angle < 248)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return TurnInstruction::TurnSlightLeft;
 | 
					        return TurnInstruction::TurnSlightLeft;
 | 
				
			||||||
    }
 | 
					    if (angle > 220 && angle <= 300)
 | 
				
			||||||
    if (angle >= 248 && angle < 292)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return TurnInstruction::TurnLeft;
 | 
					        return TurnInstruction::TurnLeft;
 | 
				
			||||||
    }
 | 
					    if (angle > 300 && angle < 360)
 | 
				
			||||||
    if (angle >= 292 && angle < 336)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return TurnInstruction::TurnSharpLeft;
 | 
					        return TurnInstruction::TurnSharpLeft;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return TurnInstruction::UTurn;
 | 
					    return TurnInstruction::UTurn;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -75,6 +131,51 @@ inline bool isTurnNecessary(const TurnInstruction turn_instruction)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline bool resolve(TurnInstruction &to_resolve, const TurnInstruction neighbor, bool resolve_right)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const auto shifted_turn =
 | 
				
			||||||
 | 
					        resolve_right ? shiftTurnToRight(to_resolve) : shiftTurnToLeft(to_resolve);
 | 
				
			||||||
 | 
					    if (shifted_turn == neighbor || shifted_turn == to_resolve)
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    to_resolve = shifted_turn;
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline bool resolveTransitive(TurnInstruction &first,
 | 
				
			||||||
 | 
					                              TurnInstruction &second,
 | 
				
			||||||
 | 
					                              const TurnInstruction third,
 | 
				
			||||||
 | 
					                              bool resolve_right)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (resolve(second, third, resolve_right))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        first = resolve_right ? shiftTurnToRight(first) : shiftTurnToLeft(first);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline bool isSlightTurn(const TurnInstruction turn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return turn == TurnInstruction::GoStraight || turn == TurnInstruction::TurnSlightRight ||
 | 
				
			||||||
 | 
					           turn == TurnInstruction::TurnSlightLeft || turn == TurnInstruction::NoTurn;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline bool isSharpTurn(const TurnInstruction turn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return turn == TurnInstruction::TurnSharpLeft || turn == TurnInstruction::TurnSharpRight;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline bool isStraight(const TurnInstruction turn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return turn == TurnInstruction::GoStraight || turn == TurnInstruction::NoTurn;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline bool isConflict(const TurnInstruction first, const TurnInstruction second)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return first == second || (isStraight(first) && isStraight(second));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
#include "extractor/edge_based_edge.hpp"
 | 
					#include "extractor/edge_based_edge.hpp"
 | 
				
			||||||
#include "extractor/edge_based_graph_factory.hpp"
 | 
					#include "extractor/edge_based_graph_factory.hpp"
 | 
				
			||||||
 | 
					#include "util/coordinate.hpp"
 | 
				
			||||||
#include "util/coordinate_calculation.hpp"
 | 
					#include "util/coordinate_calculation.hpp"
 | 
				
			||||||
#include "util/percent.hpp"
 | 
					#include "util/percent.hpp"
 | 
				
			||||||
#include "util/integer_range.hpp"
 | 
					#include "util/integer_range.hpp"
 | 
				
			||||||
@ -12,15 +13,38 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <boost/assert.hpp>
 | 
					#include <boost/assert.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <cmath>
 | 
				
			||||||
#include <fstream>
 | 
					#include <fstream>
 | 
				
			||||||
#include <iomanip>
 | 
					#include <iomanip>
 | 
				
			||||||
#include <limits>
 | 
					#include <limits>
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace osrm
 | 
					namespace osrm
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
namespace extractor
 | 
					namespace extractor
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// configuration of turn classification
 | 
				
			||||||
 | 
					const bool constexpr INVERT = true;
 | 
				
			||||||
 | 
					const bool constexpr RESOLVE_TO_RIGHT = true;
 | 
				
			||||||
 | 
					const bool constexpr RESOLVE_TO_LEFT = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// what angle is interpreted as going straight
 | 
				
			||||||
 | 
					const double constexpr STRAIGHT_ANGLE = 180.;
 | 
				
			||||||
 | 
					// if a turn deviates this much from going straight, it will be kept straight
 | 
				
			||||||
 | 
					const double constexpr MAXIMAL_ALLOWED_NO_TURN_DEVIATION = 2.;
 | 
				
			||||||
 | 
					// angle that lies between two nearly indistinguishable roads
 | 
				
			||||||
 | 
					const double constexpr NARROW_TURN_ANGLE = 25.;
 | 
				
			||||||
 | 
					// angle difference that can be classified as straight, if its the only narrow turn
 | 
				
			||||||
 | 
					const double constexpr FUZZY_STRAIGHT_ANGLE = 15.;
 | 
				
			||||||
 | 
					const double constexpr DISTINCTION_RATIO = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Configuration to find representative candidate for turn angle calculations
 | 
				
			||||||
 | 
					const double constexpr MINIMAL_SEGMENT_LENGTH = 1.;
 | 
				
			||||||
 | 
					const double constexpr DESIRED_SEGMENT_LENGTH = 10.;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
 | 
					EdgeBasedGraphFactory::EdgeBasedGraphFactory(
 | 
				
			||||||
    std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
 | 
					    std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
 | 
				
			||||||
    const CompressedEdgeContainer &compressed_edge_container,
 | 
					    const CompressedEdgeContainer &compressed_edge_container,
 | 
				
			||||||
@ -361,8 +385,12 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    util::SimpleLogger().Write() << "generating edge-expanded edges";
 | 
					    util::SimpleLogger().Write() << "generating edge-expanded edges";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unsigned node_based_edge_counter = 0;
 | 
					    std::size_t node_based_edge_counter = 0;
 | 
				
			||||||
    unsigned original_edges_counter = 0;
 | 
					    std::size_t original_edges_counter = 0;
 | 
				
			||||||
 | 
					    restricted_turns_counter = 0;
 | 
				
			||||||
 | 
					    skipped_uturns_counter = 0;
 | 
				
			||||||
 | 
					    skipped_barrier_turns_counter = 0;
 | 
				
			||||||
 | 
					    std::size_t compressed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::ofstream edge_data_file(original_edge_data_filename.c_str(), std::ios::binary);
 | 
					    std::ofstream edge_data_file(original_edge_data_filename.c_str(), std::ios::binary);
 | 
				
			||||||
    std::ofstream edge_segment_file;
 | 
					    std::ofstream edge_segment_file;
 | 
				
			||||||
@ -383,11 +411,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
				
			|||||||
    // Loop over all turns and generate new set of edges.
 | 
					    // Loop over all turns and generate new set of edges.
 | 
				
			||||||
    // Three nested loop look super-linear, but we are dealing with a (kind of)
 | 
					    // Three nested loop look super-linear, but we are dealing with a (kind of)
 | 
				
			||||||
    // linear number of turns only.
 | 
					    // linear number of turns only.
 | 
				
			||||||
    unsigned restricted_turns_counter = 0;
 | 
					 | 
				
			||||||
    unsigned skipped_uturns_counter = 0;
 | 
					 | 
				
			||||||
    unsigned skipped_barrier_turns_counter = 0;
 | 
					 | 
				
			||||||
    unsigned compressed = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    util::Percent progress(m_node_based_graph->GetNumberOfNodes());
 | 
					    util::Percent progress(m_node_based_graph->GetNumberOfNodes());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef DEBUG_GEOMETRY
 | 
					#ifdef DEBUG_GEOMETRY
 | 
				
			||||||
@ -397,79 +420,30 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
				
			|||||||
    for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
 | 
					    for (const auto node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // progress.printStatus(node_u);
 | 
					        // progress.printStatus(node_u);
 | 
				
			||||||
        for (const EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(node_u))
 | 
					        for (const EdgeID edge_form_u : m_node_based_graph->GetAdjacentEdgeRange(node_u))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (m_node_based_graph->GetEdgeData(e1).reversed)
 | 
					            if (m_node_based_graph->GetEdgeData(edge_form_u).reversed)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ++node_based_edge_counter;
 | 
					            ++node_based_edge_counter;
 | 
				
			||||||
            const NodeID node_v = m_node_based_graph->GetTarget(e1);
 | 
					            auto turn_candidates = getTurnCandidates(node_u, edge_form_u);
 | 
				
			||||||
            const NodeID only_restriction_to_node =
 | 
					            turn_candidates = optimizeCandidates(edge_form_u, turn_candidates);
 | 
				
			||||||
                m_restriction_map->CheckForEmanatingIsOnlyTurn(node_u, node_v);
 | 
					            turn_candidates = suppressTurns(edge_form_u, turn_candidates);
 | 
				
			||||||
            const bool is_barrier_node = m_barrier_nodes.find(node_v) != m_barrier_nodes.end();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (const EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(node_v))
 | 
					            const NodeID node_v = m_node_based_graph->GetTarget(edge_form_u);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (const auto turn : turn_candidates)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (m_node_based_graph->GetEdgeData(e2).reversed)
 | 
					                if (!turn.valid)
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                const NodeID node_w = m_node_based_graph->GetTarget(e2);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if ((only_restriction_to_node != SPECIAL_NODEID) &&
 | 
					                const double turn_angle = turn.angle;
 | 
				
			||||||
                    (node_w != only_restriction_to_node))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    // We are at an only_-restriction but not at the right turn.
 | 
					 | 
				
			||||||
                    ++restricted_turns_counter;
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (is_barrier_node)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    if (node_u != node_w)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        ++skipped_barrier_turns_counter;
 | 
					 | 
				
			||||||
                        continue;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    if (node_u == node_w && m_node_based_graph->GetOutDegree(node_v) > 1)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        auto number_of_emmiting_bidirectional_edges = 0;
 | 
					 | 
				
			||||||
                        for (auto edge : m_node_based_graph->GetAdjacentEdgeRange(node_v))
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            auto target = m_node_based_graph->GetTarget(edge);
 | 
					 | 
				
			||||||
                            auto reverse_edge = m_node_based_graph->FindEdge(target, node_v);
 | 
					 | 
				
			||||||
                            if (!m_node_based_graph->GetEdgeData(reverse_edge).reversed)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                ++number_of_emmiting_bidirectional_edges;
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        if (number_of_emmiting_bidirectional_edges > 1)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            ++skipped_uturns_counter;
 | 
					 | 
				
			||||||
                            continue;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // only add an edge if turn is not a U-turn except when it is
 | 
					 | 
				
			||||||
                // at the end of a dead-end street
 | 
					 | 
				
			||||||
                if (m_restriction_map->CheckIfTurnIsRestricted(node_u, node_v, node_w) &&
 | 
					 | 
				
			||||||
                    (only_restriction_to_node == SPECIAL_NODEID) &&
 | 
					 | 
				
			||||||
                    (node_w != only_restriction_to_node))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    // We are at an only_-restriction but not at the right turn.
 | 
					 | 
				
			||||||
                    ++restricted_turns_counter;
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // only add an edge if turn is not prohibited
 | 
					                // only add an edge if turn is not prohibited
 | 
				
			||||||
                const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(e1);
 | 
					                const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(edge_form_u);
 | 
				
			||||||
                const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(e2);
 | 
					                const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
 | 
					                BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
 | 
				
			||||||
                BOOST_ASSERT(!edge_data1.reversed);
 | 
					                BOOST_ASSERT(!edge_data1.reversed);
 | 
				
			||||||
@ -485,23 +459,9 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
				
			|||||||
                                       speed_profile.traffic_signal_penalty);
 | 
					                                       speed_profile.traffic_signal_penalty);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // unpack last node of first segment if packed
 | 
					 | 
				
			||||||
                const auto first_coordinate =
 | 
					 | 
				
			||||||
                    m_node_info_list[(m_compressed_edge_container.HasEntryForID(e1)
 | 
					 | 
				
			||||||
                                          ? m_compressed_edge_container.GetLastEdgeSourceID(e1)
 | 
					 | 
				
			||||||
                                          : node_u)];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // unpack first node of second segment if packed
 | 
					 | 
				
			||||||
                const auto third_coordinate =
 | 
					 | 
				
			||||||
                    m_node_info_list[(m_compressed_edge_container.HasEntryForID(e2)
 | 
					 | 
				
			||||||
                                          ? m_compressed_edge_container.GetFirstEdgeTargetID(e2)
 | 
					 | 
				
			||||||
                                          : node_w)];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                const double turn_angle = util::coordinate_calculation::computeAngle(
 | 
					 | 
				
			||||||
                    first_coordinate, m_node_info_list[node_v], third_coordinate);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                const int turn_penalty = GetTurnPenalty(turn_angle, lua_state);
 | 
					                const int turn_penalty = GetTurnPenalty(turn_angle, lua_state);
 | 
				
			||||||
                TurnInstruction turn_instruction = AnalyzeTurn(node_u, node_v, node_w, turn_angle);
 | 
					                const TurnInstruction turn_instruction = turn.instruction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (turn_instruction == TurnInstruction::UTurn)
 | 
					                if (turn_instruction == TurnInstruction::UTurn)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    distance += speed_profile.u_turn_penalty;
 | 
					                    distance += speed_profile.u_turn_penalty;
 | 
				
			||||||
@ -509,12 +469,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
				
			|||||||
                    util::DEBUG_UTURN(node_v, m_node_info_list, speed_profile.u_turn_penalty);
 | 
					                    util::DEBUG_UTURN(node_v, m_node_info_list, speed_profile.u_turn_penalty);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                util::DEBUG_TURN(node_v, m_node_info_list, first_coordinate, turn_angle,
 | 
					 | 
				
			||||||
                                 turn_penalty);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                distance += turn_penalty;
 | 
					                distance += turn_penalty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const bool edge_is_compressed = m_compressed_edge_container.HasEntryForID(e1);
 | 
					                const bool edge_is_compressed =
 | 
				
			||||||
 | 
					                    m_compressed_edge_container.HasEntryForID(edge_form_u);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (edge_is_compressed)
 | 
					                if (edge_is_compressed)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@ -522,7 +480,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                original_edge_data_vector.emplace_back(
 | 
					                original_edge_data_vector.emplace_back(
 | 
				
			||||||
                    (edge_is_compressed ? m_compressed_edge_container.GetPositionForID(e1)
 | 
					                    (edge_is_compressed ? m_compressed_edge_container.GetPositionForID(edge_form_u)
 | 
				
			||||||
                                        : node_v),
 | 
					                                        : node_v),
 | 
				
			||||||
                    edge_data1.name_id, turn_instruction, edge_is_compressed,
 | 
					                    edge_data1.name_id, turn_instruction, edge_is_compressed,
 | 
				
			||||||
                    edge_data2.travel_mode);
 | 
					                    edge_data2.travel_mode);
 | 
				
			||||||
@ -563,7 +521,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
				
			|||||||
                    if (edge_is_compressed)
 | 
					                    if (edge_is_compressed)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        const auto node_based_edges =
 | 
					                        const auto node_based_edges =
 | 
				
			||||||
                            m_compressed_edge_container.GetBucketReference(e1);
 | 
					                            m_compressed_edge_container.GetBucketReference(edge_form_u);
 | 
				
			||||||
                        NodeID previous = node_u;
 | 
					                        NodeID previous = node_u;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        const unsigned node_count = node_based_edges.size() + 1;
 | 
					                        const unsigned node_count = node_based_edges.size() + 1;
 | 
				
			||||||
@ -638,6 +596,470 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
 | 
				
			|||||||
                                 << " turns over barriers";
 | 
					                                 << " turns over barriers";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// requires sorted candidates
 | 
				
			||||||
 | 
					std::vector<EdgeBasedGraphFactory::TurnCandidate>
 | 
				
			||||||
 | 
					EdgeBasedGraphFactory::optimizeCandidates(NodeID via_eid,
 | 
				
			||||||
 | 
					                                          std::vector<TurnCandidate> turn_candidates) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BOOST_ASSERT_MSG(std::is_sorted(turn_candidates.begin(), turn_candidates.end(),
 | 
				
			||||||
 | 
					                                    [](const TurnCandidate &left, const TurnCandidate &right)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        return left.angle < right.angle;
 | 
				
			||||||
 | 
					                                    }),
 | 
				
			||||||
 | 
					                     "Turn Candidates not sorted by angle.");
 | 
				
			||||||
 | 
					    if (turn_candidates.size() <= 1)
 | 
				
			||||||
 | 
					        return turn_candidates;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto getLeft = [&turn_candidates](std::size_t index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return (index + 1) % turn_candidates.size();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const auto getRight = [&turn_candidates](std::size_t index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return (index + turn_candidates.size() - 1) % turn_candidates.size();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // handle availability of multiple u-turns (e.g. street with separated small parking roads)
 | 
				
			||||||
 | 
					    if (turn_candidates[0].instruction == TurnInstruction::UTurn && turn_candidates[0].angle == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (turn_candidates[getLeft(0)].instruction == TurnInstruction::UTurn)
 | 
				
			||||||
 | 
					            turn_candidates[getLeft(0)].instruction = TurnInstruction::TurnSharpLeft;
 | 
				
			||||||
 | 
					        if (turn_candidates[getRight(0)].instruction == TurnInstruction::UTurn)
 | 
				
			||||||
 | 
					            turn_candidates[getRight(0)].instruction = TurnInstruction::TurnSharpRight;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto keepStraight = [](double angle)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return std::abs(angle - 180) < 5;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (std::size_t turn_index = 0; turn_index < turn_candidates.size(); ++turn_index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto &turn = turn_candidates[turn_index];
 | 
				
			||||||
 | 
					        if (turn.instruction > TurnInstruction::TurnSlightLeft ||
 | 
				
			||||||
 | 
					            turn.instruction == TurnInstruction::UTurn)
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        auto &left = turn_candidates[getLeft(turn_index)];
 | 
				
			||||||
 | 
					        if (turn.angle == left.angle)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            util::SimpleLogger().Write(logDEBUG)
 | 
				
			||||||
 | 
					                << "[warning] conflicting turn angles, identical road duplicated? "
 | 
				
			||||||
 | 
					                << m_node_info_list[m_node_based_graph->GetTarget(via_eid)].lat << " "
 | 
				
			||||||
 | 
					                << m_node_info_list[m_node_based_graph->GetTarget(via_eid)].lon << std::endl;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (isConflict(turn.instruction, left.instruction))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // begin of a conflicting region
 | 
				
			||||||
 | 
					            std::size_t conflict_begin = turn_index;
 | 
				
			||||||
 | 
					            std::size_t conflict_end = getLeft(turn_index);
 | 
				
			||||||
 | 
					            std::size_t conflict_size = 2;
 | 
				
			||||||
 | 
					            while (
 | 
				
			||||||
 | 
					                isConflict(turn_candidates[getLeft(conflict_end)].instruction, turn.instruction) &&
 | 
				
			||||||
 | 
					                conflict_size < turn_candidates.size())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                conflict_end = getLeft(conflict_end);
 | 
				
			||||||
 | 
					                ++conflict_size;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            turn_index = (conflict_end < conflict_begin) ? turn_candidates.size() : conflict_end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (conflict_size > 3)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // check if some turns are invalid to find out about good handling
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            auto &instruction_left_of_end = turn_candidates[getLeft(conflict_end)].instruction;
 | 
				
			||||||
 | 
					            auto &instruction_right_of_begin =
 | 
				
			||||||
 | 
					                turn_candidates[getRight(conflict_begin)].instruction;
 | 
				
			||||||
 | 
					            auto &candidate_at_end = turn_candidates[conflict_end];
 | 
				
			||||||
 | 
					            auto &candidate_at_begin = turn_candidates[conflict_begin];
 | 
				
			||||||
 | 
					            if (conflict_size == 2)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (turn.instruction == TurnInstruction::GoStraight)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (instruction_left_of_end != TurnInstruction::TurnSlightLeft &&
 | 
				
			||||||
 | 
					                        instruction_right_of_begin != TurnInstruction::TurnSlightRight)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        std::int32_t resolved_count = 0;
 | 
				
			||||||
 | 
					                        //uses side-effects in resolve
 | 
				
			||||||
 | 
					                        if (!keepStraight(candidate_at_end.angle) &&
 | 
				
			||||||
 | 
					                            !resolve(candidate_at_end.instruction, instruction_left_of_end,
 | 
				
			||||||
 | 
					                                     RESOLVE_TO_LEFT))
 | 
				
			||||||
 | 
					                            util::SimpleLogger().Write(logDEBUG) << "[warning] failed to resolve conflict";
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                            ++resolved_count;
 | 
				
			||||||
 | 
					                        //uses side-effects in resolve
 | 
				
			||||||
 | 
					                        if (!keepStraight(candidate_at_begin.angle) &&
 | 
				
			||||||
 | 
					                            !resolve(candidate_at_begin.instruction, instruction_right_of_begin,
 | 
				
			||||||
 | 
					                                     RESOLVE_TO_RIGHT))
 | 
				
			||||||
 | 
					                            util::SimpleLogger().Write(logDEBUG) << "[warning] failed to resolve conflict";
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                            ++resolved_count;
 | 
				
			||||||
 | 
					                        if (resolved_count >= 1 &&
 | 
				
			||||||
 | 
					                            (!keepStraight(candidate_at_begin.angle) ||
 | 
				
			||||||
 | 
					                             !keepStraight(candidate_at_end.angle))) // should always be the
 | 
				
			||||||
 | 
					                                                                     // case, theoretically
 | 
				
			||||||
 | 
					                            continue;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (candidate_at_begin.confidence < candidate_at_end.confidence)
 | 
				
			||||||
 | 
					                { // if right shift is cheaper, or only option
 | 
				
			||||||
 | 
					                    if (resolve(candidate_at_begin.instruction, instruction_right_of_begin,
 | 
				
			||||||
 | 
					                                RESOLVE_TO_RIGHT))
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					                    else if (resolve(candidate_at_end.instruction, instruction_left_of_end,
 | 
				
			||||||
 | 
					                                     RESOLVE_TO_LEFT))
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (resolve(candidate_at_end.instruction, instruction_left_of_end,
 | 
				
			||||||
 | 
					                                RESOLVE_TO_LEFT))
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					                    else if (resolve(candidate_at_begin.instruction, instruction_right_of_begin,
 | 
				
			||||||
 | 
					                                     RESOLVE_TO_RIGHT))
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (isSlightTurn(turn.instruction) || isSharpTurn(turn.instruction))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    auto resolve_direction =
 | 
				
			||||||
 | 
					                        (turn.instruction == TurnInstruction::TurnSlightRight ||
 | 
				
			||||||
 | 
					                         turn.instruction == TurnInstruction::TurnSharpLeft)
 | 
				
			||||||
 | 
					                            ? RESOLVE_TO_RIGHT
 | 
				
			||||||
 | 
					                            : RESOLVE_TO_LEFT;
 | 
				
			||||||
 | 
					                    if (resolve_direction == RESOLVE_TO_RIGHT &&
 | 
				
			||||||
 | 
					                        resolveTransitive(
 | 
				
			||||||
 | 
					                            candidate_at_begin.instruction, instruction_right_of_begin,
 | 
				
			||||||
 | 
					                            turn_candidates[getRight(getRight(conflict_begin))].instruction,
 | 
				
			||||||
 | 
					                            RESOLVE_TO_RIGHT))
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					                    else if (resolve_direction == RESOLVE_TO_LEFT &&
 | 
				
			||||||
 | 
					                             resolveTransitive(
 | 
				
			||||||
 | 
					                                 candidate_at_end.instruction, instruction_left_of_end,
 | 
				
			||||||
 | 
					                                 turn_candidates[getLeft(getLeft(conflict_end))].instruction,
 | 
				
			||||||
 | 
					                                 RESOLVE_TO_LEFT))
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (conflict_size >= 3)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // a conflict of size larger than three cannot be handled with the current
 | 
				
			||||||
 | 
					                // model.
 | 
				
			||||||
 | 
					                // Handle it as best as possible and keep the rest of the conflicting turns
 | 
				
			||||||
 | 
					                if (conflict_size > 3)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    NodeID conflict_location = m_node_based_graph->GetTarget(via_eid);
 | 
				
			||||||
 | 
					                    util::SimpleLogger().Write(logDEBUG)
 | 
				
			||||||
 | 
					                        << "[warning] found conflict larget than size three at "
 | 
				
			||||||
 | 
					                        << m_node_info_list[conflict_location].lat << ", "
 | 
				
			||||||
 | 
					                        << m_node_info_list[conflict_location].lon;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (!resolve(candidate_at_begin.instruction, instruction_right_of_begin,
 | 
				
			||||||
 | 
					                             RESOLVE_TO_RIGHT))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (isSlightTurn(turn.instruction))
 | 
				
			||||||
 | 
					                        resolveTransitive(
 | 
				
			||||||
 | 
					                            candidate_at_begin.instruction, instruction_right_of_begin,
 | 
				
			||||||
 | 
					                            turn_candidates[getRight(getRight(conflict_begin))].instruction,
 | 
				
			||||||
 | 
					                            RESOLVE_TO_RIGHT);
 | 
				
			||||||
 | 
					                    else if (isSharpTurn(turn.instruction))
 | 
				
			||||||
 | 
					                        resolveTransitive(
 | 
				
			||||||
 | 
					                            candidate_at_end.instruction, instruction_left_of_end,
 | 
				
			||||||
 | 
					                            turn_candidates[getLeft(getLeft(conflict_end))].instruction,
 | 
				
			||||||
 | 
					                            RESOLVE_TO_LEFT);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (!resolve(candidate_at_end.instruction, instruction_left_of_end,
 | 
				
			||||||
 | 
					                             RESOLVE_TO_LEFT))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (isSlightTurn(turn.instruction))
 | 
				
			||||||
 | 
					                        resolveTransitive(
 | 
				
			||||||
 | 
					                            candidate_at_end.instruction, instruction_left_of_end,
 | 
				
			||||||
 | 
					                            turn_candidates[getLeft(getLeft(conflict_end))].instruction,
 | 
				
			||||||
 | 
					                            RESOLVE_TO_LEFT);
 | 
				
			||||||
 | 
					                    else if (isSharpTurn(turn.instruction))
 | 
				
			||||||
 | 
					                        resolveTransitive(
 | 
				
			||||||
 | 
					                            candidate_at_begin.instruction, instruction_right_of_begin,
 | 
				
			||||||
 | 
					                            turn_candidates[getRight(getRight(conflict_begin))].instruction,
 | 
				
			||||||
 | 
					                            RESOLVE_TO_RIGHT);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return turn_candidates;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool EdgeBasedGraphFactory::isObviousChoice(EdgeID via_eid,
 | 
				
			||||||
 | 
					                                            std::size_t turn_index,
 | 
				
			||||||
 | 
					                                            const std::vector<TurnCandidate> &turn_candidates) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const auto getLeft = [&turn_candidates](std::size_t index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return (index + 1) % turn_candidates.size();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const auto getRight = [&turn_candidates](std::size_t index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return (index + turn_candidates.size() - 1) % turn_candidates.size();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const auto &candidate = turn_candidates[turn_index];
 | 
				
			||||||
 | 
					    const EdgeData &in_data = m_node_based_graph->GetEdgeData(via_eid);
 | 
				
			||||||
 | 
					    const EdgeData &out_data = m_node_based_graph->GetEdgeData(candidate.eid);
 | 
				
			||||||
 | 
					    const auto &candidate_to_the_left = turn_candidates[getLeft(turn_index)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto &candidate_to_the_right = turn_candidates[getRight(turn_index)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto hasValidRatio = [](const TurnCandidate &left, const TurnCandidate ¢er,
 | 
				
			||||||
 | 
					                                  const TurnCandidate &right)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto angle_left = (left.angle > 180) ? angularDeviation(left.angle, STRAIGHT_ANGLE) : 180;
 | 
				
			||||||
 | 
					        auto angle_right =
 | 
				
			||||||
 | 
					            (right.angle < 180) ? angularDeviation(right.angle, STRAIGHT_ANGLE) : 180;
 | 
				
			||||||
 | 
					        auto self_angle = angularDeviation(center.angle, STRAIGHT_ANGLE);
 | 
				
			||||||
 | 
					        return angularDeviation(center.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE &&
 | 
				
			||||||
 | 
					               ((center.angle < STRAIGHT_ANGLE)
 | 
				
			||||||
 | 
					                    ? (angle_right > self_angle && angle_left / self_angle > DISTINCTION_RATIO)
 | 
				
			||||||
 | 
					                    : (angle_left > self_angle && angle_right / self_angle > DISTINCTION_RATIO));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    // only valid turn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return turn_candidates.size() == 1 ||
 | 
				
			||||||
 | 
					           // only non u-turn
 | 
				
			||||||
 | 
					           (turn_candidates.size() == 2 &&
 | 
				
			||||||
 | 
					            candidate_to_the_left.instruction == TurnInstruction::UTurn) || // nearly straight turn
 | 
				
			||||||
 | 
					           angularDeviation(candidate.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION ||
 | 
				
			||||||
 | 
					           hasValidRatio(candidate_to_the_left, candidate, candidate_to_the_right) ||
 | 
				
			||||||
 | 
					           (in_data.name_id != 0 && in_data.name_id == out_data.name_id &&
 | 
				
			||||||
 | 
					            angularDeviation(candidate.angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE / 2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<EdgeBasedGraphFactory::TurnCandidate>
 | 
				
			||||||
 | 
					EdgeBasedGraphFactory::suppressTurns(EdgeID via_eid,
 | 
				
			||||||
 | 
					                                     std::vector<TurnCandidate> turn_candidates) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // remove invalid candidates
 | 
				
			||||||
 | 
					    BOOST_ASSERT_MSG(std::is_sorted(turn_candidates.begin(), turn_candidates.end(),
 | 
				
			||||||
 | 
					                                    [](const TurnCandidate &left, const TurnCandidate &right)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        return left.angle < right.angle;
 | 
				
			||||||
 | 
					                                    }),
 | 
				
			||||||
 | 
					                     "Turn Candidates not sorted by angle.");
 | 
				
			||||||
 | 
					    const auto end_valid = std::remove_if(turn_candidates.begin(), turn_candidates.end(),
 | 
				
			||||||
 | 
					                                          [](const TurnCandidate &candidate)
 | 
				
			||||||
 | 
					                                          {
 | 
				
			||||||
 | 
					                                              return !candidate.valid;
 | 
				
			||||||
 | 
					                                          });
 | 
				
			||||||
 | 
					    turn_candidates.erase(end_valid, turn_candidates.end());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto getLeft = [&turn_candidates](std::size_t index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return (index + 1) % turn_candidates.size();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const auto getRight = [&turn_candidates](std::size_t index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return (index + turn_candidates.size() - 1) % turn_candidates.size();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const EdgeData &in_data = m_node_based_graph->GetEdgeData(via_eid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool has_obvious_with_same_name = false;
 | 
				
			||||||
 | 
					    double obvious_with_same_name_angle = 0;
 | 
				
			||||||
 | 
					    for (std::size_t turn_index = 0; turn_index < turn_candidates.size(); ++turn_index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (m_node_based_graph->GetEdgeData(turn_candidates[turn_index].eid).name_id ==
 | 
				
			||||||
 | 
					                in_data.name_id &&
 | 
				
			||||||
 | 
					            isObviousChoice(via_eid, turn_index, turn_candidates))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            has_obvious_with_same_name = true;
 | 
				
			||||||
 | 
					            obvious_with_same_name_angle = turn_candidates[turn_index].angle;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (std::size_t turn_index = 0; turn_index < turn_candidates.size(); ++turn_index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto &candidate = turn_candidates[turn_index];
 | 
				
			||||||
 | 
					        const EdgeData &out_data = m_node_based_graph->GetEdgeData(candidate.eid);
 | 
				
			||||||
 | 
					        if (candidate.valid && candidate.instruction != TurnInstruction::UTurn)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // TODO road category would be useful to indicate obviousness of turn
 | 
				
			||||||
 | 
					            // check if turn can be omitted or at least changed
 | 
				
			||||||
 | 
					            const auto &left = turn_candidates[getLeft(turn_index)];
 | 
				
			||||||
 | 
					            const auto &right = turn_candidates[getRight(turn_index)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // make very slight instructions straight, if they are the only valid choice going with
 | 
				
			||||||
 | 
					            // at most a slight turn
 | 
				
			||||||
 | 
					            if (candidate.instruction < TurnInstruction::ReachViaLocation &&
 | 
				
			||||||
 | 
					                (!isSlightTurn(getTurnDirection(left.angle)) || !left.valid) &&
 | 
				
			||||||
 | 
					                (!isSlightTurn(getTurnDirection(right.angle)) || !right.valid) &&
 | 
				
			||||||
 | 
					                angularDeviation(candidate.angle, STRAIGHT_ANGLE) < FUZZY_STRAIGHT_ANGLE)
 | 
				
			||||||
 | 
					                candidate.instruction = TurnInstruction::GoStraight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // TODO this smaller comparison for turns is DANGEROUS, has to be revised if turn
 | 
				
			||||||
 | 
					            // instructions change
 | 
				
			||||||
 | 
					            if (candidate.instruction < TurnInstruction::ReachViaLocation)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (in_data.travel_mode ==
 | 
				
			||||||
 | 
					                    out_data.travel_mode) // make sure to always announce mode changes
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (isObviousChoice(via_eid, turn_index, turn_candidates))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (in_data.name_id == out_data.name_id) // same road
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            candidate.instruction = TurnInstruction::NoTurn;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        else if (!has_obvious_with_same_name)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            // TODO discuss, we might want to keep the current name of the turn. But
 | 
				
			||||||
 | 
					                            // this would mean emitting a turn when you just keep on a road
 | 
				
			||||||
 | 
					                            candidate.instruction = TurnInstruction::NameChanges;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else if (candidate.angle < obvious_with_same_name_angle)
 | 
				
			||||||
 | 
					                            candidate.instruction = TurnInstruction::TurnSlightRight;
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                            candidate.instruction = TurnInstruction::TurnSlightLeft;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else if (candidate.instruction == TurnInstruction::GoStraight &&
 | 
				
			||||||
 | 
					                             has_obvious_with_same_name)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (candidate.angle < obvious_with_same_name_angle)
 | 
				
			||||||
 | 
					                            candidate.instruction = TurnInstruction::TurnSlightRight;
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                            candidate.instruction = TurnInstruction::TurnSlightLeft;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return turn_candidates;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<EdgeBasedGraphFactory::TurnCandidate>
 | 
				
			||||||
 | 
					EdgeBasedGraphFactory::getTurnCandidates(NodeID from_node, EdgeID via_eid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    std::vector<TurnCandidate> turn_candidates;
 | 
				
			||||||
 | 
					    const NodeID turn_node = m_node_based_graph->GetTarget(via_eid);
 | 
				
			||||||
 | 
					    const NodeID only_restriction_to_node =
 | 
				
			||||||
 | 
					        m_restriction_map->CheckForEmanatingIsOnlyTurn(from_node, turn_node);
 | 
				
			||||||
 | 
					    const bool is_barrier_node = m_barrier_nodes.find(turn_node) != m_barrier_nodes.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const EdgeID onto_edge : m_node_based_graph->GetAdjacentEdgeRange(turn_node))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        bool turn_is_valid = true;
 | 
				
			||||||
 | 
					        if (m_node_based_graph->GetEdgeData(onto_edge).reversed)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            turn_is_valid = false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const NodeID to_node = m_node_based_graph->GetTarget(onto_edge);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (turn_is_valid && (only_restriction_to_node != SPECIAL_NODEID) &&
 | 
				
			||||||
 | 
					            (to_node != only_restriction_to_node))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // We are at an only_-restriction but not at the right turn.
 | 
				
			||||||
 | 
					            ++restricted_turns_counter;
 | 
				
			||||||
 | 
					            turn_is_valid = false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (turn_is_valid)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (is_barrier_node)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (from_node != to_node)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ++skipped_barrier_turns_counter;
 | 
				
			||||||
 | 
					                    turn_is_valid = false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (from_node == to_node && m_node_based_graph->GetOutDegree(turn_node) > 1)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    auto number_of_emmiting_bidirectional_edges = 0;
 | 
				
			||||||
 | 
					                    for (auto edge : m_node_based_graph->GetAdjacentEdgeRange(turn_node))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        auto target = m_node_based_graph->GetTarget(edge);
 | 
				
			||||||
 | 
					                        auto reverse_edge = m_node_based_graph->FindEdge(target, turn_node);
 | 
				
			||||||
 | 
					                        if (!m_node_based_graph->GetEdgeData(reverse_edge).reversed)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            ++number_of_emmiting_bidirectional_edges;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (number_of_emmiting_bidirectional_edges > 1)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        ++skipped_uturns_counter;
 | 
				
			||||||
 | 
					                        turn_is_valid = false;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // only add an edge if turn is not a U-turn except when it is
 | 
				
			||||||
 | 
					        // at the end of a dead-end street
 | 
				
			||||||
 | 
					        if (m_restriction_map->CheckIfTurnIsRestricted(from_node, turn_node, to_node) &&
 | 
				
			||||||
 | 
					            (only_restriction_to_node == SPECIAL_NODEID) && (to_node != only_restriction_to_node))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // We are at an only_-restriction but not at the right turn.
 | 
				
			||||||
 | 
					            ++restricted_turns_counter;
 | 
				
			||||||
 | 
					            turn_is_valid = false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // unpack first node of second segment if packed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const auto first_coordinate =
 | 
				
			||||||
 | 
					            getRepresentativeCoordinate(from_node, turn_node, via_eid, INVERT);
 | 
				
			||||||
 | 
					        const auto third_coordinate =
 | 
				
			||||||
 | 
					            getRepresentativeCoordinate(turn_node, to_node, onto_edge, !INVERT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const auto angle = util::coordinate_calculation::computeAngle(
 | 
				
			||||||
 | 
					            first_coordinate, m_node_info_list[turn_node], third_coordinate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const auto turn = AnalyzeTurn(from_node, via_eid, turn_node, onto_edge, to_node, angle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto confidence = getTurnConfidence(angle, turn);
 | 
				
			||||||
 | 
					        if (!turn_is_valid)
 | 
				
			||||||
 | 
					            confidence *= 0.8; // makes invalid turns more likely to be resolved in conflicts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        turn_candidates.push_back({onto_edge, turn_is_valid, angle, turn, confidence});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto ByAngle = [](const TurnCandidate &first, const TurnCandidate second)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return first.angle < second.angle;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    std::sort(std::begin(turn_candidates), std::end(turn_candidates), ByAngle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto getLeft = [&](std::size_t index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return (index + 1) % turn_candidates.size();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto getRight = [&](std::size_t index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return (index + turn_candidates.size() - 1) % turn_candidates.size();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto isInvalidEquivalent = [&](std::size_t this_turn, std::size_t valid_turn)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!turn_candidates[valid_turn].valid || turn_candidates[this_turn].valid)
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return angularDeviation(turn_candidates[this_turn].angle,
 | 
				
			||||||
 | 
					                                turn_candidates[valid_turn].angle) < NARROW_TURN_ANGLE;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (std::size_t index = 0; index < turn_candidates.size(); ++index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (isInvalidEquivalent(index, getRight(index)) ||
 | 
				
			||||||
 | 
					            isInvalidEquivalent(index, getLeft(index)))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            turn_candidates.erase(turn_candidates.begin() + index);
 | 
				
			||||||
 | 
					            --index;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return turn_candidates;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) const
 | 
					int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -658,22 +1080,22 @@ int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) co
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// node_u -- (edge_1) --> node_v -- (edge_2) --> node_w
 | 
				
			||||||
TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
 | 
					TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
 | 
				
			||||||
 | 
					                                                   const EdgeID edge1,
 | 
				
			||||||
                                                   const NodeID node_v,
 | 
					                                                   const NodeID node_v,
 | 
				
			||||||
 | 
					                                                   const EdgeID edge2,
 | 
				
			||||||
                                                   const NodeID node_w,
 | 
					                                                   const NodeID node_w,
 | 
				
			||||||
                                                   const double angle) const
 | 
					                                                   const double angle) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const EdgeData &data1 = m_node_based_graph->GetEdgeData(edge1);
 | 
				
			||||||
 | 
					    const EdgeData &data2 = m_node_based_graph->GetEdgeData(edge2);
 | 
				
			||||||
    if (node_u == node_w)
 | 
					    if (node_u == node_w)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return TurnInstruction::UTurn;
 | 
					        return TurnInstruction::UTurn;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const EdgeID edge1 = m_node_based_graph->FindEdge(node_u, node_v);
 | 
					 | 
				
			||||||
    const EdgeID edge2 = m_node_based_graph->FindEdge(node_v, node_w);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const EdgeData &data1 = m_node_based_graph->GetEdgeData(edge1);
 | 
					 | 
				
			||||||
    const EdgeData &data2 = m_node_based_graph->GetEdgeData(edge2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // roundabouts need to be handled explicitely
 | 
					    // roundabouts need to be handled explicitely
 | 
				
			||||||
    if (data1.roundabout && data2.roundabout)
 | 
					    if (data1.roundabout && data2.roundabout)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -700,19 +1122,89 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID node_u,
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // If street names stay the same and if we are certain that it is not a
 | 
					    // assign a designated turn angle instruction purely based on the angle
 | 
				
			||||||
    // a segment of a roundabout, we skip it.
 | 
					 | 
				
			||||||
    if (data1.name_id == data2.name_id && data1.travel_mode == data2.travel_mode)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // TODO: Here we should also do a small graph exploration to check for
 | 
					 | 
				
			||||||
        //      more complex situations
 | 
					 | 
				
			||||||
        if (0 != data1.name_id || m_node_based_graph->GetOutDegree(node_v) <= 2)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return TurnInstruction::NoTurn;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return getTurnDirection(angle);
 | 
					    return getTurnDirection(angle);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QueryNode EdgeBasedGraphFactory::getRepresentativeCoordinate(const NodeID src,
 | 
				
			||||||
 | 
					                                                             const NodeID tgt,
 | 
				
			||||||
 | 
					                                                             const EdgeID via_eid,
 | 
				
			||||||
 | 
					                                                             bool INVERTED) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (m_compressed_edge_container.HasEntryForID(via_eid))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        util::FixedPointCoordinate prev = util::FixedPointCoordinate(
 | 
				
			||||||
 | 
					                                       m_node_info_list[INVERTED ? tgt : src].lat,
 | 
				
			||||||
 | 
					                                       m_node_info_list[INVERTED ? tgt : src].lon),
 | 
				
			||||||
 | 
					                                   cur;
 | 
				
			||||||
 | 
					        // walk along the edge for the first 5 meters
 | 
				
			||||||
 | 
					        const auto &geometry = m_compressed_edge_container.GetBucketReference(via_eid);
 | 
				
			||||||
 | 
					        double dist = 0;
 | 
				
			||||||
 | 
					        double this_dist = 0;
 | 
				
			||||||
 | 
					        NodeID prev_id = INVERTED ? tgt : src;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const auto selectBestCandidate = [this](const NodeID current, const double current_distance,
 | 
				
			||||||
 | 
					                                                const NodeID previous,
 | 
				
			||||||
 | 
					                                                const double previous_distance)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (current_distance < DESIRED_SEGMENT_LENGTH ||
 | 
				
			||||||
 | 
					                current_distance - DESIRED_SEGMENT_LENGTH <
 | 
				
			||||||
 | 
					                    DESIRED_SEGMENT_LENGTH - previous_distance ||
 | 
				
			||||||
 | 
					                previous_distance < MINIMAL_SEGMENT_LENGTH)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return m_node_info_list[current];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return m_node_info_list[previous];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (INVERTED)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            for (auto itr = geometry.rbegin(), end = geometry.rend(); itr != end; ++itr)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                const auto compressed_node = *itr;
 | 
				
			||||||
 | 
					                cur = util::FixedPointCoordinate(m_node_info_list[compressed_node.first].lat,
 | 
				
			||||||
 | 
					                                                 m_node_info_list[compressed_node.first].lon);
 | 
				
			||||||
 | 
					                this_dist = util::coordinate_calculation::haversineDistance(prev, cur);
 | 
				
			||||||
 | 
					                if (dist + this_dist > DESIRED_SEGMENT_LENGTH)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return selectBestCandidate(compressed_node.first, dist + this_dist, prev_id,
 | 
				
			||||||
 | 
					                                               dist);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                dist += this_dist;
 | 
				
			||||||
 | 
					                prev = cur;
 | 
				
			||||||
 | 
					                prev_id = compressed_node.first;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            cur = util::FixedPointCoordinate(m_node_info_list[src].lat, m_node_info_list[src].lon);
 | 
				
			||||||
 | 
					            this_dist = util::coordinate_calculation::haversineDistance(prev, cur);
 | 
				
			||||||
 | 
					            return selectBestCandidate(src, dist + this_dist, prev_id, dist);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            for (auto itr = geometry.begin(), end = geometry.end(); itr != end; ++itr)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                const auto compressed_node = *itr;
 | 
				
			||||||
 | 
					                cur = util::FixedPointCoordinate(m_node_info_list[compressed_node.first].lat,
 | 
				
			||||||
 | 
					                                                 m_node_info_list[compressed_node.first].lon);
 | 
				
			||||||
 | 
					                this_dist = util::coordinate_calculation::haversineDistance(prev, cur);
 | 
				
			||||||
 | 
					                if (dist + this_dist > DESIRED_SEGMENT_LENGTH)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return selectBestCandidate(compressed_node.first, dist + this_dist, prev_id,
 | 
				
			||||||
 | 
					                                               dist);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                dist += this_dist;
 | 
				
			||||||
 | 
					                prev = cur;
 | 
				
			||||||
 | 
					                prev_id = compressed_node.first;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            cur = util::FixedPointCoordinate(m_node_info_list[tgt].lat, m_node_info_list[tgt].lon);
 | 
				
			||||||
 | 
					            this_dist = util::coordinate_calculation::haversineDistance(prev, cur);
 | 
				
			||||||
 | 
					            return selectBestCandidate(tgt, dist + this_dist, prev_id, dist);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // default: If the edge is very short, or we do not have a compressed geometry
 | 
				
			||||||
 | 
					    return m_node_info_list[INVERTED ? src : tgt];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					} // namespace extractor
 | 
				
			||||||
 | 
					} // namespace osrm
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user