add LevelMapHistory

This commit is contained in:
Laura Klünder 2017-10-23 22:50:15 +02:00
parent 82fc9f2264
commit 026926503c
2 changed files with 89 additions and 0 deletions

View file

@ -1,8 +1,96 @@
import math
import struct
import numpy as np
from django.conf import settings
from django.db.models.signals import m2m_changed, post_delete
from shapely import prepared
from shapely.geometry import box
from c3nav.mapdata.utils.models import get_submodels
class MapHistory:
# binary format (everything little-endian):
# 1 byte (uint8): resolution
# 2 bytes (uint16): origin x
# 2 bytes (uint16): origin y
# 2 bytes (uint16): origin width
# 2 bytes (uint16): origin height
# 2 bytes (uint16): number of updates
# n*16 bytes: update keys as null-terminated strings
# width*height*2 bytes: data (line after line) with uint16 data
def __init__(self, resolution=settings.CACHE_RESOLUTION, x=None, y=None, updates=None, data=None):
self.resolution = resolution
self.x = None
self.y = None
self.updates = updates
self.data = data
self.unfinished = False
@classmethod
def open(cls, filename, default_update=None):
try:
with open(filename, 'rb') as f:
resolution, x, y, width, height, num_updates = struct.unpack('<BHHHHH', f.read(11))
updates = list(struct.unpack('16s'*num_updates, f.read(num_updates*16)))
data = np.frombuffer(f.read(width*height*2), np.uint16).reshape((height, width))
return cls(resolution, x, y, list(updates), data)
except FileNotFoundError:
if default_update is None:
raise
return cls(updates=[default_update])
def save(self, filename):
with open(filename, 'wb') as f:
f.write(struct.pack('<BHHHHH', self.resolution, self.x, self.y, *reversed(self.data.shape),
len(self.updates)))
f.write(struct.pack('16s'*len(self.updates), *self.updates))
f.write(self.data.tobytes('C'))
def add_new(self, geometry):
prep = prepared.prep(geometry)
minx, miny, maxx, maxy = geometry.bounds
res = self.resolution
minx = int(math.floor(minx/res))
miny = int(math.floor(miny/res))
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:]
if data is None:
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 = min(maxx, self.x+orig_width)-new_x
new_height = min(maxy, self.y+orig_height)-new_y
new_data = np.zeros((new_height, new_width), dtype=np.uint16)
dx, dy = new_x-self.x, new_y-self.y
new_data[dy:dx, (dy+orig_height):(dx+orig_width)] = data
data = new_data
self.x, self.y = new_x, new_y
new_val = len(self.updates)
for iy, y in enumerate(range(miny*res, maxy*res, res), start=miny-self.y):
for ix, x in enumerate(range(miny*res, maxy*res, res), start=minx-self.x):
if prep.intersects(box(x, y, x+res, y+res)):
data[iy, ix] = new_val
self.unfinished = True
def finish(self, cache_key):
self.unfinished = False
self.updates.append(cache_key)
class GeometryChangeTracker:
def __init__(self):
self._geometries_by_level = {}

View file

@ -59,6 +59,7 @@ DEBUG = config.getboolean('django', 'debug', fallback=debug_fallback)
RENDER_SCALE = float(config.get('c3nav', 'render_scale', fallback=20.0))
SVG_RENDERER = config.get('c3nav', 'svg_renderer', fallback='rsvg-convert')
CACHE_TILES = config.get('c3nav', 'cache_tiles', fallback=not DEBUG)
CACHE_RESOLUTION = config.get('c3nav', 'cache_resolution', fallback=4)
db_backend = config.get('database', 'backend', fallback='sqlite3')
DATABASES = {