44
55author Atsushi Sakai(@Atsushi_twi)
66co-author Videh Patel(@videh25) : Added the missing RS paths
7+ co-author fishyy119(@fishyy119) : Improved runtime efficiency
78
89"""
9- import sys
1010import pathlib
11+ import sys
12+
1113sys .path .append (str (pathlib .Path (__file__ ).parent .parent .parent ))
1214
1315import math
16+ from typing import List , Tuple
1417
1518import matplotlib .pyplot as plt
1619import numpy as np
20+ from numpy .typing import NDArray
21+
1722from utils .angle import angle_mod
1823
1924show_animation = True
@@ -342,63 +347,88 @@ def generate_path(q0, q1, max_curvature, step_size):
342347 return paths
343348
344349
345- def calc_interpolate_dists_list (lengths , step_size ) :
346- interpolate_dists_list = []
350+ def calc_interpolate_dists_list (lengths : List [ float ] , step_size : float ) -> List [ NDArray [ np . floating ]] :
351+ interpolate_dists_list : List [ NDArray [ np . floating ]] = []
347352 for length in lengths :
348353 d_dist = step_size if length >= 0.0 else - step_size
349- interp_dists = np .arange (0.0 , length , d_dist )
350- interp_dists = np .append (interp_dists , length )
354+
355+ interp_core = np .arange (0.0 , length , d_dist , dtype = np .float64 )
356+ interp_dists = np .empty (len (interp_core ) + 1 , dtype = np .float64 )
357+ interp_dists [:- 1 ] = interp_core
358+ interp_dists [- 1 ] = length
359+
351360 interpolate_dists_list .append (interp_dists )
352361
353362 return interpolate_dists_list
354363
355364
356- def generate_local_course (lengths , modes , max_curvature , step_size ):
365+ def generate_local_course (
366+ lengths : List [float ],
367+ modes : List [str ],
368+ max_curvature : float ,
369+ step_size : float ,
370+ ) -> Tuple [NDArray [np .floating ], NDArray [np .floating ], NDArray [np .floating ], NDArray [np .signedinteger ]]:
357371 interpolate_dists_list = calc_interpolate_dists_list (lengths , step_size * max_curvature )
372+ total_len = sum (len (arr ) for arr in interpolate_dists_list )
373+ xs = np .empty (total_len , dtype = np .float64 )
374+ ys = np .empty_like (xs )
375+ yaws = np .empty_like (xs )
376+ directions = np .empty_like (xs , dtype = np .int32 )
358377
359378 origin_x , origin_y , origin_yaw = 0.0 , 0.0 , 0.0
360-
361- xs , ys , yaws , directions = [], [], [], []
362- for ( interp_dists , mode , length ) in zip (interpolate_dists_list , modes ,
363- lengths ):
364-
365- for dist in interp_dists :
366- x , y , yaw , direction = interpolate ( dist , length , mode ,
367- max_curvature , origin_x ,
368- origin_y , origin_yaw )
369- xs . append ( x )
370- ys . append ( y )
371- yaws . append ( yaw )
372- directions . append ( direction )
373- origin_x = xs [- 1 ]
374- origin_y = ys [- 1 ]
375- origin_yaw = yaws [ - 1 ]
379+ idx = 0
380+
381+ for interp_dists , mode , length in zip (interpolate_dists_list , modes , lengths ):
382+ n = len ( interp_dists )
383+ x_arr , y_arr , yaw_arr , dir_arr = interpolate_vectorized (
384+ interp_dists , length , mode , max_curvature , origin_x , origin_y , origin_yaw
385+ )
386+ xs [ idx : idx + n ] = x_arr
387+ ys [ idx : idx + n ] = y_arr
388+ yaws [ idx : idx + n ] = yaw_arr
389+ directions [ idx : idx + n ] = dir_arr
390+
391+ origin_x = x_arr [ - 1 ]
392+ origin_y = y_arr [- 1 ]
393+ origin_yaw = yaw_arr [- 1 ]
394+ idx += n
376395
377396 return xs , ys , yaws , directions
378397
379398
380- def interpolate (dist , length , mode , max_curvature , origin_x , origin_y ,
381- origin_yaw ):
399+ def interpolate_vectorized (
400+ dists : NDArray [np .floating ],
401+ length : float ,
402+ mode : str ,
403+ max_curvature : float ,
404+ origin_x : float ,
405+ origin_y : float ,
406+ origin_yaw : float ,
407+ ) -> Tuple [NDArray [np .floating ], NDArray [np .floating ], NDArray [np .floating ], NDArray [np .signedinteger ]]:
382408 if mode == "S" :
383- x = origin_x + dist / max_curvature * math .cos (origin_yaw )
384- y = origin_y + dist / max_curvature * math .sin (origin_yaw )
385- yaw = origin_yaw
409+ x = origin_x + dists / max_curvature * math .cos (origin_yaw )
410+ y = origin_y + dists / max_curvature * math .sin (origin_yaw )
411+ yaw = np . full_like ( dists , origin_yaw )
386412 else : # curve
387- ldx = math .sin (dist ) / max_curvature
388- ldy = 0.0
389- yaw = None
413+ ldx = np .sin (dists ) / max_curvature
414+ ldy = np . zeros_like ( dists )
415+ yaw = np . zeros_like ( dists )
390416 if mode == "L" : # left turn
391- ldy = (1.0 - math .cos (dist )) / max_curvature
392- yaw = origin_yaw + dist
393- elif mode == "R" : # right turn
394- ldy = (1.0 - math .cos (dist )) / - max_curvature
395- yaw = origin_yaw - dist
396- gdx = math .cos (- origin_yaw ) * ldx + math .sin (- origin_yaw ) * ldy
397- gdy = - math .sin (- origin_yaw ) * ldx + math .cos (- origin_yaw ) * ldy
417+ ldy = (1.0 - np .cos (dists )) / max_curvature
418+ yaw = origin_yaw + dists
419+ else : # elif mode == "R": # right turn
420+ ldy = (1.0 - np .cos (dists )) / (- max_curvature )
421+ yaw = origin_yaw - dists
422+
423+ cos_oy = math .cos (- origin_yaw )
424+ sin_oy = math .sin (- origin_yaw )
425+ gdx = cos_oy * ldx + sin_oy * ldy
426+ gdy = - sin_oy * ldx + cos_oy * ldy
398427 x = origin_x + gdx
399428 y = origin_y + gdy
400429
401- return x , y , yaw , 1 if length > 0.0 else - 1
430+ direction = 1 if length > 0 else - 1
431+ return x , y , yaw , np .full_like (dists , direction , dtype = np .int32 )
402432
403433
404434def calc_paths (sx , sy , syaw , gx , gy , gyaw , maxc , step_size ):
@@ -407,19 +437,23 @@ def calc_paths(sx, sy, syaw, gx, gy, gyaw, maxc, step_size):
407437
408438 paths = generate_path (q0 , q1 , maxc , step_size )
409439 for path in paths :
410- xs , ys , yaws , directions = generate_local_course (path .lengths ,
411- path .ctypes , maxc ,
412- step_size )
440+ xs , ys , yaws , directions = generate_local_course (path .lengths , path .ctypes , maxc , step_size )
413441
414442 # convert global coordinate
415- path .x = [math .cos (- q0 [2 ]) * ix + math .sin (- q0 [2 ]) * iy + q0 [0 ] for
416- (ix , iy ) in zip (xs , ys )]
417- path .y = [- math .sin (- q0 [2 ]) * ix + math .cos (- q0 [2 ]) * iy + q0 [1 ] for
418- (ix , iy ) in zip (xs , ys )]
419- path .yaw = [pi_2_pi (yaw + q0 [2 ]) for yaw in yaws ]
420- path .directions = directions
421- path .lengths = [length / maxc for length in path .lengths ]
422- path .L = path .L / maxc
443+ local_pts = np .vstack ([xs , ys , np .ones_like (xs )]) # shape: [3, N]
444+ cos_y = np .cos (syaw )
445+ sin_y = np .sin (syaw )
446+ se2 = np .array ([[cos_y , - sin_y , sx ],[sin_y , cos_y , sy ],[0 , 0 , 1 ]])
447+ global_pts = se2 @ local_pts # shape: [3, N]
448+
449+ path .x = global_pts [0 , :].tolist ()
450+ path .y = global_pts [1 , :].tolist ()
451+
452+ path .yaw = ((yaws + syaw + np .pi ) % (2 * np .pi ) - np .pi ).tolist ()
453+
454+ path .directions = directions .tolist ()
455+ path .lengths = [l / maxc for l in path .lengths ]
456+ path .L /= maxc
423457
424458 return paths
425459
0 commit comments