diff --git a/src/c3nav/mapdata/models/geometry/level.py b/src/c3nav/mapdata/models/geometry/level.py index 8d83eaf0..d6c6437a 100644 --- a/src/c3nav/mapdata/models/geometry/level.py +++ b/src/c3nav/mapdata/models/geometry/level.py @@ -229,13 +229,13 @@ class AltitudeArea(LevelGeometryMixin, models.Model): if space.outside: space.geometry = space.geometry.difference(buildings_geom) space_accessible = space.geometry.difference( - unary_union(tuple(c.geometry for c in space.columns.all() if c.access_restriction_id is None) + - tuple(o.geometry for o in space.obstacles.all() if o.altitude == 0) + + unary_union(tuple(unwrap_geom(c.geometry) for c in space.columns.all() if c.access_restriction_id is None) + + tuple(unwrap_geom(o.geometry) for o in space.obstacles.all() if o.altitude == 0) + tuple(o.buffered_geometry for o in space.lineobstacles.all() if o.altitude == 0) + - tuple(h.geometry for h in space.holes.all())) + tuple(unwrap_geom(h.geometry) for h in space.holes.all())) ) - space_ramps = unary_union(tuple(r.geometry for r in space.ramps.all())) + space_ramps = unary_union(tuple(unwrap_geom(r.geometry) for r in space.ramps.all())) areas.append(space_accessible.difference(space_ramps)) for geometry in assert_multipolygon(space_accessible.intersection(space_ramps)): ramp = AltitudeArea(geometry=geometry, level=level) @@ -244,7 +244,7 @@ class AltitudeArea(LevelGeometryMixin, models.Model): ramps.append(ramp) areas = tuple(orient(polygon) for polygon in assert_multipolygon( - unary_union(areas+list(door.geometry for door in level.doors.all())) + unary_union(areas+list(unwrap_geom(door.geometry) for door in level.doors.all())) )) # collect all stairs on this level @@ -281,7 +281,7 @@ class AltitudeArea(LevelGeometryMixin, models.Model): for space in level.spaces.all(): for altitudemarker in space.altitudemarkers.all(): for area in space_areas[space.pk]: - if area.geometry_prep.contains(altitudemarker.geometry): + if area.geometry_prep.contains(unwrap_geom(altitudemarker.geometry)): area.altitude = altitudemarker.altitude break else: @@ -471,7 +471,7 @@ class AltitudeArea(LevelGeometryMixin, models.Model): space.geometry = space.orig_geometry buildings_geom = unary_union(tuple(unwrap_geom(b.geometry) for b in level.buildings.all())) - doors_geom = unary_union(tuple(d.geometry for d in level.doors.all())) + doors_geom = unary_union(tuple(unwrap_geom(d.geometry) for d in level.doors.all())) space_geom = unary_union(tuple((unwrap_geom(s.geometry) if not s.outside else s.geometry.difference(buildings_geom)) @@ -481,7 +481,7 @@ class AltitudeArea(LevelGeometryMixin, models.Model): accessible_area = unary_union((doors_geom, space_geom)) for space in level.spaces.all(): accessible_area = accessible_area.difference(space.geometry.intersection( - unary_union(tuple(h.geometry for h in space.holes.all())) + unary_union(tuple(unwrap_geom(h.geometry) for h in space.holes.all())) )) # areas mean altitude areas (including ramps) here @@ -497,17 +497,17 @@ class AltitudeArea(LevelGeometryMixin, models.Model): if space.outside: space_geom = space_geom.difference(buildings_geom) space_geom_prep = prepared.prep(unwrap_geom(space_geom)) - holes_geom = unary_union(tuple(h.geometry for h in space.holes.all())) + holes_geom = unary_union(tuple(unwrap_geom(h.geometry) for h in space.holes.all())) # remaining_space means remaining space (=obstacles) that still needs to be added to altitude areas remaining_space = ( - tuple(o.geometry for o in space.obstacles.all()) + + tuple(unwrap_geom(o.geometry) for o in space.obstacles.all()) + tuple(o.buffered_geometry for o in space.lineobstacles.all()) ) # make sure to remove everything outside the space the obstacles are in as well as holes - remaining_space = tuple(g.intersection(space_geom).difference(holes_geom) + remaining_space = tuple(g.intersection(unwrap_geom(space_geom)).difference(holes_geom) for g in remaining_space - if space_geom_prep.intersects(g)) + if space_geom_prep.intersects(unwrap_geom(g))) # we need this to be a list of simple normal polygons remaining_space = tuple(chain(*( assert_multipolygon(g) for g in remaining_space if not g.is_empty @@ -597,9 +597,9 @@ class AltitudeArea(LevelGeometryMixin, models.Model): potential_areas = [area for area in potential_areas if (candidate.altitude, candidate.altitude2) in ((area.altitude, area.altitude2), (area.altitude2, area.altitude))] - potential_areas = [(area, area.geometry.intersection(candidate.geometry).area) + potential_areas = [(area, area.geometry.intersection(unwrap_geom(candidate.geometry)).area) for area in potential_areas - if candidate.geometry_prep.intersects(area.geometry)] + if candidate.geometry_prep.intersects(unwrap_geom(area.geometry))] if potential_areas: new_area = max(potential_areas, key=itemgetter(1))[0] diff --git a/src/c3nav/mapdata/render/geometry/level.py b/src/c3nav/mapdata/render/geometry/level.py index c28a5b69..68246e54 100644 --- a/src/c3nav/mapdata/render/geometry/level.py +++ b/src/c3nav/mapdata/render/geometry/level.py @@ -78,11 +78,11 @@ class LevelGeometries: if columns: subtract.extend(columns) if subtract: - space.geometry = space.geometry.difference(unary_union(subtract)) + space.geometry = space.geometry.difference(unary_union([unwrap_geom(geom) for geom in subtract])) holes = tuple(h.geometry for h in space.holes.all()) if holes: - space.holes_geom = unary_union([h.geometry for h in space.holes.all()]) + space.holes_geom = unary_union([unwrap_geom(h.geometry) for h in space.holes.all()]) space.walkable_geom = space.geometry.difference(space.holes_geom) space.holes_geom = space.geometry.intersection(space.holes_geom) else: @@ -110,7 +110,7 @@ class LevelGeometries: heightareas = {} for space in level.spaces.all(): buffered = space.geometry.buffer(0.01).union(unary_union( - tuple(door.geometry for door in level.doors.all() if door.geometry.intersects(space.geometry)) + tuple(unwrap_geom(door.geometry) for door in level.doors.all() if door.geometry.intersects(unwrap_geom(space.geometry))) ).difference(walkable_spaces_geom)) intersects = buildings_geom_prep.intersects(buffered) @@ -133,7 +133,7 @@ class LevelGeometries: for area in space.areas.all(): access_restriction = area.access_restriction_id or space.access_restriction_id - area.geometry = area.geometry.intersection(space.walkable_geom) + area.geometry = area.geometry.intersection(unwrap_geom(space.walkable_geom)) if access_restriction is not None: access_restriction_affected.setdefault(access_restriction, []).append(area.geometry) colors.setdefault(area.get_color_sorted(), {}).setdefault(access_restriction, []).append(area.geometry) @@ -142,7 +142,7 @@ class LevelGeometries: access_restriction = column.access_restriction_id if access_restriction is None: continue - column.geometry = column.geometry.intersection(space.walkable_geom) + column.geometry = column.geometry.intersection(unwrap_geom(space.walkable_geom)) buffered_column = column.geometry.buffer(0.01) if intersects: restricted_spaces_indoors.setdefault(access_restriction, []).append(buffered_column) @@ -156,14 +156,14 @@ class LevelGeometries: obstacles.setdefault( int((obstacle.height+obstacle.altitude)*1000), {} ).setdefault(obstacle.color, []).append( - obstacle.geometry.intersection(space.walkable_geom) + obstacle.geometry.intersection(unwrap_geom(space.walkable_geom)) ) for lineobstacle in space.lineobstacles.all(): if not lineobstacle.height: continue obstacles.setdefault(int(lineobstacle.height*1000), {}).setdefault(lineobstacle.color, []).append( - lineobstacle.buffered_geometry.intersection(space.walkable_geom) + lineobstacle.buffered_geometry.intersection(unwrap_geom(space.walkable_geom)) ) geoms.ramps.extend(ramp.geometry for ramp in space.ramps.all()) @@ -196,7 +196,7 @@ class LevelGeometries: new_color_obstacles = [] for obstacle in color_obstacles: if altitudearea_prep.intersects(obstacle): - new_color_obstacles.append(obstacle.intersection(altitudearea.geometry)) + new_color_obstacles.append(obstacle.intersection(unwrap_geom(altitudearea.geometry))) if new_color_obstacles: new_height_obstacles[color] = new_color_obstacles if new_height_obstacles: @@ -211,7 +211,7 @@ class LevelGeometries: for height, geoms in sorted(heightareas.items(), key=operator.itemgetter(0))) # merge access restrictions - geoms.access_restriction_affected = {access_restriction: unary_union(areas) + geoms.access_restriction_affected = {access_restriction: unary_union([unwrap_geom(geom) for geom in areas]) for access_restriction, areas in access_restriction_affected.items()} geoms.restricted_spaces_indoors = {access_restriction: unary_union(spaces) for access_restriction, spaces in restricted_spaces_indoors.items()} @@ -228,11 +228,11 @@ class LevelGeometries: intersection = altitudearea.geometry.intersection(remaining).buffer(0) if intersection.is_empty: continue - remaining = remaining.difference(altitudearea.geometry) + remaining = remaining.difference(unwrap_geom(altitudearea.geometry)) geoms.short_walls.append((altitudearea, intersection)) geoms.all_walls = geoms.walls geoms.walls = geoms.walls.difference( - unary_union(tuple(altitudearea.geometry for altitudearea in altitudeareas_above)) + unary_union(tuple(unwrap_geom(altitudearea.geometry) for altitudearea in altitudeareas_above)) ) # general level infos diff --git a/src/c3nav/mapdata/render/renderdata.py b/src/c3nav/mapdata/render/renderdata.py index 5e3f5873..f2146f70 100644 --- a/src/c3nav/mapdata/render/renderdata.py +++ b/src/c3nav/mapdata/render/renderdata.py @@ -211,7 +211,7 @@ class LevelRenderData: new_color_obstacles = [] for obstacle in color_obstacles: if new_geometry_prep.intersects(obstacle): - new_color_obstacles.append(obstacle.intersection(altitudearea.geometry)) + new_color_obstacles.append(obstacle.intersection(unwrap_geom(altitudearea.geometry))) if new_color_obstacles: new_height_obstacles[color] = new_color_obstacles if new_height_obstacles: @@ -224,12 +224,12 @@ class LevelRenderData: continue new_geoms.ramps = tuple( - ramp for ramp in (crop_to.intersection(ramp) for ramp in old_geoms.ramps) + ramp for ramp in (crop_to.intersection(unwrap_geom(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) + (area, height) for area, height in ((crop_to.intersection(unwrap_geom(area)), height) for area, height in old_geoms.heightareas) if not area.is_empty ) diff --git a/src/c3nav/mapdata/utils/geometry.py b/src/c3nav/mapdata/utils/geometry.py index 301039a7..a45209bb 100644 --- a/src/c3nav/mapdata/utils/geometry.py +++ b/src/c3nav/mapdata/utils/geometry.py @@ -131,8 +131,8 @@ def good_representative_point(geometry): if Polygon(polygon.exterior.coords).contains(c): return c x1, y1, x2, y2 = geometry.bounds - lines = (tuple(assert_multilinestring(LineString(((x1, c.y), (x2, c.y))).intersection(geometry))) + - tuple(assert_multilinestring(LineString(((c.x, y1), (c.x, y2))).intersection(geometry)))) + lines = (tuple(assert_multilinestring(LineString(((x1, c.y), (x2, c.y))).intersection(unwrap_geom(geometry)))) + + tuple(assert_multilinestring(LineString(((c.x, y1), (c.x, y2))).intersection(unwrap_geom(geometry))))) return min(lines, key=lambda line: (line.distance(c), line.length), default=geometry.representative_point()).centroid diff --git a/src/c3nav/mapdata/utils/locations.py b/src/c3nav/mapdata/utils/locations.py index 23d14dfa..0a79c0d8 100644 --- a/src/c3nav/mapdata/utils/locations.py +++ b/src/c3nav/mapdata/utils/locations.py @@ -20,6 +20,7 @@ from c3nav.mapdata.models.geometry.level import LevelGeometryMixin, Space from c3nav.mapdata.models.geometry.space import SpaceGeometryMixin from c3nav.mapdata.models.locations import LocationRedirect, LocationSlug, Position, SpecificLocation from c3nav.mapdata.utils.cache.local import LocalCacheProxy +from c3nav.mapdata.utils.geometry import unwrap_geom from c3nav.mapdata.utils.models import get_submodels proxied_cache = LocalCacheProxy(maxsize=128) @@ -137,7 +138,7 @@ def get_better_space_geometries(): result = {} for space in Space.objects.prefetch_related('columns', 'holes'): geometry = space.geometry.difference( - unary_union(tuple(obj.geometry for obj in chain(space.columns.all(), space.holes.all()))) + unary_union(tuple(unwrap_geom(obj.geometry) for obj in chain(space.columns.all(), space.holes.all()))) ) if not geometry.is_empty: result[space.pk] = geometry diff --git a/src/c3nav/routing/router.py b/src/c3nav/routing/router.py index e7e1bb34..b2f1bc3f 100644 --- a/src/c3nav/routing/router.py +++ b/src/c3nav/routing/router.py @@ -78,13 +78,13 @@ class Router: for space in level.spaces.all(): # create space geometries accessible_geom = space.geometry.difference(unary_union( - tuple(column.geometry for column in space.columns.all() if column.access_restriction_id is None) + - tuple(hole.geometry for hole in space.holes.all()) + + tuple(unwrap_geom(column.geometry) for column in space.columns.all() if column.access_restriction_id is None) + + tuple(unwrap_geom(hole.geometry) for hole in space.holes.all()) + ((buildings_geom, ) if space.outside else ()) )) obstacles_geom = unary_union( - tuple(obstacle.geometry for obstacle in space.obstacles.all()) + - tuple(lineobstacle.buffered_geometry for lineobstacle in space.lineobstacles.all()) + tuple(unwrap_geom(obstacle.geometry) for obstacle in space.obstacles.all()) + + tuple(unwrap_geom(lineobstacle.buffered_geometry) for lineobstacle in space.lineobstacles.all()) ) clear_geom = unary_union(tuple(get_rings(accessible_geom.difference(obstacles_geom)))) clear_geom_prep = prepared.prep(clear_geom)