change the poorly integrated "walkable-tile-check"
This commit is contained in:
parent
11fc99cbb5
commit
bdc3ee46d6
@ -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)
|
||||
|
81
tools.py
81
tools.py
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user