diff --git a/src/c3nav/mapdata/models/level.py b/src/c3nav/mapdata/models/level.py index 39f91943..9e3e26a0 100644 --- a/src/c3nav/mapdata/models/level.py +++ b/src/c3nav/mapdata/models/level.py @@ -180,6 +180,10 @@ class LevelGeometries(): def accessible(self): return self.areas.difference(self.holes).difference(self.obstacles) + @cached_property + def accessible_without_oneways(self): + return self.accessible.difference(self.oneways_buffered) + @cached_property def buildings_with_holes(self): return self.buildings.difference(self.holes) @@ -241,6 +245,18 @@ class LevelGeometries(): def escalatorslopes(self): return cascaded_union([s.geometry for s in self.query('escalatorslopes')]).intersection(self.accessible) + @cached_property + def oneways_raw(self): + return cascaded_union([oneway.geometry for oneway in self.query('oneways')]) + + @cached_property + def oneways(self): + return self.oneways_raw.intersection(self.accessible) + + @cached_property + def oneways_buffered(self): + return self.oneways_raw.buffer(0.05, join_style=JOIN_STYLE.mitre, cap_style=CAP_STYLE.square) + @cached_property def stair_areas(self): left = [] diff --git a/src/c3nav/routing/level.py b/src/c3nav/routing/level.py index 6402063f..da8ee80f 100644 --- a/src/c3nav/routing/level.py +++ b/src/c3nav/routing/level.py @@ -7,7 +7,7 @@ from matplotlib.path import Path from PIL import Image, ImageDraw from scipy.sparse.csgraph._shortest_path import shortest_path from scipy.sparse.csgraph._tools import csgraph_from_dense -from shapely.geometry import JOIN_STYLE +from shapely.geometry import CAP_STYLE, JOIN_STYLE, LineString from c3nav.mapdata.utils.geometry import assert_multilinestring, assert_multipolygon from c3nav.routing.point import GraphPoint @@ -61,6 +61,7 @@ class GraphLevel(): room.build_points() self.create_doors() + self.create_oneways() self.create_levelconnectors() self.create_elevatorlevels() @@ -103,8 +104,15 @@ class GraphLevel(): print('Escalator %s has no slope line!' % escalator.name) continue + def collect_oneways(self): + self._built_oneways = () + for oneway_line in assert_multilinestring(self.level.geometries.oneways): + coords = tuple(oneway_line.coords) + self._built_oneways += tuple((Path(part), coord_angle(*part)) + for part in zip(coords[:-1], coords[1:])) + def collect_rooms(self): - accessibles = self.level.geometries.accessible + accessibles = self.level.geometries.accessible_without_oneways accessibles = assert_multipolygon(accessibles) for geometry in accessibles: room = GraphRoom(self) @@ -144,6 +152,52 @@ class GraphLevel(): center_point.connect_to(point) point.connect_to(center_point) + def create_oneways(self): + oneways = self.level.geometries.oneways + oneways = assert_multilinestring(oneways) + + segments = () + for oneway in oneways: + coords = tuple(oneway.coords) + segments += tuple((Path(part), coord_angle(*part)) + for part in zip(coords[:-1], coords[1:])) + + for oneway, oneway_angle in segments: + line_string = LineString(tuple(oneway.vertices)) + polygon = line_string.buffer(0.10, join_style=JOIN_STYLE.mitre, cap_style=CAP_STYLE.flat) + center = polygon.centroid + + num_points = 0 + connected_rooms = set() + points = [] + for room in self.rooms: + if not polygon.intersects(room._built_geometry): + continue + + for subpolygon in assert_multipolygon(polygon.intersection(room._built_geometry)): + connected_rooms.add(room) + nearest_point = get_nearest_point(room.clear_geometry, subpolygon.centroid) + point, = room.add_point(nearest_point.coords[0]) + points.append(point) + + if len(points) < 2: + print('oneway with <2 points (%d) detected at (%.2f, %.2f)' % (num_points, center.x, center.y)) + continue + + center_point = GraphPoint(center.x, center.y, None) + self._built_room_transfer_points.append(center_point) + for room in connected_rooms: + room._built_points.append(center_point) + + for point in points: + angle = coord_angle(point.xy, center_point.xy) + angle_diff = ((oneway_angle - angle + 180) % 360) - 180 + direction_up = (angle_diff > 0) + if direction_up: + point.connect_to(center_point) + else: + center_point.connect_to(point) + def create_levelconnectors(self): for levelconnector in self.level.levelconnectors.all(): polygon = levelconnector.geometry diff --git a/src/c3nav/site/views.py b/src/c3nav/site/views.py index 40456766..3434200a 100644 --- a/src/c3nav/site/views.py +++ b/src/c3nav/site/views.py @@ -42,7 +42,7 @@ def main(request, origin=None, destination=None): route = None if origin and destination: graph = Graph.load() - route = graph.get_route(origin, destination, ('', 'steps_down', 'steps_up', 'elevator_down', 'elevator_up')) + route = graph.get_route(origin, destination, ('', 'escalator_down', 'escalator_up')) print(route) route = route.split() print(route)