123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- # -*- coding: utf-8 -*-
- import math
- import copy
- # square root of 2 for diagonal distance
- SQRT2 = math.sqrt(2)
- def backtrace(node):
- """
- Backtrace according to the parent records and return the path.
- (including both start and end nodes)
- """
- path = [(node.x, node.y)]
- while node.parent:
- node = node.parent
- path.append((node.x, node.y))
- path.reverse()
- return path
- def bi_backtrace(node_a, node_b):
- """
- Backtrace from start and end node, returns the path for bi-directional A*
- (including both start and end nodes)
- """
- path_a = backtrace(node_a)
- path_b = backtrace(node_b)
- path_b.reverse()
- return path_a + path_b
- def raytrace(coords_a, coords_b):
- line = []
- x0, y0 = coords_a
- x1, y1 = coords_b
- dx = x1 - x0
- dy = y1 - y0
- t = 0
- grid_pos = [x0, y0]
- t_for_one = \
- abs(1.0 / dx) if dx > 0 else 10000, \
- abs(1.0 / dy) if dy > 0 else 10000
- frac_start_pos = (x0 + .5) - x0, (y0 + .5) - y0
- t_for_next_border = [
- (1 - frac_start_pos[0] if dx < 0 else frac_start_pos[0]) * t_for_one[0],
- (1 - frac_start_pos[1] if dx < 0 else frac_start_pos[1]) * t_for_one[1]
- ]
- step = \
- 1 if dx >= 0 else -1, \
- 1 if dy >= 0 else -1
- while t <= 1:
- line.append(copy.copy(grid_pos))
- index = 0 if t_for_next_border[0] <= t_for_next_border[1] else 1
- t = t_for_next_border[index]
- t_for_next_border[index] += t_for_one[index]
- grid_pos[index] += step[index]
- return line
- def bresenham(coords_a, coords_b):
- '''
- Given the start and end coordinates, return all the coordinates lying
- on the line formed by these coordinates, based on Bresenham's algorithm.
- http://en.wikipedia.org/wiki/Bresenham's_line_algorithm#Simplification
- '''
- line = []
- x0, y0 = coords_a
- x1, y1 = coords_b
- dx = abs(x1 - x0)
- dy = abs(y1 - y0)
- sx = 1 if x0 < x1 else -1
- sy = 1 if y0 < y1 else -1
- err = dx - dy
- while True:
- line += [[x0, y0]]
- if x0 == x1 and y0 == y1:
- break
- e2 = err * 2
- if e2 > -dy:
- err = err - dy
- x0 = x0 + sx
- if e2 < dx:
- err = err + dx
- y0 = y0 + sy
- return line
- def expand_path(path):
- '''
- Given a compressed path, return a new path that has all the segments
- in it interpolated.
- '''
- expanded = []
- if len(path) < 2:
- return expanded
- for i in range(len(path)-1):
- expanded += bresenham(path[i], path[i + 1])
- expanded += [path[:-1]]
- return expanded
- def smoothen_path(grid, path, use_raytrace=False):
- x0, y0 = path[0]
- sx, sy = path[0]
- new_path = [[sx, sy]]
- interpolate = raytrace if use_raytrace else bresenham
- last_valid = path[1]
- for coord in path[2:-1]:
- line = interpolate([sx, sy], coord)
- blocked = False
- for test_coord in line[1:]:
- if not grid.walkable(test_coord[0], test_coord[1]):
- blocked = True
- break
- if not blocked:
- new_path.append(last_valid)
- sx, sy = last_valid
- last_valid = coord
- new_path.append(path[-1])
- return new_path
|