build map history with holes
This commit is contained in:
parent
e453bc4959
commit
7640e77c14
2 changed files with 82 additions and 21 deletions
|
@ -76,7 +76,7 @@ class MapHistory:
|
|||
f.write(struct.pack('<'+'II'*len(self.updates), *chain(*self.updates)))
|
||||
f.write(self.data.tobytes('C'))
|
||||
|
||||
def add_new(self, geometry):
|
||||
def add_new(self, geometry, data=None):
|
||||
prep = prepared.prep(geometry)
|
||||
minx, miny, maxx, maxy = geometry.bounds
|
||||
res = self.resolution
|
||||
|
@ -85,34 +85,44 @@ class MapHistory:
|
|||
maxx = int(math.ceil(maxx/res))
|
||||
maxy = int(math.ceil(maxy/res))
|
||||
|
||||
data = self.data
|
||||
if self.resolution != settings.CACHE_RESOLUTION:
|
||||
data = None
|
||||
self.updates = self.updates[-1:]
|
||||
direct = data is None
|
||||
|
||||
if not data.size:
|
||||
data = np.zeros(((maxy-miny), (maxx-minx)), dtype=np.uint16)
|
||||
self.x, self.y = minx, miny
|
||||
if direct:
|
||||
data = self.data
|
||||
if self.resolution != settings.CACHE_RESOLUTION:
|
||||
data = None
|
||||
self.updates = self.updates[-1:]
|
||||
|
||||
if not data.size:
|
||||
data = np.zeros(((maxy-miny), (maxx-minx)), dtype=np.uint16)
|
||||
self.x, self.y = minx, miny
|
||||
else:
|
||||
orig_height, orig_width = data.shape
|
||||
if minx < self.x or miny < self.y or maxx > self.x+orig_width or maxy > self.y+orig_height:
|
||||
new_x, new_y = min(minx, self.x), min(miny, self.y)
|
||||
new_width = max(maxx, self.x+orig_width)-new_x
|
||||
new_height = max(maxy, self.y+orig_height)-new_y
|
||||
new_data = np.zeros((new_height, new_width), dtype=np.uint16)
|
||||
dx, dy = self.x-new_x, self.y-new_y
|
||||
new_data[dy:(dy+orig_height), dx:(dx+orig_width)] = data
|
||||
data = new_data
|
||||
self.x, self.y = new_x, new_y
|
||||
else:
|
||||
orig_height, orig_width = data.shape
|
||||
if minx < self.x or miny < self.y or maxx > self.x+orig_width or maxy > self.y+orig_height:
|
||||
new_x, new_y = min(minx, self.x), min(miny, self.y)
|
||||
new_width = max(maxx, self.x+orig_width)-new_x
|
||||
new_height = max(maxy, self.y+orig_height)-new_y
|
||||
new_data = np.zeros((new_height, new_width), dtype=np.uint16)
|
||||
dx, dy = self.x-new_x, self.y-new_y
|
||||
new_data[dy:(dy+orig_height), dx:(dx+orig_width)] = data
|
||||
data = new_data
|
||||
self.x, self.y = new_x, new_y
|
||||
height, width = data.shape
|
||||
minx, miny = max(minx, self.x), max(miny, self.y)
|
||||
maxx, maxy = min(maxx, self.x+width), max(maxy, self.y+height)
|
||||
|
||||
new_val = len(self.updates)
|
||||
new_val = len(self.updates) if direct else 1
|
||||
for iy, y in enumerate(range(miny*res, maxy*res, res), start=miny-self.y):
|
||||
for ix, x in enumerate(range(minx*res, maxx*res, res), start=minx-self.x):
|
||||
if prep.intersects(box(x, y, x+res, y+res)):
|
||||
data[iy, ix] = new_val
|
||||
|
||||
self.data = data
|
||||
self.unfinished = True
|
||||
if direct:
|
||||
self.data = data
|
||||
self.unfinished = True
|
||||
else:
|
||||
return data
|
||||
|
||||
def finish(self, update):
|
||||
self.unfinished = False
|
||||
|
@ -140,6 +150,49 @@ class MapHistory:
|
|||
self.y += miny
|
||||
self.data = self.data[miny:maxy+1, minx:maxx+1]
|
||||
|
||||
def composite(self, other, mask_geometry):
|
||||
if other.resolution != other.resolution:
|
||||
return
|
||||
|
||||
# check overlapping area
|
||||
self_height, self_width = self.data.shape
|
||||
other_height, other_width = other.data.shape
|
||||
minx, miny = max(self.x, other.x), max(self.y, other.y)
|
||||
maxx = min(self.x+self_width-1, other.x+other_width-1)
|
||||
maxy = min(self.y+self_height-1, other.y+other_height-1)
|
||||
if maxx < minx or maxy < miny:
|
||||
return
|
||||
|
||||
# merge update lists
|
||||
self_update_i = {update: i for i, update in enumerate(self.updates)}
|
||||
other_update_i = {update: i for i, update in enumerate(other.updates)}
|
||||
new_updates = sorted(set(self_update_i.keys()) | set(other_update_i.keys()))
|
||||
|
||||
# create slices
|
||||
self_slice = slice(miny-self.y, maxy-self.y+1), slice(minx-self.x, maxx-self.x+1)
|
||||
other_slice = slice(miny-other.y, maxy-other.y+1), slice(minx-other.x, maxx-other.x+1)
|
||||
|
||||
# reindex according to new update list
|
||||
other_data = np.zeros_like(self.data)
|
||||
other_data[self_slice] = other.data[other_slice]
|
||||
for i, update in enumerate(new_updates):
|
||||
if update in self_update_i:
|
||||
self.data[self.data == self_update_i[update]] = i
|
||||
if update in other_update_i:
|
||||
other_data[other_data == other_update_i[update]] = i
|
||||
|
||||
# calculate maximum
|
||||
maximum = np.maximum(self.data, other_data)
|
||||
|
||||
# add with mask
|
||||
mask = self.add_new(mask_geometry.buffer(1), data=np.zeros_like(self.data, dtype=np.bool))
|
||||
self.data[mask] = maximum[mask]
|
||||
|
||||
# write new updates
|
||||
self.updates = new_updates
|
||||
|
||||
self.simplify()
|
||||
|
||||
def to_image(self):
|
||||
from c3nav.mapdata.models import Source
|
||||
(miny, minx), (maxy, maxx) = Source.max_bounds()
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.core.cache import cache
|
|||
from django.db import transaction
|
||||
from shapely.ops import unary_union
|
||||
|
||||
from c3nav.mapdata.cache import MapHistory
|
||||
from c3nav.mapdata.models import Level, MapUpdate
|
||||
|
||||
|
||||
|
@ -40,6 +41,8 @@ class LevelRenderData:
|
|||
if level.on_top_of_id is not None:
|
||||
continue
|
||||
|
||||
map_history = MapHistory.open_level(level.pk, 'base')
|
||||
|
||||
level_crop_to = {}
|
||||
|
||||
# choose a crop area for each level. non-intermediate levels (not on_top_of) below the one that we are
|
||||
|
@ -69,6 +72,9 @@ class LevelRenderData:
|
|||
old_geoms = single_level_geoms[sublevel.pk]
|
||||
crop_to = level_crop_to[sublevel.pk]
|
||||
|
||||
if crop_to is not FakeCropper:
|
||||
map_history.composite(MapHistory.open_level(sublevel.pk, 'base'), crop_to)
|
||||
|
||||
new_geoms = LevelGeometries()
|
||||
new_geoms.doors = crop_to.intersection(old_geoms.doors)
|
||||
new_geoms.walls = crop_to.intersection(old_geoms.walls)
|
||||
|
@ -129,6 +135,8 @@ class LevelRenderData:
|
|||
|
||||
level.render_data = pickle.dumps(render_data)
|
||||
|
||||
map_history.save(MapHistory.level_filename(level.pk, 'render'))
|
||||
|
||||
with transaction.atomic():
|
||||
for level in levels:
|
||||
level.save()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue