avoid merging intersecting polygons too early
This commit is contained in:
parent
54b21b12ce
commit
651d6b79eb
5 changed files with 20 additions and 19 deletions
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue