change the poorly integrated "walkable-tile-check"

This commit is contained in:
Steffen Illium 2017-07-24 11:24:30 +02:00
parent 11fc99cbb5
commit bdc3ee46d6
2 changed files with 43 additions and 42 deletions

View File

@ -11,7 +11,7 @@ from tools import Worker, Isovist, TrackCollection, IndoorToolset # , Track, Is
if __name__ == '__main__':
walkableTiles = 255
walkableTiles = [255, 103, 210, 79]
trackColor = 103
startColor = 210
endColor = 79
@ -82,7 +82,7 @@ if __name__ == '__main__':
if False:
point = baseToolset.getRandomPos()
print(point)
i = Isovist(*point, array=baseToolset.imgArray, walkable=walkableTiles, rangeLimit=30)
i = Isovist(*point, array=baseToolset.imgArray, walkables=walkableTiles, rangeLimit=30)
i.saveImg()
baseToolset.imgArray[point] = 160
imshow(baseToolset.imgArray)

View File

@ -19,7 +19,7 @@ from PCHA import PCHA
from operator import itemgetter
from dtw import dtw
workercount = 1
workercount = 6
class Worker(object):
@ -62,26 +62,26 @@ class Worker(object):
class IsovistCollection(UserDict):
def __init__(self, walkable, rangeLimit, tileArray, worker=None, single_threaded=False):
def __init__(self, walkables, rangeLimit, tileArray, worker=None, single_threaded=False):
super(IsovistCollection, self).__init__()
if not isinstance(worker, Worker):
raise TypeError
self.data = dict()
self.walkable = walkable
self.walkables = walkables
self.tileArray = tileArray
self.rangeLimit = rangeLimit
self.lfr = None
if rangeLimit:
if not single_threaded:
workerResult = worker.init_many(
Isovist, [(*npIdx, self.tileArray, self.walkable, self.rangeLimit)
for npIdx, value in np.ndenumerate(self.tileArray) if value == self.walkable])
Isovist, [(*npIdx, self.tileArray, self.walkables, self.rangeLimit)
for npIdx, value in np.ndenumerate(self.tileArray) if value == self.walkables])
self.data = {isovist.vertex: isovist for isovist in workerResult}
# The following would be a non multithreaded approach, maybe activate it for smaller blueprints later
# TODO: Activate this for smaller Blueprints, when multithreading would lead to overhead
else:
for ndIndex, value in np.ndenumerate(self.tileArray):
if value == self.walkable or value > 0:
if value in self.walkables:
self.add_isovist(*ndIndex)
else:
pass
@ -99,7 +99,7 @@ class IsovistCollection(UserDict):
:rtype: bool
"""
self[(x, y)] = (Isovist(x, y, self.tileArray, self.walkable, self.rangeLimit))
self[(x, y)] = (Isovist(x, y, self.tileArray, self.walkables, self.rangeLimit))
return True
@staticmethod
@ -211,7 +211,7 @@ class IsovistCollection(UserDict):
class Isovist(object):
def __init__(self, x, y, array, walkable, rangeLimit):
def __init__(self, x, y, array, walkables, rangeLimit):
"""
"Calculate lit squares from the given location and radius through 'Shadow Casting'"
Source:
@ -224,8 +224,8 @@ class Isovist(object):
:type y: int
:param array: Numpy Array holding the background image
:type array: np.ndarray
:param walkable: The value which identifies positions in the array through which light can travel
:type walkable: int or (int, int, int)
:param walkables: The value which identifies positions in the array through which light can travel
:type walkables: int or (int, int, int)
:param rangeLimit: Determine the radius in which pixels of the shadow needs to be calculated
:type rangeLimit: int
"""
@ -236,14 +236,17 @@ class Isovist(object):
self.x = x
self.y = y
self.vertex = (self.x, self.y)
self.walkables = walkables
if isinstance(array, np.ndarray):
self.rangeLimit = rangeLimit if rangeLimit else int(sqrt(array.shape[0] * array.shape[1]))
self.radius = rangeLimit // 2 + 1
self.visArray = np.zeros(array.shape, dtype=bool)
for octant in range(8):
self.__cast_light(self.x, self.y, 1, 1.0, 0.0, self.rangeLimit,
self.__cast_light(self.x, self.y, 1, 1.0, 0.0,
mult[0][octant], mult[1][octant],
mult[2][octant], mult[3][octant], 0, array, walkable)
mult[2][octant], mult[3][octant], 0, array)
offset = int(rangeLimit/2)
# self.visArray = self.visArray[
@ -260,12 +263,11 @@ class Isovist(object):
self.Xcent = centroid[0]
self.Ycent = centroid[1]
@staticmethod
def __blocksLight(x, y, array, walkable):
def __blocksLight(self, x, y, array):
if x < 0 or y < 0:
return True
try:
return False if array[x, y] == walkable or array[x, y] > 0 else True
return False if array[x, y] in self.walkables else True
except IndexError:
return True
@ -280,12 +282,12 @@ class Isovist(object):
def __isVisible(self, x, y):
return self.visArray[x, y]
def __cast_light(self, cx, cy, row, start, end, radius, xx, xy, yx, yy, idx, array, walkable):
"""Recursive lightcasting function"""
def __cast_light(self, cx, cy, row, start, end, xx, xy, yx, yy, idx, array):
"""Recursive lightcasting function from roguebasin.com"""
if start < end:
return
radius_squared = radius * radius
for j in range(row, radius + 1):
radius_squared = self.radius * self.radius
for j in range(row, self.radius + 1):
dx, dy = -j - 1, -j
blocked = False
while dx <= 0:
@ -305,18 +307,17 @@ class Isovist(object):
self.__setVisible(X, Y)
if blocked:
# we're scanning a row of blocked squares:
if self.__blocksLight(X, Y, array, walkable):
if self.__blocksLight(X, Y, array):
new_start = r_slope
continue
else:
blocked = False
start = new_start
else:
if self.__blocksLight(X, Y, array, walkable) and j < radius:
if self.__blocksLight(X, Y, array) and j < self.radius:
# This is a blocking square, start a child scan:
blocked = True
self.__cast_light(cx, cy, j + 1, start, l_slope,
radius, xx, xy, yx, yy, idx + 1, array, walkable)
self.__cast_light(cx, cy, j + 1, start, l_slope, xx, xy, yx, yy, idx + 1, array)
new_start = r_slope
# Row is scanned; do next row unless last square was blocked:
if blocked:
@ -381,13 +382,12 @@ class TrackCollection(UserDict):
self[key] = track
return True
def add_n_bunch_tracks(self, n, start, target, nbunch=None, penalty=None):
def build_track(segment1, segment2):
combined = list()
combined.extend(segment1 + list(reversed(segment2)))
return Track(combined, self.map.walkableTile)
return Track(combined, self.map.walkableTiles)
if isinstance(penalty, int) or isinstance(penalty, float):
for i in range(n):
@ -565,7 +565,7 @@ class TrackCollection(UserDict):
return [self[key] for key in [self.archeArray[:, 0][idx] for idx in idxArray]]
def return_walkableTileList(self):
return [npIndex for npIndex, value in np.ndenumerate(self.map.imgArray) if value == self.map.walkableTile]
return [npIndex for npIndex, value in np.ndenumerate(self.map.imgArray) if value in self.map.walkableTiles]
def save_to_disc(self, filename):
filename = filename if filename.endswith('.pik') else '%s%s' % (filename, '.pik')
@ -699,7 +699,7 @@ class TrackCollection(UserDict):
position = c[0] if c[0] not in currentTrack else c[1]
else:
raise ValueError('Something went wrong here, maybe no stop position?')
tracks.append(Track(currentTrack, self.map.walkableTile, qhull=False))
tracks.append(Track(currentTrack, self.map.walkableTiles, qhull=False))
self.add_n_bunch_tracks(0, 0, 0, tracks)
@ -711,13 +711,12 @@ class TrackCollection(UserDict):
pass
class Track(UserList):
def __init__(self, NodeList, walkableTile, qhull=True):
def __init__(self, NodeList, walkableTiles, qhull=True):
if not isinstance(NodeList, list):
raise TypeError
super(UserList, self).__init__()
self.walkableTile = walkableTile
self.walkableTiles = walkableTiles
self.data = NodeList.copy()
self.group = None
self.vertex = None
@ -799,7 +798,7 @@ class Track(UserList):
('an' if typ.startswith(prefix) else 'a', typ))
l = self.data
l.extend(l2)
return Track(l, self.walkableTile)
return Track(l, self.walkableTiles)
def return_isovists(self, trackCollection=None, indoorToolset=None):
if isinstance(trackCollection, TrackCollection):
@ -812,7 +811,7 @@ class Track(UserList):
class IndoorToolset(object):
def __init__(self, imageArray, walkableTile, graph=None, worker=None, isoVistSize=0):
def __init__(self, imageArray, walkableTiles, graph=None, worker=None, isoVistSize=0):
"""
:param graph: An optional Graph
:type graph: nx.Graph
@ -820,7 +819,7 @@ class IndoorToolset(object):
if not isinstance(imageArray, np.ndarray) or not isinstance(worker, Worker):
raise TypeError
self.walkableTile = walkableTile
self.walkableTiles = walkableTiles
self.imgArray = imageArray
self.shape = self.imgArray.shape
self.height = self.shape[0]
@ -830,14 +829,14 @@ class IndoorToolset(object):
else:
self.graph = self.translate_to_graph()
self.__rand = random.Random()
self.isovists = IsovistCollection(self.walkableTile, isoVistSize, self.imgArray, worker=worker)
self.isovists = IsovistCollection(self.walkableTiles, isoVistSize, self.imgArray,
worker=worker, single_threaded=True)
def refresh_random_clock(self):
self.__rand.seed(time.clock())
def copy(self):
return IndoorToolset(self.imgArray.copy(), self.walkableTile, graph=self.graph.copy())
return IndoorToolset(self.imgArray.copy(), self.walkableTiles, graph=self.graph.copy())
def __len__(self):
return self.width * self.height
@ -898,9 +897,11 @@ class IndoorToolset(object):
rs = self.graph.nodes()[self.__rand.randrange(len(self.graph))]
if verbose:
print(rs, ' is random Position -> checking accessibiliy')
notWalkable = False
if self.imgArray[rs] != self.walkableTile:
if self.imgArray[rs] in self.walkableTiles:
notWalkable = True
else:
notWalkable = False
while notWalkable:
self.refresh_random_clock()
rs = self.graph.nodes()[self.__rand.randrange(len(self.graph))]
@ -913,7 +914,7 @@ class IndoorToolset(object):
def translate_to_graph(self):
graph = nx.Graph()
for idx, value in np.ndenumerate(self.imgArray):
if value > 0 or value == self.walkableTile:
if value in self.walkableTiles:
x, y = idx
graph.add_node((x, y), count=0)
@ -972,7 +973,7 @@ class IndoorToolset(object):
oldWeight = self.graph.edge[currNode][nextNode]['weight']
self.graph.add_edge(currNode, nextNode, weight=oldWeight + penalty)
track = Track(dij_s_p, self.walkableTile, qhull=qhull)
track = Track(dij_s_p, self.walkableTiles, qhull=qhull)
print(len(dij_s_p), ' Len Path generated -> Nodes: ', len(self.graph), ' -> Edges: ', len(self.graph.edges()))
return track