From da25951555d99eb161ba623684d6e7b42f858b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Sat, 18 Nov 2017 13:10:07 +0100 Subject: [PATCH] ramp rendering --- src/c3nav/mapdata/models/geometry/level.py | 18 +++++++ src/c3nav/mapdata/render/data.py | 60 +++++++++++++++------- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/src/c3nav/mapdata/models/geometry/level.py b/src/c3nav/mapdata/models/geometry/level.py index 840aea47..b405626c 100644 --- a/src/c3nav/mapdata/models/geometry/level.py +++ b/src/c3nav/mapdata/models/geometry/level.py @@ -144,6 +144,24 @@ class AltitudeArea(LevelGeometryMixin, models.Model): default_related_name = 'altitudeareas' ordering = ('altitude', ) + def get_altitudes(self, points): + points = np.asanyarray(points).reshape((-1, 2)) + if self.altitude2 is None: + return np.full((points.shape[0], ), fill_value=float(self.altitude)) + + a_to_p = points - np.array(self.point1) + a_to_b = np.array(self.point2) - np.array(self.point1) + + atb2 = (a_to_b**2).sum() + + atp_dot_atb = a_to_p[:, 0] * a_to_b[0] + a_to_p[:, 1] * a_to_b[1] + + distances = atp_dot_atb / atb2 + + distances = distances.clip(0, 1) + + return self.altitude + distances*(self.altitude2-self.altitude) + @classmethod def recalculate(cls): # collect location areas diff --git a/src/c3nav/mapdata/render/data.py b/src/c3nav/mapdata/render/data.py index ef7eae41..25973077 100644 --- a/src/c3nav/mapdata/render/data.py +++ b/src/c3nav/mapdata/render/data.py @@ -15,7 +15,7 @@ from shapely.geometry import GeometryCollection, LineString, MultiLineString from shapely.ops import unary_union from c3nav.mapdata.cache import MapHistory -from c3nav.mapdata.models import Level, MapUpdate +from c3nav.mapdata.models import AltitudeArea, Level, MapUpdate from c3nav.mapdata.utils.geometry import assert_multipolygon, get_rings from c3nav.mapdata.utils.mesh import triangulate_rings from c3nav.mapdata.utils.mpl import shapely_to_mpl @@ -106,12 +106,22 @@ class AltitudeAreaGeometries: if altitudearea is not None: self.geometry = altitudearea.geometry self.altitude = int(altitudearea.altitude * 1000) + self.altitude2 = None if altitudearea.altitude2 is None else int(altitudearea.altitude2 * 1000) + self.point1 = altitudearea.point1 + self.point2 = altitudearea.point2 else: self.geometry = None self.altitude = None + self.altitude2 = None + self.point1 = None + self.point2 = None self.colors = colors self.obstacles = obstacles + def get_altitudes(self, points): + # noinspection PyCallByClass,PyTypeChecker + return AltitudeArea.get_altitudes(self, points/1000).astype(np.int32) + def get_geometries(self): return chain((self.geometry,), chain(*(areas.values() for areas in self.colors.values())), @@ -130,21 +140,23 @@ class AltitudeAreaGeometries: for area in areas.values(): area.remove_faces(faces) - def create_polyhedrons(self, create_polyhedron, crops): - altitude = self.altitude + def create_polyhedrons(self, create_polyhedron, altitudes, crops): + if self.altitude2 is None: + altitudes = self.altitude + self.geometry.build_polyhedron(create_polyhedron, - lower=altitude - int(0.7 * 1000), - upper=altitude, + lower=altitudes - int(0.7 * 1000), + upper=altitudes, crops=crops) for geometry in chain(*(areas.values() for areas in self.colors.values())): geometry.build_polyhedron(create_polyhedron, - lower=altitude, - upper=altitude + int(0.001 * 1000), + lower=altitudes, + upper=altitudes + int(0.001 * 1000), crops=crops) for height, geometry in self.obstacles.items(): geometry.build_polyhedron(create_polyhedron, - lower=altitude, - upper=altitude + height, + lower=altitudes, + upper=altitudes + height, crops=crops) @@ -257,6 +269,9 @@ class LevelRenderData: 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(): @@ -572,13 +587,16 @@ class LevelGeometries: self.restricted_spaces_outdoors = {key: HybridGeometry.create(geom, face_centers) for key, geom in self.restricted_spaces_outdoors.items()} - def _build_vertex_values(self, area_values): + def _get_altitudearea_vertex_values(self, area, i_vertices): + return area.get_altitudes(self.vertices[i_vertices]) + + def _build_vertex_values(self, items, area_func, value_func): vertex_values = np.empty(self.vertices.shape[:1], dtype=np.int32) vertex_value_mask = np.full(self.vertices.shape[:1], fill_value=False, dtype=np.bool) - for area, value in area_values: - i_vertices = np.unique(self.faces[np.array(tuple(chain(*area.faces)))].flatten()) - vertex_values[i_vertices] = value + for item in items: + i_vertices = np.unique(self.faces[np.array(tuple(chain(*area_func(item).faces)))].flatten()) + vertex_values[i_vertices] = value_func(item, i_vertices) vertex_value_mask[i_vertices] = True if not np.all(vertex_value_mask): @@ -671,10 +689,12 @@ class LevelGeometries: self.create_hybrid_geometries(face_centers=self.vertices[self.faces].sum(axis=1) / 3000) # calculate altitudes - vertex_altitudes = self._build_vertex_values((area.geometry, area.altitude) - for area in reversed(self.altitudeareas)) - vertex_heights = self._build_vertex_values((area, height) - for area, height in self.heightareas) + vertex_altitudes = self._build_vertex_values(reversed(self.altitudeareas), + area_func=operator.attrgetter('geometry'), + value_func=self._get_altitudearea_vertex_values) + vertex_heights = self._build_vertex_values(self.heightareas, + area_func=operator.itemgetter(0), + value_func=lambda a, i: a[1]) vertex_wall_heights = vertex_altitudes + vertex_heights # remove altitude area faces inside walls @@ -723,7 +743,11 @@ class LevelGeometries: self.doors_extended = None for area in self.altitudeareas: - area.create_polyhedrons(self._create_polyhedron, crops=crops) + area.create_polyhedrons(self._create_polyhedron, + self._build_vertex_values([area], + area_func=operator.attrgetter('geometry'), + value_func=self._get_altitudearea_vertex_values), + crops=crops) for key, geometry in self.restricted_spaces_indoors.items(): geometry.build_polyhedron(self._create_polyhedron,