diff --git a/src/c3nav/mapdata/models/level.py b/src/c3nav/mapdata/models/level.py index 007db557..533473f1 100644 --- a/src/c3nav/mapdata/models/level.py +++ b/src/c3nav/mapdata/models/level.py @@ -1,7 +1,7 @@ import os from decimal import Decimal from itertools import chain -from operator import attrgetter +from operator import attrgetter, itemgetter from django.conf import settings from django.db import models @@ -231,11 +231,18 @@ class Level(SpecificLocation, models.Model): self._render_scad_polygon(f, area.geometry, area.altitude, low_clip=low_clip) draw_obstacles = {} + height_spaces = {} for space in spaces: + columns = cascaded_union(tuple(columns.geometry for columns in space.columns.all())) + space.geometry = space.geometry.difference(columns) + if self.on_top_of_id is None and not space.outside: + height = space.height or self.default_height + height_spaces.setdefault(height, []).append(space.geometry) + holes = cascaded_union(tuple(hole.geometry for hole in space.holes.all())) for lineobstacle in space.lineobstacles.all(): lineobstacle.geometry = lineobstacle.buffered_geometry for obstacle in chain(space.obstacles.all(), space.lineobstacles.all()): - geometry = obstacle.geometry.intersection(space.geometry) + geometry = obstacle.geometry.intersection(space.geometry).difference(holes) for altitudearea in self.altitudeareas.all(): intersection = geometry.intersection(altitudearea.geometry) if not intersection.is_empty: @@ -250,6 +257,34 @@ class Level(SpecificLocation, models.Model): for (altitude, height), polygons in draw_obstacles.items(): self._render_scad_polygon(f, cascaded_union(polygons), altitude, height, low_clip=low_clip) + spaces_geom = cascaded_union(tuple(space.geometry for space in self.spaces.all() if not space.outside)) + buildings_geom = cascaded_union(tuple(building.geometry for building in self.buildings.all())) + doors_geom = cascaded_union(tuple(door.geometry for door in self.doors.all())) + walls_geom = buildings_geom.difference(doors_geom).difference(spaces_geom) + + drawn_walls = {} + for height, polygons in sorted(height_spaces.items(), key=itemgetter(0)): + polygons = cascaded_union(polygons) + for area in self.altitudeareas.all(): + intersection = area.geometry.intersection(polygons) + if not intersection.is_empty: + walls = intersection.buffer(0.5, join_style=JOIN_STYLE.mitre).intersection(walls_geom) + walls = walls.buffer(0.001, join_style=JOIN_STYLE.mitre) + self._render_scad_polygon(f, walls, area.altitude+height, low_clip=low_clip) + drawn_walls.setdefault(area.altitude+height, []).append(walls) + + remaining_walls_geom = walls_geom.difference(cascaded_union(tuple(chain(*drawn_walls.values())))) + + drawn_walls = {altitude: cascaded_union(walls) for altitude, walls in drawn_walls.items()} + drawn_walls_sorted = sorted(drawn_walls.items(), key=itemgetter(0)) + for wall in assert_multipolygon(remaining_walls_geom): + buffered = wall.buffer(0.001, join_style=JOIN_STYLE.mitre) + try: + altitude = next(iter(altitude for altitude, geom in drawn_walls_sorted if geom.intersects(buffered))) + except StopIteration: + altitude = min(drawn_walls_sorted, key=lambda a: buffered.distance(a[1]))[0] + self._render_scad_polygon(f, buffered, altitude, low_clip=low_clip) + @classmethod def _render_scad_levels(cls, levels, filename, level_spaces): bounds = cascaded_union(tuple(box(*level.bounds) for level in levels)).bounds