def map_history(request, level, mode, filetype): if not request.user.is_superuser: raise PermissionDenied level = get_object_or_404(Level, pk=level) if mode == 'composite' and level.on_top_of_id is not None: raise Http404 history = MapHistory.open_level(level.pk, mode) if filetype == 'png': response = HttpResponse(content_type='image/png') history.to_image().save(response, format='PNG') elif filetype == 'data': response = HttpResponse(content_type='application/octet-stream') history.write(response) else: raise ValueError response['Cache-Control'] = 'no-cache' return response
def read(cls, f): f = TarFile.open(fileobj=f) files = {info.name: info for info in f.getmembers()} bounds = tuple( i / 100 for i in struct.unpack('<IIII', f.extractfile(files['bounds']).read())) levels = {} for filename in files: if not filename.startswith('history_'): continue level_id = int(filename[8:]) levels[level_id] = CachePackageLevel( history=MapHistory.read( f.extractfile(files['history_%d' % level_id])), restrictions=AccessRestrictionAffected.read( f.extractfile(files['restrictions_%d' % level_id]))) return cls(bounds, levels)
def rebuild(): levels = tuple(Level.objects.prefetch_related('altitudeareas', 'buildings', 'doors', 'spaces', 'spaces__holes', 'spaces__areas', 'spaces__columns', 'spaces__obstacles', 'spaces__lineobstacles', 'spaces__groups', 'spaces__ramps')) package = CachePackage(bounds=tuple(chain(*Source.max_bounds()))) # first pass in reverse to collect some data that we need later single_level_geoms = {} interpolators = {} last_interpolator = None altitudeareas_above = [] for level in reversed(levels): single_level_geoms[level.pk] = LevelGeometries.build_for_level(level, altitudeareas_above) # ignore intermediate levels in this pass if level.on_top_of_id is not None: altitudeareas_above.extend(single_level_geoms[level.pk].altitudeareas) altitudeareas_above.sort(key=operator.attrgetter('altitude')) continue # create interpolator to create the pieces that fit multiple layers together if last_interpolator is not None: interpolators[level.pk] = last_interpolator coords = deque() values = deque() for area in single_level_geoms[level.pk].altitudeareas: new_coords = np.vstack(tuple(np.array(ring.coords) for ring in get_rings(area.geometry))) coords.append(new_coords) values.append(np.full((new_coords.shape[0], 1), fill_value=area.altitude)) if coords: last_interpolator = NearestNDInterpolator(np.vstack(coords), np.vstack(values)) else: last_interpolator = NearestNDInterpolator(np.array([[0, 0]]), np.array([float(level.base_altitude)])) for i, level in enumerate(levels): print("we are at level_id:" + str(level.id) + " level slug: "+level.slug) print("on top of:" + str(level.on_top_of_id)) if level.on_top_of_id is not None: continue print("we continue") map_history = MapHistory.open_level(level.pk, 'base') sublevels = tuple(sublevel for sublevel in levels if sublevel.on_top_of_id == level.pk or sublevel.base_altitude <= level.base_altitude) print("sublevels" + str([l.slug for l in sublevels])) level_crop_to = {} # choose a crop area for each level. non-intermediate levels (not on_top_of) below the one that we are # currently rendering will be cropped to only render content that is visible through holes indoors in the # levels above them. crop_to = None primary_level_count = 0 main_level_passed = 0 lowest_important_level = None last_lower_bound = None for sublevel in reversed(sublevels): geoms = single_level_geoms[sublevel.pk] if geoms.holes is not None: primary_level_count += 1 # get lowest intermediate level directly below main level if not main_level_passed: if geoms.pk == level.pk: main_level_passed = 1 else: if not sublevel.on_top_of_id: main_level_passed += 1 if main_level_passed < 2: lowest_important_level = sublevel # make upper bounds if geoms.on_top_of_id is None: if last_lower_bound is None: geoms.upper_bound = geoms.max_altitude+geoms.max_height else: geoms.upper_bound = last_lower_bound last_lower_bound = geoms.lower_bound # set crop area if we area on the second primary layer from top or below level_crop_to[sublevel.pk] = Cropper(crop_to if primary_level_count > 1 else None) if geoms.holes is not None: if crop_to is None: crop_to = geoms.holes else: crop_to = crop_to.intersection(geoms.holes) if crop_to.is_empty: break render_data = LevelRenderData() render_data.base_altitude = level.base_altitude render_data.lowest_important_level = lowest_important_level.pk access_restriction_affected = {} # go through sublevels, get their level geometries and crop them lowest_important_level_passed = False for sublevel in reversed(sublevels): try: crop_to = level_crop_to[sublevel.pk] except KeyError: print ("in except, sublevel_pk: " + str(sublevel.pk)) break; old_geoms = single_level_geoms[sublevel.pk] if render_data.lowest_important_level == sublevel.pk: lowest_important_level_passed = True if old_geoms.holes and render_data.darken_area is None and lowest_important_level_passed: render_data.darken_area = old_geoms.holes if crop_to.geometry is not None: map_history.composite(MapHistory.open_level(sublevel.pk, 'base'), crop_to.geometry) elif level.pk != sublevel.pk: map_history.composite(MapHistory.open_level(sublevel.pk, 'base'), None) new_geoms = LevelGeometries() new_geoms.buildings = crop_to.intersection(old_geoms.buildings) if old_geoms.on_top_of_id is None: new_geoms.holes = crop_to.intersection(old_geoms.holes) new_geoms.doors = crop_to.intersection(old_geoms.doors) new_geoms.walls = crop_to.intersection(old_geoms.walls) new_geoms.all_walls = crop_to.intersection(old_geoms.all_walls) new_geoms.short_walls = tuple((altitude, geom) for altitude, geom in tuple( (altitude, crop_to.intersection(geom)) for altitude, geom in old_geoms.short_walls ) if not geom.is_empty) for altitudearea in old_geoms.altitudeareas: new_geometry = crop_to.intersection(altitudearea.geometry) if new_geometry.is_empty: continue new_geometry_prep = prepared.prep(new_geometry) new_altitudearea = AltitudeAreaGeometries() new_altitudearea.geometry = new_geometry new_altitudearea.altitude = altitudearea.altitude new_altitudearea.altitude2 = altitudearea.altitude2 new_altitudearea.point1 = altitudearea.point1 new_altitudearea.point2 = altitudearea.point2 new_colors = {} for color, areas in altitudearea.colors.items(): new_areas = {} for access_restriction, area in areas.items(): if not new_geometry_prep.intersects(area): continue new_area = new_geometry.intersection(area) if not new_area.is_empty: new_areas[access_restriction] = new_area if new_areas: new_colors[color] = new_areas new_altitudearea.colors = new_colors new_altitudearea_obstacles = {} for height, height_obstacles in altitudearea.obstacles.items(): new_height_obstacles = {} for color, color_obstacles in height_obstacles.items(): new_color_obstacles = [] for obstacle in color_obstacles: if new_geometry_prep.intersects(obstacle): new_color_obstacles.append(obstacle.intersection(altitudearea.geometry)) if new_color_obstacles: new_height_obstacles[color] = new_color_obstacles if new_height_obstacles: new_altitudearea_obstacles[height] = new_height_obstacles new_altitudearea.obstacles = new_altitudearea_obstacles new_geoms.altitudeareas.append(new_altitudearea) if new_geoms.walls.is_empty and not new_geoms.altitudeareas: continue new_geoms.ramps = tuple( ramp for ramp in (crop_to.intersection(ramp) for ramp in old_geoms.ramps) if not ramp.is_empty ) new_geoms.heightareas = tuple( (area, height) for area, height in ((crop_to.intersection(area), height) for area, height in old_geoms.heightareas) if not area.is_empty ) new_geoms.affected_area = unary_union(( *(altitudearea.geometry for altitudearea in new_geoms.altitudeareas), crop_to.intersection(new_geoms.walls.buffer(1)) )) for access_restriction, area in old_geoms.access_restriction_affected.items(): new_area = crop_to.intersection(area) if not new_area.is_empty: access_restriction_affected.setdefault(access_restriction, []).append(new_area) new_geoms.restricted_spaces_indoors = {} for access_restriction, area in old_geoms.restricted_spaces_indoors.items(): new_area = crop_to.intersection(area) if not new_area.is_empty: new_geoms.restricted_spaces_indoors[access_restriction] = new_area new_geoms.restricted_spaces_outdoors = {} for access_restriction, area in old_geoms.restricted_spaces_outdoors.items(): new_area = crop_to.intersection(area) if not new_area.is_empty: new_geoms.restricted_spaces_outdoors[access_restriction] = new_area new_geoms.pk = old_geoms.pk new_geoms.on_top_of_id = old_geoms.on_top_of_id new_geoms.short_label = old_geoms.short_label new_geoms.base_altitude = old_geoms.base_altitude new_geoms.default_height = old_geoms.default_height new_geoms.door_height = old_geoms.door_height new_geoms.min_altitude = (min(area.altitude for area in new_geoms.altitudeareas) if new_geoms.altitudeareas else new_geoms.base_altitude) new_geoms.max_altitude = (max(area.altitude for area in new_geoms.altitudeareas) if new_geoms.altitudeareas else new_geoms.base_altitude) new_geoms.max_height = (min(height for area, height in new_geoms.heightareas) if new_geoms.heightareas else new_geoms.default_height) new_geoms.lower_bound = old_geoms.lower_bound new_geoms.upper_bound = old_geoms.upper_bound new_geoms.build_mesh(interpolators.get(level.pk) if sublevel.pk == level.pk else None) render_data.levels.append(new_geoms) access_restriction_affected = { access_restriction: unary_union(areas) for access_restriction, areas in access_restriction_affected.items() } access_restriction_affected = AccessRestrictionAffected.build(access_restriction_affected) access_restriction_affected.save_level(level.pk, 'composite') map_history.save_level(level.pk, 'composite') package.add_level(level.pk, map_history, access_restriction_affected) render_data.save(level.pk) package.save_all()
def rebuild(): levels = tuple(Level.objects.prefetch_related('altitudeareas', 'buildings', 'doors', 'spaces', 'spaces__holes', 'spaces__areas', 'spaces__columns', 'spaces__obstacles', 'spaces__lineobstacles', 'spaces__groups', 'spaces__ramps')) package = CachePackage(bounds=tuple(chain(*Source.max_bounds()))) # first pass in reverse to collect some data that we need later single_level_geoms = {} interpolators = {} last_interpolator = None altitudeareas_above = [] for level in reversed(levels): single_level_geoms[level.pk] = LevelGeometries.build_for_level(level, altitudeareas_above) # ignore intermediate levels in this pass if level.on_top_of_id is not None: altitudeareas_above.extend(single_level_geoms[level.pk].altitudeareas) altitudeareas_above.sort(key=operator.attrgetter('altitude')) continue # create interpolator to create the pieces that fit multiple layers together if last_interpolator is not None: interpolators[level.pk] = last_interpolator coords = deque() values = deque() for area in single_level_geoms[level.pk].altitudeareas: new_coords = np.vstack(tuple(np.array(ring.coords) for ring in get_rings(area.geometry))) coords.append(new_coords) values.append(np.full((new_coords.shape[0], 1), fill_value=area.altitude)) if coords: last_interpolator = NearestNDInterpolator(np.vstack(coords), np.vstack(values)) else: last_interpolator = NearestNDInterpolator(np.array([[0, 0]]), np.array([float(level.base_altitude)])) for i, level in enumerate(levels): if level.on_top_of_id is not None: continue map_history = MapHistory.open_level(level.pk, 'base') sublevels = tuple(sublevel for sublevel in levels if sublevel.on_top_of_id == level.pk or sublevel.base_altitude <= level.base_altitude) level_crop_to = {} # choose a crop area for each level. non-intermediate levels (not on_top_of) below the one that we are # currently rendering will be cropped to only render content that is visible through holes indoors in the # levels above them. crop_to = None primary_level_count = 0 main_level_passed = 0 lowest_important_level = None last_lower_bound = None for sublevel in reversed(sublevels): geoms = single_level_geoms[sublevel.pk] if geoms.holes is not None: primary_level_count += 1 # get lowest intermediate level directly below main level if not main_level_passed: if geoms.pk == level.pk: main_level_passed = 1 else: if not sublevel.on_top_of_id: main_level_passed += 1 if main_level_passed < 2: lowest_important_level = sublevel # make upper bounds if geoms.on_top_of_id is None: if last_lower_bound is None: geoms.upper_bound = geoms.max_altitude+geoms.max_height else: geoms.upper_bound = last_lower_bound last_lower_bound = geoms.lower_bound # set crop area if we area on the second primary layer from top or below level_crop_to[sublevel.pk] = Cropper(crop_to if primary_level_count > 1 else None) if geoms.holes is not None: if crop_to is None: crop_to = geoms.holes else: crop_to = crop_to.intersection(geoms.holes) if crop_to.is_empty: break render_data = LevelRenderData() render_data.base_altitude = level.base_altitude render_data.lowest_important_level = lowest_important_level.pk access_restriction_affected = {} # go through sublevels, get their level geometries and crop them lowest_important_level_passed = False for sublevel in sublevels: try: crop_to = level_crop_to[sublevel.pk] except KeyError: break old_geoms = single_level_geoms[sublevel.pk] if render_data.lowest_important_level == sublevel.pk: lowest_important_level_passed = True if old_geoms.holes and render_data.darken_area is None and lowest_important_level_passed: render_data.darken_area = old_geoms.holes if crop_to.geometry is not None: map_history.composite(MapHistory.open_level(sublevel.pk, 'base'), crop_to.geometry) elif level.pk != sublevel.pk: map_history.composite(MapHistory.open_level(sublevel.pk, 'base'), None) new_geoms = LevelGeometries() new_geoms.buildings = crop_to.intersection(old_geoms.buildings) if old_geoms.on_top_of_id is None: new_geoms.holes = crop_to.intersection(old_geoms.holes) new_geoms.doors = crop_to.intersection(old_geoms.doors) new_geoms.walls = crop_to.intersection(old_geoms.walls) new_geoms.all_walls = crop_to.intersection(old_geoms.all_walls) new_geoms.short_walls = tuple((altitude, geom) for altitude, geom in tuple( (altitude, crop_to.intersection(geom)) for altitude, geom in old_geoms.short_walls ) if not geom.is_empty) for altitudearea in old_geoms.altitudeareas: new_geometry = crop_to.intersection(altitudearea.geometry) if new_geometry.is_empty: continue new_geometry_prep = prepared.prep(new_geometry) new_altitudearea = AltitudeAreaGeometries() new_altitudearea.geometry = new_geometry new_altitudearea.altitude = altitudearea.altitude new_altitudearea.altitude2 = altitudearea.altitude2 new_altitudearea.point1 = altitudearea.point1 new_altitudearea.point2 = altitudearea.point2 new_colors = {} for color, areas in altitudearea.colors.items(): new_areas = {} for access_restriction, area in areas.items(): if not new_geometry_prep.intersects(area): continue new_area = new_geometry.intersection(area) if not new_area.is_empty: new_areas[access_restriction] = new_area if new_areas: new_colors[color] = new_areas new_altitudearea.colors = new_colors new_altitudearea.obstacles = {key: tuple(new_geometry.intersection(obstacle) for obstacle in height_obstacles if new_geometry_prep.intersects(obstacle)) for key, height_obstacles in altitudearea.obstacles.items()} new_altitudearea.obstacles = {height: height_obstacles for height, height_obstacles in new_altitudearea.obstacles.items() if height_obstacles} new_geoms.altitudeareas.append(new_altitudearea) if new_geoms.walls.is_empty and not new_geoms.altitudeareas: continue new_geoms.ramps = tuple( ramp for ramp in (crop_to.intersection(ramp) for ramp in old_geoms.ramps) if not ramp.is_empty ) new_geoms.heightareas = tuple( (area, height) for area, height in ((crop_to.intersection(area), height) for area, height in old_geoms.heightareas) if not area.is_empty ) new_geoms.affected_area = unary_union(( *(altitudearea.geometry for altitudearea in new_geoms.altitudeareas), crop_to.intersection(new_geoms.walls.buffer(1)) )) for access_restriction, area in old_geoms.access_restriction_affected.items(): new_area = crop_to.intersection(area) if not new_area.is_empty: access_restriction_affected.setdefault(access_restriction, []).append(new_area) new_geoms.restricted_spaces_indoors = {} for access_restriction, area in old_geoms.restricted_spaces_indoors.items(): new_area = crop_to.intersection(area) if not new_area.is_empty: new_geoms.restricted_spaces_indoors[access_restriction] = new_area new_geoms.restricted_spaces_outdoors = {} for access_restriction, area in old_geoms.restricted_spaces_outdoors.items(): new_area = crop_to.intersection(area) if not new_area.is_empty: new_geoms.restricted_spaces_outdoors[access_restriction] = new_area new_geoms.pk = old_geoms.pk new_geoms.on_top_of_id = old_geoms.on_top_of_id new_geoms.short_label = old_geoms.short_label new_geoms.base_altitude = old_geoms.base_altitude new_geoms.default_height = old_geoms.default_height new_geoms.door_height = old_geoms.door_height new_geoms.min_altitude = (min(area.altitude for area in new_geoms.altitudeareas) if new_geoms.altitudeareas else new_geoms.base_altitude) new_geoms.max_altitude = (max(area.altitude for area in new_geoms.altitudeareas) if new_geoms.altitudeareas else new_geoms.base_altitude) new_geoms.max_height = (min(height for area, height in new_geoms.heightareas) if new_geoms.heightareas else new_geoms.default_height) new_geoms.lower_bound = old_geoms.lower_bound new_geoms.upper_bound = old_geoms.upper_bound new_geoms.build_mesh(interpolators.get(level.pk) if sublevel.pk == level.pk else None) render_data.levels.append(new_geoms) access_restriction_affected = { access_restriction: unary_union(areas) for access_restriction, areas in access_restriction_affected.items() } access_restriction_affected = AccessRestrictionAffected.build(access_restriction_affected) access_restriction_affected.save_level(level.pk, 'composite') map_history.save_level(level.pk, 'composite') package.add_level(level.pk, map_history, access_restriction_affected) render_data.save(level.pk) package.save_all()