try to call heavy shapely operations less often to improve performance
This commit is contained in:
parent
b6be667cfc
commit
b700ccd46c
1 changed files with 44 additions and 19 deletions
|
@ -159,10 +159,20 @@ class AltitudeAreaGeometries:
|
||||||
crops=crops)
|
crops=crops)
|
||||||
|
|
||||||
|
|
||||||
class FakeCropper:
|
empty_geometry_collection = GeometryCollection()
|
||||||
@staticmethod
|
|
||||||
def intersection(other):
|
|
||||||
return other
|
class Cropper:
|
||||||
|
def __init__(self, geometry=None):
|
||||||
|
self.geometry = geometry
|
||||||
|
self.geometry_prep = None if geometry is None else prepared.prep(geometry)
|
||||||
|
|
||||||
|
def intersection(self, other):
|
||||||
|
if self.geometry is None:
|
||||||
|
return other
|
||||||
|
if self.geometry_prep.intersects(other):
|
||||||
|
return self.geometry.intersection(other)
|
||||||
|
return empty_geometry_collection
|
||||||
|
|
||||||
|
|
||||||
class LevelRenderData:
|
class LevelRenderData:
|
||||||
|
@ -224,7 +234,7 @@ class LevelRenderData:
|
||||||
primary_level_count += 1
|
primary_level_count += 1
|
||||||
|
|
||||||
# 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] = crop_to if primary_level_count > 1 else FakeCropper
|
level_crop_to[sublevel.pk] = Cropper(crop_to if primary_level_count > 1 else None)
|
||||||
|
|
||||||
if geoms.holes is not None:
|
if geoms.holes is not None:
|
||||||
if crop_to is None:
|
if crop_to is None:
|
||||||
|
@ -246,8 +256,8 @@ class LevelRenderData:
|
||||||
|
|
||||||
old_geoms = single_level_geoms[sublevel.pk]
|
old_geoms = single_level_geoms[sublevel.pk]
|
||||||
|
|
||||||
if crop_to is not FakeCropper:
|
if crop_to.geometry is not None:
|
||||||
map_history.composite(MapHistory.open_level(sublevel.pk, 'base'), crop_to)
|
map_history.composite(MapHistory.open_level(sublevel.pk, 'base'), crop_to.geometry)
|
||||||
elif level.pk != sublevel.pk:
|
elif level.pk != sublevel.pk:
|
||||||
map_history.composite(MapHistory.open_level(sublevel.pk, 'base'), None)
|
map_history.composite(MapHistory.open_level(sublevel.pk, 'base'), None)
|
||||||
|
|
||||||
|
@ -264,6 +274,7 @@ class LevelRenderData:
|
||||||
new_geometry = crop_to.intersection(altitudearea.geometry)
|
new_geometry = crop_to.intersection(altitudearea.geometry)
|
||||||
if new_geometry.is_empty:
|
if new_geometry.is_empty:
|
||||||
continue
|
continue
|
||||||
|
new_geometry_prep = prepared.prep(new_geometry)
|
||||||
|
|
||||||
new_altitudearea = AltitudeAreaGeometries()
|
new_altitudearea = AltitudeAreaGeometries()
|
||||||
new_altitudearea.geometry = new_geometry
|
new_altitudearea.geometry = new_geometry
|
||||||
|
@ -276,6 +287,8 @@ class LevelRenderData:
|
||||||
for color, areas in altitudearea.colors.items():
|
for color, areas in altitudearea.colors.items():
|
||||||
new_areas = {}
|
new_areas = {}
|
||||||
for access_restriction, area in areas.items():
|
for access_restriction, area in areas.items():
|
||||||
|
if not new_geometry_prep.intersects(area):
|
||||||
|
continue
|
||||||
new_area = new_geometry.intersection(area)
|
new_area = new_geometry.intersection(area)
|
||||||
if not new_area.is_empty:
|
if not new_area.is_empty:
|
||||||
new_areas[access_restriction] = new_area
|
new_areas[access_restriction] = new_area
|
||||||
|
@ -285,7 +298,7 @@ class LevelRenderData:
|
||||||
|
|
||||||
new_altitudearea.obstacles = {key: new_geometry.intersection(areas)
|
new_altitudearea.obstacles = {key: new_geometry.intersection(areas)
|
||||||
for key, areas in altitudearea.obstacles.items()
|
for key, areas in altitudearea.obstacles.items()
|
||||||
if new_geometry.intersects(areas)}
|
if new_geometry_prep.intersects(areas)}
|
||||||
|
|
||||||
new_geoms.altitudeareas.append(new_altitudearea)
|
new_geoms.altitudeareas.append(new_altitudearea)
|
||||||
|
|
||||||
|
@ -436,18 +449,27 @@ class LevelGeometries:
|
||||||
self.door_height = None
|
self.door_height = None
|
||||||
self.min_altitude = None
|
self.min_altitude = None
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def build_for_level(level, altitudeareas_above):
|
def build_for_level(cls, level, altitudeareas_above):
|
||||||
geoms = LevelGeometries()
|
geoms = LevelGeometries()
|
||||||
buildings_geom = unary_union([b.geometry for b in level.buildings.all()])
|
buildings_geom = unary_union([b.geometry for b in level.buildings.all()])
|
||||||
|
buildings_geom_prep = prepared.prep(buildings_geom)
|
||||||
|
|
||||||
# remove columns and holes from space areas
|
# remove columns and holes from space areas
|
||||||
for space in level.spaces.all():
|
for space in level.spaces.all():
|
||||||
|
subtract = []
|
||||||
if space.outside:
|
if space.outside:
|
||||||
space.geometry = space.geometry.difference(buildings_geom)
|
subtract.append(buildings_geom)
|
||||||
space.geometry = space.geometry.difference(unary_union([c.geometry for c in space.columns.all()]))
|
if subtract:
|
||||||
space.holes_geom = unary_union([h.geometry for h in space.holes.all()])
|
space.geometry = space.geometry.difference(unary_union(subtract))
|
||||||
space.walkable_geom = space.geometry.difference(space.holes_geom)
|
|
||||||
|
holes = tuple(h.geometry for h in space.holes.all())
|
||||||
|
if holes:
|
||||||
|
space.holes_geom = unary_union([h.geometry for h in space.holes.all()])
|
||||||
|
space.walkable_geom = space.geometry.difference(space.holes_geom)
|
||||||
|
else:
|
||||||
|
space.holes_geom = empty_geometry_collection
|
||||||
|
space.walkable_geom = space.geometry
|
||||||
|
|
||||||
spaces_geom = unary_union([s.geometry for s in level.spaces.all()])
|
spaces_geom = unary_union([s.geometry for s in level.spaces.all()])
|
||||||
doors_geom = unary_union([d.geometry for d in level.doors.all()])
|
doors_geom = unary_union([d.geometry for d in level.doors.all()])
|
||||||
|
@ -475,11 +497,13 @@ class LevelGeometries:
|
||||||
buffered = space.geometry.buffer(0.01).union(unary_union(
|
buffered = space.geometry.buffer(0.01).union(unary_union(
|
||||||
tuple(door.geometry for door in level.doors.all() if door.geometry.intersects(space.geometry))
|
tuple(door.geometry for door in level.doors.all() if door.geometry.intersects(space.geometry))
|
||||||
).difference(walkable_spaces_geom))
|
).difference(walkable_spaces_geom))
|
||||||
if buffered.intersects(buildings_geom):
|
|
||||||
|
intersects = buildings_geom_prep.intersects(buffered)
|
||||||
|
if intersects:
|
||||||
restricted_spaces_indoors.setdefault(access_restriction, []).append(
|
restricted_spaces_indoors.setdefault(access_restriction, []).append(
|
||||||
buffered.intersection(buildings_geom)
|
buffered.intersection(buildings_geom)
|
||||||
)
|
)
|
||||||
if not buffered.within(buildings_geom):
|
if not intersects or not buildings_geom_prep.contains(buffered):
|
||||||
restricted_spaces_outdoors.setdefault(access_restriction, []).append(
|
restricted_spaces_outdoors.setdefault(access_restriction, []).append(
|
||||||
buffered.difference(buildings_geom)
|
buffered.difference(buildings_geom)
|
||||||
)
|
)
|
||||||
|
@ -517,15 +541,16 @@ class LevelGeometries:
|
||||||
|
|
||||||
# add altitudegroup geometries and split ground colors into them
|
# add altitudegroup geometries and split ground colors into them
|
||||||
for altitudearea in level.altitudeareas.all():
|
for altitudearea in level.altitudeareas.all():
|
||||||
|
altitudearea_prep = prepared.prep(altitudearea.geometry)
|
||||||
altitudearea_colors = {color: {access_restriction: area.intersection(altitudearea.geometry)
|
altitudearea_colors = {color: {access_restriction: area.intersection(altitudearea.geometry)
|
||||||
for access_restriction, area in areas.items()
|
for access_restriction, area in areas.items()
|
||||||
if area.intersects(altitudearea.geometry)}
|
if altitudearea_prep.intersects(area)}
|
||||||
for color, areas in colors.items()}
|
for color, areas in colors.items()}
|
||||||
altitudearea_colors = {color: areas for color, areas in altitudearea_colors.items() if areas}
|
altitudearea_colors = {color: areas for color, areas in altitudearea_colors.items() if areas}
|
||||||
|
|
||||||
altitudearea_obstacles = {height: area.intersection(altitudearea.geometry)
|
altitudearea_obstacles = {height: area.intersection(altitudearea.geometry)
|
||||||
for height, area in obstacles.items()
|
for height, area in obstacles.items()
|
||||||
if area.intersects(altitudearea.geometry)}
|
if altitudearea_prep.intersects(area)}
|
||||||
geoms.altitudeareas.append(AltitudeAreaGeometries(altitudearea,
|
geoms.altitudeareas.append(AltitudeAreaGeometries(altitudearea,
|
||||||
altitudearea_colors,
|
altitudearea_colors,
|
||||||
altitudearea_obstacles))
|
altitudearea_obstacles))
|
||||||
|
@ -542,7 +567,7 @@ class LevelGeometries:
|
||||||
geoms.restricted_spaces_outdoors = {access_restriction: unary_union(spaces)
|
geoms.restricted_spaces_outdoors = {access_restriction: unary_union(spaces)
|
||||||
for access_restriction, spaces in restricted_spaces_outdoors.items()}
|
for access_restriction, spaces in restricted_spaces_outdoors.items()}
|
||||||
|
|
||||||
geoms.walls = buildings_geom.difference(spaces_geom).difference(doors_geom)
|
geoms.walls = buildings_geom.difference(unary_union((spaces_geom, doors_geom)))
|
||||||
|
|
||||||
# shorten walls if there are altitudeareas above
|
# shorten walls if there are altitudeareas above
|
||||||
remaining = geoms.walls
|
remaining = geoms.walls
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue