@@ -40,7 +40,6 @@ def informed_rrt_star_search(self, animation=True):
4040 self .node_list = [self .start ]
4141 # max length we expect to find in our 'informed' sample space, starts as infinite
4242 cBest = float ('inf' )
43- pathLen = float ('inf' )
4443 solutionSet = set ()
4544 path = None
4645
@@ -74,25 +73,24 @@ def informed_rrt_star_search(self, animation=True):
7473 newNode = self .get_new_node (theta , nind , nearestNode )
7574 d = self .line_cost (nearestNode , newNode )
7675
77- isCollision = self .collision_check (newNode , self .obstacle_list )
78- isCollisionEx = self .check_collision_extend (nearestNode , theta , d )
76+ noCollision = self .check_collision (nearestNode , theta , d )
7977
80- if isCollision and isCollisionEx :
78+ if noCollision :
8179 nearInds = self .find_near_nodes (newNode )
8280 newNode = self .choose_parent (newNode , nearInds )
8381
8482 self .node_list .append (newNode )
8583 self .rewire (newNode , nearInds )
8684
8785 if self .is_near_goal (newNode ):
88- solutionSet . add (newNode )
89- lastIndex = len ( self . node_list ) - 1
90- tempPath = self .get_final_course ( lastIndex )
91- tempPathLen = self .get_path_len ( tempPath )
92- if tempPathLen < pathLen :
93- path = tempPath
94- cBest = tempPathLen
95-
86+ if self . check_segment_collision (newNode . x , newNode . y , self . goal . x , self . goal . y ):
87+ solutionSet . add ( newNode )
88+ lastIndex = len ( self .node_list ) - 1
89+ tempPath = self .get_final_course ( lastIndex )
90+ tempPathLen = self . get_path_len ( tempPath )
91+ if tempPathLen < cBest :
92+ path = tempPath
93+ cBest = tempPathLen
9694 if animation :
9795 self .draw_graph (xCenter = xCenter ,
9896 cBest = cBest , cMin = cMin ,
@@ -110,7 +108,7 @@ def choose_parent(self, newNode, nearInds):
110108 dy = newNode .y - self .node_list [i ].y
111109 d = math .sqrt (dx ** 2 + dy ** 2 )
112110 theta = math .atan2 (dy , dx )
113- if self .check_collision_extend (self .node_list [i ], theta , d ):
111+ if self .check_collision (self .node_list [i ], theta , d ):
114112 dList .append (self .node_list [i ].cost + d )
115113 else :
116114 dList .append (float ('inf' ))
@@ -194,17 +192,6 @@ def get_nearest_list_index(nodes, rnd):
194192 minIndex = dList .index (min (dList ))
195193 return minIndex
196194
197- @staticmethod
198- def collision_check (newNode , obstacleList ):
199- for (ox , oy , size ) in obstacleList :
200- dx = ox - newNode .x
201- dy = oy - newNode .y
202- d = dx * dx + dy * dy
203- if d <= 1.1 * size ** 2 :
204- return False # collision
205-
206- return True # safe
207-
208195 def get_new_node (self , theta , nind , nearestNode ):
209196 newNode = copy .deepcopy (nearestNode )
210197
@@ -234,20 +221,40 @@ def rewire(self, newNode, nearInds):
234221 if nearNode .cost > scost :
235222 theta = math .atan2 (newNode .y - nearNode .y ,
236223 newNode .x - nearNode .x )
237- if self .check_collision_extend (nearNode , theta , d ):
224+ if self .check_collision (nearNode , theta , d ):
238225 nearNode .parent = n_node - 1
239226 nearNode .cost = scost
227+
228+ @staticmethod
229+ def distance_squared_point_to_segment (v , w , p ):
230+ # Return minimum distance between line segment vw and point p
231+ if (np .array_equal (v , w )):
232+ return (p - v ).dot (p - v ) # v == w case
233+ l2 = (w - v ).dot (w - v ) # i.e. |w-v|^2 - avoid a sqrt
234+ # Consider the line extending the segment, parameterized as v + t (w - v).
235+ # We find projection of point p onto the line.
236+ # It falls where t = [(p-v) . (w-v)] / |w-v|^2
237+ # We clamp t from [0,1] to handle points outside the segment vw.
238+ t = max (0 , min (1 , (p - v ).dot (w - v ) / l2 ))
239+ projection = v + t * (w - v ) # Projection falls on the segment
240+ return (p - projection ).dot (p - projection )
241+
242+ def check_segment_collision (self , x1 , y1 , x2 , y2 ):
243+ for (ox , oy , size ) in self .obstacle_list :
244+ dd = self .distance_squared_point_to_segment (
245+ np .array ([x1 , y1 ]),
246+ np .array ([x2 , y2 ]),
247+ np .array ([ox , oy ]))
248+ if dd <= size ** 2 :
249+ return False # collision
250+ return True
240251
241- def check_collision_extend (self , nearNode , theta , d ):
242- tmpNode = copy .deepcopy (nearNode )
243-
244- for i in range (int (d / self .expand_dis )):
245- tmpNode .x += self .expand_dis * math .cos (theta )
246- tmpNode .y += self .expand_dis * math .sin (theta )
247- if not self .collision_check (tmpNode , self .obstacle_list ):
248- return False
249252
250- return True
253+ def check_collision (self , nearNode , theta , d ):
254+ tmpNode = copy .deepcopy (nearNode )
255+ endx = tmpNode .x + math .cos (theta )* d
256+ endy = tmpNode .y + math .sin (theta )* d
257+ return self .check_segment_collision (tmpNode .x , tmpNode .y , endx , endy )
251258
252259 def get_final_course (self , lastIndex ):
253260 path = [[self .goal .x , self .goal .y ]]
0 commit comments