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