some renderdata code modernization
This commit is contained in:
parent
551cb1e086
commit
99c2c4e0f0
1 changed files with 58 additions and 40 deletions
|
@ -64,28 +64,36 @@ class LevelRenderData:
|
||||||
|
|
||||||
package = CachePackage(bounds=tuple(chain(*Source.max_bounds())))
|
package = CachePackage(bounds=tuple(chain(*Source.max_bounds())))
|
||||||
|
|
||||||
# first pass in reverse to collect some data that we need later
|
# todo: we should check that levels on top come before their levels as they should
|
||||||
|
|
||||||
|
"""
|
||||||
|
first pass in reverse to collect some data that we need later
|
||||||
|
"""
|
||||||
|
# level geometry for every single level
|
||||||
single_level_geoms: dict[int, LevelGeometries] = {}
|
single_level_geoms: dict[int, LevelGeometries] = {}
|
||||||
|
# interpolator are used to create the 3d mesh
|
||||||
interpolators = {}
|
interpolators = {}
|
||||||
last_interpolator: NearestNDInterpolator | None = None
|
last_interpolator: NearestNDInterpolator | None = None
|
||||||
|
# altitudeareas of levels on top are are collected on the way down to supply to the levelgeometries builder
|
||||||
altitudeareas_above = [] # todo: typing
|
altitudeareas_above = [] # todo: typing
|
||||||
for level in reversed(levels):
|
for render_level in reversed(levels):
|
||||||
# build level geometry for every single level
|
# build level geometry for every single level
|
||||||
single_level_geoms[level.pk] = LevelGeometries.build_for_level(level, altitudeareas_above)
|
single_level_geoms[render_level.pk] = LevelGeometries.build_for_level(render_level, altitudeareas_above)
|
||||||
|
|
||||||
# ignore intermediate levels in this pass
|
# ignore intermediate levels in this pass
|
||||||
if level.on_top_of_id is not None:
|
if render_level.on_top_of_id is not None:
|
||||||
altitudeareas_above.extend(single_level_geoms[level.pk].altitudeareas)
|
# todo: shouldn't this be cleared or something?
|
||||||
|
altitudeareas_above.extend(single_level_geoms[render_level.pk].altitudeareas)
|
||||||
altitudeareas_above.sort(key=operator.attrgetter('altitude'))
|
altitudeareas_above.sort(key=operator.attrgetter('altitude'))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# create interpolator to create the pieces that fit multiple layers together
|
# create interpolator to create the pieces that fit multiple 3d layers together
|
||||||
if last_interpolator is not None:
|
if last_interpolator is not None:
|
||||||
interpolators[level.pk] = last_interpolator
|
interpolators[render_level.pk] = last_interpolator
|
||||||
|
|
||||||
coords = deque()
|
coords = deque()
|
||||||
values = deque()
|
values = deque()
|
||||||
for area in single_level_geoms[level.pk].altitudeareas:
|
for area in single_level_geoms[render_level.pk].altitudeareas:
|
||||||
new_coords = np.vstack(tuple(np.array(ring.coords) for ring in get_rings(area.geometry)))
|
new_coords = np.vstack(tuple(np.array(ring.coords) for ring in get_rings(area.geometry)))
|
||||||
coords.append(new_coords)
|
coords.append(new_coords)
|
||||||
values.append(np.full((new_coords.shape[0], 1), fill_value=area.altitude))
|
values.append(np.full((new_coords.shape[0], 1), fill_value=area.altitude))
|
||||||
|
@ -93,43 +101,53 @@ class LevelRenderData:
|
||||||
if coords:
|
if coords:
|
||||||
last_interpolator = NearestNDInterpolator(np.vstack(coords), np.vstack(values))
|
last_interpolator = NearestNDInterpolator(np.vstack(coords), np.vstack(values))
|
||||||
else:
|
else:
|
||||||
last_interpolator = NearestNDInterpolator(np.array([[0, 0]]), np.array([float(level.base_altitude)]))
|
last_interpolator = NearestNDInterpolator(np.array([[0, 0]]), np.array([float(render_level.base_altitude)]))
|
||||||
|
|
||||||
for i, level in enumerate(levels):
|
"""
|
||||||
if level.on_top_of_id is not None:
|
second pass, forward to create the LevelRenderData for each level
|
||||||
|
"""
|
||||||
|
for render_level in levels:
|
||||||
|
# we don't create render data for on_top_of levels
|
||||||
|
if render_level.on_top_of_id is not None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
map_history = MapHistory.open_level(level.pk, 'base')
|
map_history = MapHistory.open_level(render_level.pk, 'base')
|
||||||
|
|
||||||
sublevels = tuple(sublevel for sublevel in levels
|
# collect potentially relevant levels for rendering this level
|
||||||
if sublevel.on_top_of_id == level.pk or sublevel.base_altitude <= level.base_altitude)
|
# these are all levels that are on_top_of this level or below this level
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
level_crop_to = {}
|
"""
|
||||||
|
choose a crop area for each level. non-intermediate levels (not on_top_of) below the one that we are
|
||||||
# choose a crop area for each level. non-intermediate levels (not on_top_of) below the one that we are
|
currently rendering will be cropped to only render content that is visible through holes indoors in the
|
||||||
# currently rendering will be cropped to only render content that is visible through holes indoors in the
|
levels above them.
|
||||||
# levels above them.
|
"""
|
||||||
|
# area to crop each level to, by id
|
||||||
|
level_crop_to: dict[int, Cropper] = {}
|
||||||
|
# current remaining area that we're cropping to – None means no cropping
|
||||||
crop_to = None
|
crop_to = None
|
||||||
primary_level_count = 0
|
primary_level_count = 0
|
||||||
main_level_passed = 0
|
main_level_passed = 0
|
||||||
lowest_important_level = None
|
lowest_important_level = None
|
||||||
last_lower_bound = None
|
last_lower_bound = None
|
||||||
for sublevel in reversed(sublevels):
|
for level in reversed(relevant_levels): # reversed means we are going down
|
||||||
geoms = single_level_geoms[sublevel.pk]
|
geoms = single_level_geoms[level.pk]
|
||||||
|
|
||||||
if geoms.holes is not None:
|
if geoms.holes is not None:
|
||||||
primary_level_count += 1
|
primary_level_count += 1
|
||||||
|
|
||||||
# get lowest intermediate level directly below main level
|
# get lowest intermediate level directly below main level
|
||||||
|
|
||||||
if not main_level_passed:
|
if not main_level_passed:
|
||||||
if geoms.pk == level.pk:
|
if geoms.pk == render_level.pk:
|
||||||
main_level_passed = 1
|
main_level_passed = 1
|
||||||
else:
|
else:
|
||||||
if not sublevel.on_top_of_id:
|
if not level.on_top_of_id:
|
||||||
main_level_passed += 1
|
main_level_passed += 1
|
||||||
if main_level_passed < 2:
|
if main_level_passed < 2:
|
||||||
lowest_important_level = sublevel
|
lowest_important_level = level
|
||||||
|
|
||||||
# make upper bounds
|
# make upper bounds
|
||||||
if geoms.on_top_of_id is None:
|
if geoms.on_top_of_id is None:
|
||||||
|
@ -140,9 +158,9 @@ class LevelRenderData:
|
||||||
last_lower_bound = geoms.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 area on the second primary layer from top or below
|
||||||
level_crop_to[sublevel.pk] = Cropper(crop_to if primary_level_count > 1 else None)
|
level_crop_to[level.pk] = Cropper(crop_to if primary_level_count > 1 else None)
|
||||||
|
|
||||||
if geoms.holes is not None:
|
if geoms.holes is not None: # there area holes on this area
|
||||||
if crop_to is None:
|
if crop_to is None:
|
||||||
crop_to = geoms.holes
|
crop_to = geoms.holes
|
||||||
else:
|
else:
|
||||||
|
@ -152,31 +170,31 @@ class LevelRenderData:
|
||||||
break
|
break
|
||||||
|
|
||||||
render_data = LevelRenderData(
|
render_data = LevelRenderData(
|
||||||
base_altitude=level.base_altitude,
|
base_altitude=render_level.base_altitude,
|
||||||
lowest_important_level=lowest_important_level.pk,
|
lowest_important_level=lowest_important_level.pk,
|
||||||
)
|
)
|
||||||
access_restriction_affected = {}
|
access_restriction_affected = {}
|
||||||
|
|
||||||
# go through sublevels, get their level geometries and crop them
|
# go through sublevels, get their level geometries and crop them
|
||||||
lowest_important_level_passed = False
|
lowest_important_level_passed = False
|
||||||
for sublevel in sublevels:
|
for level in relevant_levels:
|
||||||
try:
|
try:
|
||||||
crop_to = level_crop_to[sublevel.pk]
|
crop_to = level_crop_to[level.pk]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
break
|
break
|
||||||
|
|
||||||
old_geoms = single_level_geoms[sublevel.pk]
|
old_geoms = single_level_geoms[level.pk]
|
||||||
|
|
||||||
if render_data.lowest_important_level == sublevel.pk:
|
if render_data.lowest_important_level == level.pk:
|
||||||
lowest_important_level_passed = True
|
lowest_important_level_passed = True
|
||||||
|
|
||||||
if old_geoms.holes and render_data.darken_area is None and lowest_important_level_passed:
|
if old_geoms.holes and render_data.darken_area is None and lowest_important_level_passed:
|
||||||
render_data.darken_area = old_geoms.holes
|
render_data.darken_area = old_geoms.holes
|
||||||
|
|
||||||
if crop_to.geometry is not None:
|
if crop_to.geometry is not None:
|
||||||
map_history.composite(MapHistory.open_level(sublevel.pk, 'base'), crop_to.geometry)
|
map_history.composite(MapHistory.open_level(level.pk, 'base'), crop_to.geometry)
|
||||||
elif level.pk != sublevel.pk:
|
elif render_level.pk != level.pk:
|
||||||
map_history.composite(MapHistory.open_level(sublevel.pk, 'base'), None)
|
map_history.composite(MapHistory.open_level(level.pk, 'base'), None)
|
||||||
|
|
||||||
new_geoms = LevelGeometries()
|
new_geoms = LevelGeometries()
|
||||||
new_geoms.buildings = crop_to.intersection(old_geoms.buildings)
|
new_geoms.buildings = crop_to.intersection(old_geoms.buildings)
|
||||||
|
@ -285,7 +303,7 @@ class LevelRenderData:
|
||||||
new_geoms.lower_bound = old_geoms.lower_bound
|
new_geoms.lower_bound = old_geoms.lower_bound
|
||||||
new_geoms.upper_bound = old_geoms.upper_bound
|
new_geoms.upper_bound = old_geoms.upper_bound
|
||||||
|
|
||||||
new_geoms.build_mesh(interpolators.get(level.pk) if sublevel.pk == level.pk else None)
|
new_geoms.build_mesh(interpolators.get(render_level.pk) if level.pk == render_level.pk else None)
|
||||||
|
|
||||||
render_data.levels.append(new_geoms)
|
render_data.levels.append(new_geoms)
|
||||||
|
|
||||||
|
@ -295,13 +313,13 @@ class LevelRenderData:
|
||||||
}
|
}
|
||||||
|
|
||||||
access_restriction_affected = AccessRestrictionAffected.build(access_restriction_affected)
|
access_restriction_affected = AccessRestrictionAffected.build(access_restriction_affected)
|
||||||
access_restriction_affected.save_level(level.pk, 'composite')
|
access_restriction_affected.save_level(render_level.pk, 'composite')
|
||||||
|
|
||||||
map_history.save_level(level.pk, 'composite')
|
map_history.save_level(render_level.pk, 'composite')
|
||||||
|
|
||||||
package.add_level(level.pk, map_history, access_restriction_affected)
|
package.add_level(render_level.pk, map_history, access_restriction_affected)
|
||||||
|
|
||||||
render_data.save(level.pk)
|
render_data.save(render_level.pk)
|
||||||
|
|
||||||
package.save_all()
|
package.save_all()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue