trace_path: PEP7 fixes.

This commit is contained in:
Stefan van der Walt
2009-11-22 13:15:19 +02:00
parent 81c4019887
commit a0b2430726
+80 -56
View File
@@ -1,22 +1,25 @@
# -*- python -*-
import numpy as numpy
cimport numpy as numpy
cimport cython
@cython.boundscheck(False)
def trace_path(numpy.ndarray[numpy.float32_t, ndim=2] costs not None, start, ends, diagonal_steps=True):
def trace_path(numpy.ndarray[numpy.float32_t, ndim=2] costs not None,
start, ends, diagonal_steps=True):
"""Find the lowest-cost path from the start point to each given end point.
Inputs: 'costs' array; 'start' (x, y) pair; list of 'ends' (x, y) pairs,
and optional 'diagonal_steps' boolean flag.
Costs are given by the input array: a move onto any given position in the
costs array adds that cost to the path. Paths may be constrained to
vertical and horizontal moves only by passing False for the diagonal_steps
parameter. The costs must be non-negative!
The array of cumulative costs from the starting point, and a list of paths
from the start to each end point are returned.
Paths are found by (more or less) breadth-first search outward from the
starting point: each time a lower-cost route to a given pixel is found, that
pixel is marked "active"; the neighbors of all active pixels are then
@@ -38,23 +41,40 @@ def trace_path(numpy.ndarray[numpy.float32_t, ndim=2] costs not None, start, end
raise ValueError("All end points must be (x, y) pairs")
if not (0 <= a < costs.shape[0] and 0 <= b < costs.shape[1]):
raise ValueError("The end points must fall within the array")
cdef numpy.ndarray[numpy.float32_t, ndim=2] cumulative_costs = numpy.empty_like(costs)
cdef numpy.ndarray[numpy.float32_t, ndim=2] cumulative_costs = \
numpy.empty_like(costs)
cumulative_costs.fill(numpy.inf)
cumulative_costs[start] = 0
costs_shape = (costs.shape[0], costs.shape[1])
cdef numpy.ndarray[numpy.uint8_t, ndim=2] active_nodes = numpy.zeros(costs_shape, dtype=numpy.uint8)
cdef numpy.ndarray[numpy.uint8_t, ndim=2] active_nodes = \
numpy.zeros(costs_shape, dtype=numpy.uint8)
active_nodes[start] = 1
cdef numpy.ndarray[numpy.uint8_t, ndim=2] parent_nodes = numpy.empty(costs_shape, dtype=numpy.uint8)
cdef numpy.ndarray[numpy.uint8_t, ndim=2] parent_nodes = \
numpy.empty(costs_shape, dtype=numpy.uint8)
parent_nodes.fill(255)
cdef numpy.ndarray[numpy.int8_t, ndim=2] offsets
cdef numpy.ndarray[numpy.int8_t, ndim=2] offsets
if diagonal_steps:
offsets = numpy.array([[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]], dtype=numpy.int8)
offsets = numpy.array([[-1, -1],
[-1, 0],
[-1, 1],
[ 0, -1],
[ 0, 1],
[ 1, -1],
[ 1, 0],
[ 1, 1]], dtype=numpy.int8)
else:
offsets = numpy.array([[-1, 0], [0, -1], [0, 1], [1, 0]], dtype=numpy.int8)
offsets = numpy.array([[-1, 0],
[0, -1],
[0, 1],
[1, 0]], dtype=numpy.int8)
cdef Py_ssize_t x, y, ox, oy, xo, yo, i
cdef Py_ssize_t a_xmax, a_xmin, a_ymax, a_ymin, tmp_xmax, tmp_xmin, tmp_ymax, tmp_ymin
cdef Py_ssize_t a_xmax, a_xmin, a_ymax, a_ymin, tmp_xmax, \
tmp_xmin, tmp_ymax, tmp_ymin
cdef unsigned int xmax, ymax, active, num_steps
xmax = costs.shape[0] - 1
ymax = costs.shape[1] - 1
@@ -64,51 +84,55 @@ def trace_path(numpy.ndarray[numpy.float32_t, ndim=2] costs not None, start, end
cdef float current_cost, current_cumulative_cost, cumulative_cost, new_cost
while True:
active = 0
# iterate over array
for x in range(0, xmax+1):
for y in range(0, ymax+1):
if active_nodes[x, y]:
active_nodes[x, y] = 0
active = 1
current_cumulative_cost = cumulative_costs[x, y]
# iterate over offsets
for i in range(8):
ox = offsets[i, 0]
oy = offsets[i, 1]
xo = x + ox
yo = y + oy
if xo < 0 or xo > xmax or yo < 0 or yo > ymax:
continue
current_cost = costs[xo, yo]
new_cost = current_cost + current_cumulative_cost
# if a cheaper path to a given point is found, activate that point
if cumulative_costs[xo, yo] > new_cost:
cumulative_costs[xo, yo] = new_cost
parent_nodes[xo, yo] = i
active_nodes[xo, yo] = 1
if not active:
break
active = 0
# iterate over array
for x in range(0, xmax + 1):
for y in range(0, ymax + 1):
if active_nodes[x, y]:
active_nodes[x, y] = 0
active = 1
current_cumulative_cost = cumulative_costs[x, y]
# iterate over offsets
for i in range(8):
ox = offsets[i, 0]
oy = offsets[i, 1]
xo = x + ox
yo = y + oy
if xo < 0 or xo > xmax or yo < 0 or yo > ymax:
continue
current_cost = costs[xo, yo]
new_cost = current_cost + current_cumulative_cost
# if a cheaper path to a given point is found,
# activate that point
if cumulative_costs[xo, yo] > new_cost:
cumulative_costs[xo, yo] = new_cost
parent_nodes[xo, yo] = i
active_nodes[xo, yo] = 1
if not active:
break
cdef unsigned int startx, starty
startx = start[0]
starty = start[1]
return_paths = []
# Trace the paths from the endpoints to the start
for end in ends:
path = None
x = end[0]
y = end[1]
if cumulative_costs[x, y] != numpy.inf:
path = [(x, y)]
while not (x == startx and y == starty):
i = parent_nodes[x, y]
ox = offsets[i, 0]
oy = offsets[i, 1]
x -= ox
y -= oy
path.append((x, y))
path.reverse()
return_paths.append(path)
return cumulative_costs, return_paths
path = None
x = end[0]
y = end[1]
if cumulative_costs[x, y] != numpy.inf:
path = [(x, y)]
while not (x == startx and y == starty):
i = parent_nodes[x, y]
ox = offsets[i, 0]
oy = offsets[i, 1]
x -= ox
y -= oy
path.append((x, y))
path.reverse()
return_paths.append(path)
return cumulative_costs, return_paths