avoid merging intersecting polygons too early

This commit is contained in:
Laura Klünder 2017-11-14 18:18:22 +01:00
parent 54b21b12ce
commit 651d6b79eb
5 changed files with 20 additions and 19 deletions

View file

@ -69,7 +69,7 @@ class RenderEngine(ABC):
pass pass
def add_geometry(self, geometry, fill: Optional[FillAttribs] = None, stroke: Optional[StrokeAttribs] = None, def add_geometry(self, geometry, fill: Optional[FillAttribs] = None, stroke: Optional[StrokeAttribs] = None,
altitude=None, height=None, shape_cache_key=None, category=None): altitude=None, height=None, shape_cache_key=None, category=None, item=None):
# draw a shapely geometry with a given style # draw a shapely geometry with a given style
# altitude is the absolute altitude of the upper bound of the element # altitude is the absolute altitude of the upper bound of the element
# height is the height of the element # height is the height of the element
@ -79,12 +79,12 @@ class RenderEngine(ABC):
if geometry.is_empty: if geometry.is_empty:
return return
self._add_geometry(geometry=geometry, fill=fill, stroke=stroke, self._add_geometry(geometry=geometry, fill=fill, stroke=stroke, altitude=altitude, height=height,
altitude=altitude, height=height, shape_cache_key=shape_cache_key, category=category) shape_cache_key=shape_cache_key, category=category, item=item)
@abstractmethod @abstractmethod
def _add_geometry(self, geometry, fill: Optional[FillAttribs], stroke: Optional[StrokeAttribs], def _add_geometry(self, geometry, fill: Optional[FillAttribs], stroke: Optional[StrokeAttribs],
altitude=None, height=None, shape_cache_key=None): altitude=None, height=None, shape_cache_key=None, item=None):
pass pass
def set_mesh_lookup_data(self, data): def set_mesh_lookup_data(self, data):

View file

@ -32,13 +32,13 @@ class Base3DEngine(RenderEngine):
self._current_group = group self._current_group = group
self.groups.setdefault(group, []) self.groups.setdefault(group, [])
def _add_geometry(self, geometry, fill: Optional[FillAttribs], stroke: Optional[StrokeAttribs], category=None, def _add_geometry(self, geometry, fill: Optional[FillAttribs], stroke: Optional[StrokeAttribs],
**kwargs): category=None, item=None, **kwargs):
if fill is not None: if fill is not None:
key = '%s_%s' % (self._current_group, category) key = '%s_%s' % (self._current_group, category)
if key not in self.vertices: if key not in self.vertices:
self.groups[self._current_group].append(key) self.groups[self._current_group].append(key)
self.vertices.setdefault(key, []).append(self._place_geometry(geometry)) self.vertices.setdefault(key, OrderedDict()).setdefault(item, []).append(self._place_geometry(geometry))
self.colors.setdefault(key, self.color_to_rgb(fill.color)) self.colors.setdefault(key, self.color_to_rgb(fill.color))
@staticmethod @staticmethod

View file

@ -8,13 +8,12 @@ from c3nav.mapdata.render.engines.base3d import Base3DEngine
class OpenSCADEngine(Base3DEngine): class OpenSCADEngine(Base3DEngine):
filetype = 'scad' filetype = 'scad'
def _create_polyhedron(self, name, vertices): def _create_polyhedron(self, vertices):
facets = np.vstack(vertices) facets = np.vstack(vertices)
vertices = tuple(set(tuple(vertex) for vertex in facets.reshape((-1, 3)))) vertices = tuple(set(tuple(vertex) for vertex in facets.reshape((-1, 3))))
lookup = {vertex: i for i, vertex in enumerate(vertices)} lookup = {vertex: i for i, vertex in enumerate(vertices)}
return (b'module ' + name.replace('-', 'minus').encode() + b'() {\n' + return (b' polyhedron(\n' +
b' polyhedron(\n' +
b' points = [\n' + b' points = [\n' +
b'\n'.join((b' [%.3f, %.3f, %.3f],' % tuple(vertex)) for vertex in vertices) + b'\n' + b'\n'.join((b' [%.3f, %.3f, %.3f],' % tuple(vertex)) for vertex in vertices) + b'\n' +
b' ],\n' + b' ],\n' +
@ -23,8 +22,7 @@ class OpenSCADEngine(Base3DEngine):
for a, b, c in facets) + b'\n' + for a, b, c in facets) + b'\n' +
b' ],\n' + b' ],\n' +
b' convexity = 10\n' + b' convexity = 10\n' +
b' );\n' b' );')
b'}\n')
def render(self) -> bytes: def render(self) -> bytes:
result = (b'c3nav_export();\n\n' + result = (b'c3nav_export();\n\n' +
@ -41,5 +39,7 @@ class OpenSCADEngine(Base3DEngine):
b'}\n') b'}\n')
result += b'\n' result += b'\n'
for group, vertices in self.vertices.items(): for group, vertices in self.vertices.items():
result += self._create_polyhedron(group, vertices) result += (b'module ' + group.replace('-', 'minus').encode() + b'() {\n' +
b'\n'.join(self._create_polyhedron(v) for v in vertices.values()) +
b'}\n')
return result return result

