_create_polyhedron()
This commit is contained in:
parent
64de7f7c58
commit
799913e1a3
1 changed files with 62 additions and 6 deletions
|
@ -1,7 +1,7 @@
|
||||||
import operator
|
import operator
|
||||||
import pickle
|
import pickle
|
||||||
import threading
|
import threading
|
||||||
from collections import namedtuple
|
from collections import Counter, deque, namedtuple
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ from shapely.ops import unary_union
|
||||||
|
|
||||||
from c3nav.mapdata.cache import MapHistory
|
from c3nav.mapdata.cache import MapHistory
|
||||||
from c3nav.mapdata.models import Level, MapUpdate
|
from c3nav.mapdata.models import Level, MapUpdate
|
||||||
from c3nav.mapdata.utils.geometry import get_rings
|
from c3nav.mapdata.utils.geometry import assert_multipolygon, get_rings
|
||||||
from c3nav.mapdata.utils.mesh import triangulate_rings
|
from c3nav.mapdata.utils.mesh import triangulate_rings
|
||||||
from c3nav.mapdata.utils.mpl import shapely_to_mpl
|
from c3nav.mapdata.utils.mpl import shapely_to_mpl
|
||||||
|
|
||||||
|
@ -33,7 +33,11 @@ class HybridGeometry(namedtuple('HybridGeometry', ('geom', 'faces'))):
|
||||||
def create(cls, geom, face_centers):
|
def create(cls, geom, face_centers):
|
||||||
if isinstance(geom, (LineString, MultiLineString)):
|
if isinstance(geom, (LineString, MultiLineString)):
|
||||||
return HybridGeometry(geom, set())
|
return HybridGeometry(geom, set())
|
||||||
return HybridGeometry(geom, set(np.argwhere(shapely_to_mpl(geom).contains_points(face_centers)).flatten()))
|
faces = tuple(
|
||||||
|
set(np.argwhere(shapely_to_mpl(subgeom).contains_points(face_centers)).flatten())
|
||||||
|
for subgeom in assert_multipolygon(geom)
|
||||||
|
)
|
||||||
|
return HybridGeometry(geom, tuple(f for f in faces if f))
|
||||||
|
|
||||||
def union(self, geom):
|
def union(self, geom):
|
||||||
return HybridGeometry(self.geom.union(geom.geom), self.faces | geom.faces)
|
return HybridGeometry(self.geom.union(geom.geom), self.faces | geom.faces)
|
||||||
|
@ -351,7 +355,7 @@ class LevelGeometries:
|
||||||
vertex_value_mask = np.full(self.vertices.shape[:1], fill_value=False, dtype=np.bool)
|
vertex_value_mask = np.full(self.vertices.shape[:1], fill_value=False, dtype=np.bool)
|
||||||
|
|
||||||
for area, value in area_values:
|
for area, value in area_values:
|
||||||
i_vertices = np.unique(self.faces[np.array(tuple(area.faces))].flatten())
|
i_vertices = np.unique(self.faces[np.array(tuple(chain(*area.faces)))].flatten())
|
||||||
vertex_values[i_vertices] = value
|
vertex_values[i_vertices] = value
|
||||||
vertex_value_mask[i_vertices] = True
|
vertex_value_mask[i_vertices] = True
|
||||||
|
|
||||||
|
@ -364,6 +368,54 @@ class LevelGeometries:
|
||||||
|
|
||||||
return vertex_values
|
return vertex_values
|
||||||
|
|
||||||
|
def _create_polyhedron(self, geometry, bottom=None, top=None):
|
||||||
|
if geometry.is_empty:
|
||||||
|
return
|
||||||
|
|
||||||
|
# collect rings/boundaries
|
||||||
|
boundaries = deque()
|
||||||
|
for subfaces in geometry.faces:
|
||||||
|
subfaces = self.faces[np.array(tuple(subfaces))]
|
||||||
|
segments = np.hstack((subfaces[:, (0, 1)], subfaces[:, (1, 2)], subfaces[:, (2, 0)])).reshape((-1, 2))
|
||||||
|
edges = set(edge for edge, num in Counter(tuple(a) for a in np.sort(segments, axis=1)).items() if num == 1)
|
||||||
|
edges = {a: b for a, b in segments if (a, b) in edges or (b, a) in edges}
|
||||||
|
while edges:
|
||||||
|
new_ring = deque()
|
||||||
|
start, last = next(iter(edges.items()))
|
||||||
|
edges.pop(start)
|
||||||
|
new_ring.append(start)
|
||||||
|
while start != last:
|
||||||
|
new_ring.append(last)
|
||||||
|
last = edges.pop(last)
|
||||||
|
new_ring = np.array(new_ring, dtype=np.int64)
|
||||||
|
boundaries.append(tuple(zip(chain((new_ring[-1], ), new_ring), new_ring)))
|
||||||
|
boundaries = np.vstack(boundaries)
|
||||||
|
|
||||||
|
faces = deque()
|
||||||
|
geom_faces = self.faces[np.array(tuple(chain(*geometry.faces)))]
|
||||||
|
|
||||||
|
if not isinstance(top, np.ndarray):
|
||||||
|
top = np.full(self.vertices.shape[0], fill_value=top)
|
||||||
|
|
||||||
|
if not isinstance(bottom, np.ndarray):
|
||||||
|
bottom = np.full(self.vertices.shape[0], fill_value=bottom)
|
||||||
|
|
||||||
|
# upper faces
|
||||||
|
faces.append(np.dstack((self.vertices[geom_faces], top[geom_faces])))
|
||||||
|
|
||||||
|
# side faces (upper)
|
||||||
|
faces.append(np.dstack((self.vertices[boundaries[:, (1, 0, 0)]],
|
||||||
|
np.hstack((top[boundaries[:, (1, 0)]], bottom[boundaries[:, (0,)]])))))
|
||||||
|
|
||||||
|
# side faces (lower)
|
||||||
|
faces.append(np.dstack((self.vertices[boundaries[:, (0, 1, 1)]],
|
||||||
|
np.hstack((bottom[boundaries[:, (0, 1)]], top[boundaries[:, (1,)]])))))
|
||||||
|
|
||||||
|
# lower faces
|
||||||
|
faces.append(np.dstack((self.vertices[np.flip(geom_faces, axis=1)], bottom[geom_faces])))
|
||||||
|
|
||||||
|
return np.vstack(faces)
|
||||||
|
|
||||||
def build_mesh(self):
|
def build_mesh(self):
|
||||||
rings = tuple(chain(*(get_rings(geom) for geom in self.get_geometries())))
|
rings = tuple(chain(*(get_rings(geom) for geom in self.get_geometries())))
|
||||||
self.vertices, self.faces = triangulate_rings(rings)
|
self.vertices, self.faces = triangulate_rings(rings)
|
||||||
|
@ -371,9 +423,13 @@ class LevelGeometries:
|
||||||
|
|
||||||
# calculate altitudes
|
# calculate altitudes
|
||||||
self.vertex_altitudes = self._build_vertex_values((area.geometry, int(area.altitude*100))
|
self.vertex_altitudes = self._build_vertex_values((area.geometry, int(area.altitude*100))
|
||||||
for area in self.altitudeareas)
|
for area in reversed(self.altitudeareas))/100
|
||||||
self.vertex_heights = self._build_vertex_values((area, int(height*100))
|
self.vertex_heights = self._build_vertex_values((area, int(height*100))
|
||||||
for area, height in self.heightareas)
|
for area, height in self.heightareas)/100
|
||||||
|
self.vertex_wall_heights = self.vertex_altitudes+self.vertex_heights
|
||||||
|
|
||||||
|
# create polyhedrons
|
||||||
|
self._create_polyhedron(self.walls, bottom=self.vertex_altitudes, top=self.vertex_wall_heights)
|
||||||
|
|
||||||
# unset heightareas, they are no loinger needed
|
# unset heightareas, they are no loinger needed
|
||||||
self.heightareas = None
|
self.heightareas = None
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue