66
77"""
88
9+ import os
10+ import sys
11+
12+ sys .path .append (os .path .dirname (os .path .abspath (__file__ )) +
13+ "/../VoronoiRoadMap/" )
14+
15+ import math
16+ import numpy as np
917import matplotlib .pyplot as plt
18+ from dijkstra_search import DijkstraSearch
1019
1120show_animation = True
1221
22+
1323class VisibilityGraphPlanner :
1424
1525 def __init__ (self , robot_radius ):
1626 self .robot_radius = robot_radius
1727
1828 def planning (self , start_x , start_y , goal_x , goal_y , obstacles ):
19- nodes = self .exstract_graph_node (start_x , start_y , goal_x , goal_y ,
20- obstacles )
21-
29+ nodes = self .extract_graph_node (start_x , start_y , goal_x , goal_y ,
30+ obstacles )
2231 graph = self .generate_graph (nodes , obstacles )
2332
24- rx , ry = dijkstra_search (graph )
33+ # rx, ry = DijkstraSearch().search(graph)
34+
35+ rx , ry = [], []
2536
2637 return rx , ry
2738
28- def exstract_graph_node (self , start_x , start_y , goal_x , goal_x , obstacles ):
29- nodes = []
39+ def extract_graph_node (self , start_x , start_y , goal_x , goal_y , obstacles ):
40+
41+ # add start and goal as nodes
42+ nodes = [DijkstraSearch .Node (start_x , start_y ),
43+ DijkstraSearch .Node (goal_x , goal_y , 0 , None )]
44+
45+ # add vertexes in configuration space as nodes
46+ for obstacle in obstacles :
47+
48+ cvx_list , cvy_list = self .calc_vertexes_in_configuration_space (
49+ obstacle .x_list , obstacle .y_list )
50+
51+ for (vx , vy ) in zip (cvx_list , cvy_list ):
52+ nodes .append (DijkstraSearch .Node (vx , vy ))
53+
54+ for node in nodes :
55+ plt .plot (node .x , node .y , "xr" )
3056
3157 return nodes
3258
59+ def calc_vertexes_in_configuration_space (self , x_list , y_list ):
60+ x_list = x_list [0 :- 1 ]
61+ y_list = y_list [0 :- 1 ]
62+ cvx_list , cvy_list = [], []
63+
64+ n_data = len (x_list )
65+
66+ for index in range (n_data ):
67+ offset_x , offset_y = self .calc_offset_xy (
68+ x_list [index - 1 ], y_list [index - 1 ],
69+ x_list [index ], y_list [index ],
70+ x_list [(index + 1 ) % n_data ], y_list [(index + 1 ) % n_data ],
71+ )
72+ cvx_list .append (offset_x )
73+ cvy_list .append (offset_y )
74+
75+ return cvx_list , cvy_list
76+
3377 def generate_graph (self , nodes , obstacles ):
3478
3579 graph = []
3680
81+ for target_node in nodes :
82+ for node in nodes :
83+ for obstacle in obstacles :
84+ if not self .is_edge_valid (target_node , node , obstacle ):
85+ print ("bb" )
86+ break
87+ print (target_node , node )
88+ print ("aa" )
89+ plt .plot ([target_node .x , node .x ],[target_node .y , node .y ], "-r" )
90+
3791 return graph
3892
93+ def is_edge_valid (self , target_node , node , obstacle ):
94+
95+ for i in range (len (obstacle .x_list )- 1 ):
96+ p1 = np .array ([target_node .x , target_node .y ])
97+ p2 = np .array ([node .x , node .y ])
98+ p3 = np .array ([obstacle .x_list [i ], obstacle .y_list [i ]])
99+ p4 = np .array ([obstacle .y_list [i + 1 ], obstacle .y_list [i + 1 ]])
100+
101+ if is_seg_intersect (p1 , p2 , p3 , p4 ):
102+ return False
103+
104+ return True
105+
106+ def calc_offset_xy (self , px , py , x , y , nx , ny ):
107+ p_vec = math .atan2 (y - py , x - px )
108+ n_vec = math .atan2 (ny - y , nx - x )
109+ offset_vec = math .atan2 (math .sin (p_vec ) + math .sin (n_vec ),
110+ math .cos (p_vec ) + math .cos (
111+ n_vec ))+ math .pi / 2.0
112+ offset_x = x + self .robot_radius * math .cos (offset_vec )
113+ offset_y = y + self .robot_radius * math .sin (offset_vec )
114+ return offset_x , offset_y
115+
116+
117+ def is_seg_intersect (a1 , a2 , b1 , b2 ):
118+
119+ xdiff = [a1 [0 ] - a2 [0 ], b1 [0 ] - b2 [0 ]]
120+ ydiff = [a1 [1 ] - a2 [1 ], b1 [1 ] - b2 [1 ]]
121+
122+ def det (a , b ):
123+ return a [0 ] * b [1 ] - a [1 ] * b [0 ]
124+
125+ div = det (xdiff , ydiff )
126+ if div == 0 :
127+ return False
128+ else :
129+ return True
39130
40131class ObstaclePolygon :
41132
@@ -44,6 +135,21 @@ def __init__(self, x_list, y_list):
44135 self .y_list = y_list
45136
46137 self .close_polygon ()
138+ self .make_clockwise ()
139+
140+ def make_clockwise (self ):
141+ if not self .is_clockwise ():
142+ self .x_list = list (reversed (self .x_list ))
143+ self .y_list = list (reversed (self .y_list ))
144+
145+ def is_clockwise (self ):
146+ n_data = len (self .x_list )
147+ eval_sum = sum ([(self .x_list [i + 1 ] - self .x_list [i ]) *
148+ (self .y_list [i + 1 ] + self .y_list [i ])
149+ for i in range (n_data - 1 )])
150+ eval_sum += (self .x_list [0 ] - self .x_list [n_data - 1 ]) * \
151+ (self .y_list [0 ] + self .y_list [n_data - 1 ])
152+ return eval_sum >= 0
47153
48154 def close_polygon (self ):
49155 is_x_same = self .x_list [0 ] == self .x_list [- 1 ]
@@ -74,13 +180,15 @@ def main():
74180 [50.0 , 40.0 , 20.0 , 40.0 ],
75181 )]
76182
77- rx , ry = VisibilityGraphPlanner (robot_radius ).planning (sx , sy , gx , gy ,
78- obstacles )
79- assert rx , 'Cannot found path'
80183 if show_animation : # pragma: no cover
81184 plt .plot (sx , sy , "or" )
82185 plt .plot (gx , gy , "ob" )
83186 [ob .plot () for ob in obstacles ]
187+
188+ rx , ry = VisibilityGraphPlanner (robot_radius ).planning (sx , sy , gx , gy ,
189+ obstacles )
190+ # assert rx, 'Cannot found path'
191+ if show_animation : # pragma: no cover
84192 plt .plot (rx , ry , "-r" )
85193 plt .axis ("equal" )
86194 plt .show ()
0 commit comments