View file

@ -215,7 +215,7 @@ class SVGEngine(RenderEngine):
self.altitudes[new_altitude] = new_geometry self.altitudes[new_altitude] = new_geometry
def _add_geometry(self, geometry, fill: Optional[FillAttribs], stroke: Optional[StrokeAttribs], def _add_geometry(self, geometry, fill: Optional[FillAttribs], stroke: Optional[StrokeAttribs],
altitude=None, height=None, shape_cache_key=None, category=None): altitude=None, height=None, shape_cache_key=None, **kwargs):
geometry = self.buffered_bbox.intersection(geometry.geom) geometry = self.buffered_bbox.intersection(geometry.geom)
if geometry.is_empty: if geometry.is_empty:

View file

@ -107,21 +107,21 @@ class MapRenderer:
engine.add_geometry(geoms.walls_bottom.fit(scale=geoms.min_altitude-min_altitude, engine.add_geometry(geoms.walls_bottom.fit(scale=geoms.min_altitude-min_altitude,
offset=min_altitude-int(0.7*1000)), offset=min_altitude-int(0.7*1000)),
fill=FillAttribs('#aaaaaa'), category='walls') fill=FillAttribs('#aaaaaa'), category='walls')
for altitudearea in geoms.altitudeareas: for i, altitudearea in enumerate(geoms.altitudeareas):
scale = (altitudearea.altitude - min_altitude) / int(0.7 * 1000) scale = (altitudearea.altitude - min_altitude) / int(0.7 * 1000)
offset = (min_altitude - int(0.7*1000)) - (altitudearea.altitude - int(0.7*1000)) * scale offset = (min_altitude - int(0.7*1000)) - (altitudearea.altitude - int(0.7*1000)) * scale
geometry = altitudearea.geometry.difference(crop_areas) geometry = altitudearea.geometry.difference(crop_areas)
engine.add_geometry(geometry.fit(scale=scale, offset=offset).filter(top=False), engine.add_geometry(geometry.fit(scale=scale, offset=offset).filter(top=False),
fill=FillAttribs('#eeeeee'), category='ground') fill=FillAttribs('#eeeeee'), category='ground', item=i)
# render altitude areas in default ground color and add ground colors to each one afterwards # render altitude areas in default ground color and add ground colors to each one afterwards
# shadows are directly calculated and added by the engine # shadows are directly calculated and added by the engine
for altitudearea in geoms.altitudeareas: for i, altitudearea in enumerate(geoms.altitudeareas):
geometry = altitudearea.geometry.difference(crop_areas) geometry = altitudearea.geometry.difference(crop_areas)
if not_full_levels: if not_full_levels:
geometry = geometry.filter(bottom=False) geometry = geometry.filter(bottom=False)
engine.add_geometry(geometry, altitude=altitudearea.altitude, fill=FillAttribs('#eeeeee'), engine.add_geometry(geometry, altitude=altitudearea.altitude, fill=FillAttribs('#eeeeee'),
category='ground') category='ground', item=i)
i = 0 i = 0
for color, areas in altitudearea.colors.items(): for color, areas in altitudearea.colors.items():
@ -130,7 +130,8 @@ class MapRenderer:
if access_restriction in unlocked_access_restrictions) if access_restriction in unlocked_access_restrictions)
if areas: if areas:
i += 1 i += 1
engine.add_geometry(hybrid_union(areas), fill=FillAttribs(color), category='groundcolor%s' % i) engine.add_geometry(hybrid_union(areas), fill=FillAttribs(color),
category='groundcolor%s' % i, item=i)
# add walls, stroke_px makes sure that all walls are at least 1px thick on all zoom levels, # add walls, stroke_px makes sure that all walls are at least 1px thick on all zoom levels,
walls = None walls = None