introduce intermediate level setting
This commit is contained in:
parent
a4a7f02d0b
commit
9446c34e8a
8 changed files with 39 additions and 15 deletions
|
@ -72,11 +72,16 @@ class LevelsForLevel:
|
|||
# noinspection PyPep8Naming
|
||||
levels_under = ()
|
||||
levels_on_top = ()
|
||||
lower_level = level.lower(Level).first()
|
||||
primary_levels = (level,) + ((lower_level,) if lower_level else ())
|
||||
lower_levels = []
|
||||
for sublevel in level.lower(Level):
|
||||
lower_levels.append(sublevel)
|
||||
if not sublevel.intermediate:
|
||||
break
|
||||
primary_levels = chain((level,), lower_levels)
|
||||
secondary_levels = Level.objects.filter(on_top_of__in=primary_levels).values_list('pk', 'on_top_of')
|
||||
if lower_level:
|
||||
levels_under = tuple(pk for pk, on_top_of in secondary_levels if on_top_of == lower_level.pk)
|
||||
lower_level_pks = set(l.pk for l in lower_levels)
|
||||
if lower_levels:
|
||||
levels_under = tuple(pk for pk, on_top_of in secondary_levels if on_top_of in lower_level_pks)
|
||||
if True:
|
||||
levels_on_top = tuple(pk for pk, on_top_of in secondary_levels if on_top_of == level.pk)
|
||||
|
||||
|
|
|
@ -401,7 +401,8 @@ def create_editor_form(editor_model):
|
|||
'slug', 'name', 'title', 'title_plural', 'help_text', 'position_secret', 'icon', 'join_edges',
|
||||
'up_separate', 'bssid', 'main_point', 'external_url', 'hub_import_type', 'walk', 'ordering',
|
||||
'category', 'width', 'groups', 'height', 'color', 'in_legend', 'priority', 'hierarchy', 'icon_name',
|
||||
'base_altitude', 'waytype', 'access_restriction', 'default_height', 'door_height', 'outside', 'can_search',
|
||||
'base_altitude', 'intermediate',
|
||||
'waytype', 'access_restriction', 'default_height', 'door_height', 'outside', 'can_search',
|
||||
'can_describe', 'geometry', 'single', 'altitude', 'short_label', 'origin_space', 'target_space', 'data',
|
||||
'comment', 'slow_down_factor', 'groundaltitude', 'node_number', 'wifi_bssid', 'bluetooth_address', "group",
|
||||
'ibeacon_uuid', 'ibeacon_major', 'ibeacon_minor', 'uwb_address', 'extra_seconds', 'speed', 'can_report_missing',
|
||||
|
|
|
@ -25,6 +25,7 @@ class Level(SpecificLocation, models.Model):
|
|||
validators=[MinValueValidator(Decimal('0'))])
|
||||
on_top_of = models.ForeignKey('mapdata.Level', null=True, on_delete=models.CASCADE,
|
||||
related_name='levels_on_top', verbose_name=_('on top of'))
|
||||
intermediate = models.BooleanField(_("intermediate level"), default=False)
|
||||
short_label = models.SlugField(max_length=20, verbose_name=_('short label'), unique=True)
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -64,7 +64,7 @@ class RenderEngine(ABC):
|
|||
def add_group(self, group):
|
||||
pass
|
||||
|
||||
def darken(self, area):
|
||||
def darken(self, area, much=False):
|
||||
pass
|
||||
|
||||
def add_geometry(self, geometry, fill: Optional[FillAttribs] = None, stroke: Optional[StrokeAttribs] = None,
|
||||
|
|
|
@ -232,9 +232,9 @@ class SVGEngine(RenderEngine):
|
|||
else:
|
||||
self.altitudes[new_altitude] = new_geometry
|
||||
|
||||
def darken(self, area):
|
||||
def darken(self, area, much=False):
|
||||
if area:
|
||||
self.add_geometry(geometry=area, fill=FillAttribs('#000000', 0.1), category='darken')
|
||||
self.add_geometry(geometry=area, fill=FillAttribs('#000000', 0.5 if much else 0.1), category='darken')
|
||||
|
||||
def _add_geometry(self, geometry, fill: Optional[FillAttribs], stroke: Optional[StrokeAttribs],
|
||||
altitude=None, height=None, shadow_color=None, shape_cache_key=None, **kwargs):
|
||||
|
|
|
@ -6,11 +6,11 @@ from functools import reduce
|
|||
from itertools import chain
|
||||
|
||||
import numpy as np
|
||||
from shapely import prepared
|
||||
from shapely import prepared, box
|
||||
from shapely.geometry import GeometryCollection, Polygon, MultiPolygon
|
||||
from shapely.ops import unary_union
|
||||
|
||||
from c3nav.mapdata.models import Space, Level, AltitudeArea
|
||||
from c3nav.mapdata.models import Space, Level, AltitudeArea, Source
|
||||
from c3nav.mapdata.render.geometry.altitudearea import AltitudeAreaGeometries
|
||||
from c3nav.mapdata.render.geometry.hybrid import HybridGeometry
|
||||
from c3nav.mapdata.render.geometry.mesh import Mesh
|
||||
|
@ -294,6 +294,13 @@ class SingleLevelGeometries(BaseLevelGeometries):
|
|||
walls_geom = buildings_geom.difference(unary_union((spaces_geom, doors_geom)))
|
||||
if level.on_top_of_id is None:
|
||||
holes_geom = unary_union([s.holes_geom for s in spaces])
|
||||
|
||||
if level.intermediate:
|
||||
holes_geom = unary_union([
|
||||
holes_geom,
|
||||
box(*chain(*Source.max_bounds())).difference(buildings_geom).difference(spaces_geom)
|
||||
])
|
||||
|
||||
else:
|
||||
holes_geom = None
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ class LevelRenderData:
|
|||
lowest_important_level: int
|
||||
levels: list[CompositeLevelGeometries] = field(default_factory=list)
|
||||
darken_area: MultiPolygon | None = None
|
||||
darken_much: bool = False
|
||||
|
||||
@staticmethod
|
||||
def rebuild(update_cache_key):
|
||||
|
@ -125,10 +126,11 @@ class LevelRenderData:
|
|||
map_history = MapHistory.open_level(render_level.pk, 'base')
|
||||
|
||||
# collect potentially relevant levels for rendering this level
|
||||
# these are all levels that are on_top_of this level or below this level
|
||||
# these are all levels that are on_top_of this level or below this level (inless intermediate)
|
||||
relevant_levels = tuple(
|
||||
sublevel for sublevel in levels
|
||||
if sublevel.on_top_of_id == render_level.pk or sublevel.base_altitude <= render_level.base_altitude
|
||||
if (sublevel.pk == render_level.pk or sublevel.on_top_of_id == render_level.pk or
|
||||
(sublevel.base_altitude <= render_level.base_altitude and not sublevel.intermediate))
|
||||
)
|
||||
|
||||
"""
|
||||
|
@ -168,7 +170,7 @@ class LevelRenderData:
|
|||
upper_bounds[geoms.pk] = last_lower_bound
|
||||
last_lower_bound = geoms.lower_bound
|
||||
|
||||
# set crop area if we area on the second primary layer from top or below
|
||||
# set crop area if we are on the second primary layer from top or below
|
||||
level_crop_to[level.pk] = Cropper(crop_to if primary_level_count > 1 else None)
|
||||
|
||||
if geoms.holes is not None: # there area holes on this area
|
||||
|
@ -180,6 +182,10 @@ class LevelRenderData:
|
|||
if crop_to.is_empty:
|
||||
break
|
||||
|
||||
if render_level.intermediate:
|
||||
# todo: would be nice to still have the staircases leading to this level i guess?
|
||||
lowest_important_level = render_level
|
||||
|
||||
render_data = LevelRenderData(
|
||||
base_altitude=render_level.base_altitude,
|
||||
lowest_important_level=lowest_important_level.pk,
|
||||
|
@ -201,6 +207,8 @@ class LevelRenderData:
|
|||
|
||||
if single_geoms.holes and render_data.darken_area is None and lowest_important_level_passed:
|
||||
render_data.darken_area = single_geoms.holes
|
||||
if render_level.intermediate:
|
||||
render_data.darken_much = True
|
||||
|
||||
if crop_to.geometry is not None:
|
||||
map_history.composite(MapHistory.open_level(level.pk, 'base'), crop_to.geometry)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
from itertools import chain
|
||||
|
||||
from django.utils.functional import cached_property
|
||||
from shapely import prepared
|
||||
from shapely.geometry import box
|
||||
|
||||
from c3nav.mapdata.models import Level
|
||||
from c3nav.mapdata.models import Level, Source
|
||||
from c3nav.mapdata.render.engines.base import FillAttribs, StrokeAttribs
|
||||
from c3nav.mapdata.render.geometry import hybrid_union
|
||||
from c3nav.mapdata.render.renderdata import LevelRenderData
|
||||
|
@ -61,7 +63,7 @@ class MapRenderer:
|
|||
engine.add_group('level_%s' % geoms.short_label)
|
||||
|
||||
if geoms.pk == level_render_data.lowest_important_level:
|
||||
engine.darken(level_render_data.darken_area)
|
||||
engine.darken(level_render_data.darken_area, much=level_render_data.darken_much)
|
||||
|
||||
if not bbox.intersects(geoms.affected_area):
|
||||
continue
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue