remove all old rendering methods

This commit is contained in:
Laura Klünder 2017-11-09 17:32:39 +01:00
parent c365debfba
commit bf1e8a9b11

View file

@ -1,20 +1,13 @@
import os
from decimal import Decimal
from itertools import chain
from operator import attrgetter, itemgetter
from operator import attrgetter
from django.conf import settings
from django.db import models
from django.db.models import Prefetch
from django.urls import reverse
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
from shapely.geometry import JOIN_STYLE, box
from shapely.ops import cascaded_union
from c3nav.mapdata.models.locations import SpecificLocation
from c3nav.mapdata.utils.geometry import assert_multipolygon
from c3nav.mapdata.utils.scad import add_indent, polygon_scad
class LevelManager(models.Manager):
@ -98,50 +91,6 @@ class Level(SpecificLocation, models.Model):
result['editor_url'] = reverse('editor.levels.detail', kwargs={'pk': self.pk})
return result
def _render_space_ground(self, svg, space):
areas_by_color = {}
for area in space.areas.all():
areas_by_color.setdefault(area.get_color(), []).append(area)
areas_by_color.pop(None, None)
areas_by_color.pop('', None)
for i, (color, color_areas) in enumerate(areas_by_color.items()):
geometries = cascaded_union(tuple(area.geometry for area in color_areas)).intersection(space.geometry)
svg.add_geometry(geometries, fill_color=color)
stair_geometries = tuple(stair.geometry for stair in space.stairs.all())
svg.add_geometry(cascaded_union(stair_geometries).intersection(space.geometry),
stroke_width=0.06, stroke_color='#000000', opacity=0.15)
for i in range(2):
svg.add_geometry(cascaded_union(tuple(g.parallel_offset(0.06+0.04*i, 'right', join_style=JOIN_STYLE.mitre)
for g in stair_geometries)).intersection(space.geometry),
stroke_width=0.04, stroke_color='#000000', opacity=0.07-0.05*i)
def _render_space_inventory(self, svg, space):
obstacle_geometries = cascaded_union(
tuple(obstacle.geometry for obstacle in space.obstacles.all()) +
tuple(obstacle.buffered_geometry for obstacle in space.lineobstacles.all())
).intersection(space.geometry)
svg.add_geometry(obstacle_geometries, fill_color='#999999')
@staticmethod
def _give_height_to_areas_with_one_neighbor(accessible_area, areas_by_altitude):
# give height to all obstacles that touch only one altitude
remaining_polygons = []
for polygon in assert_multipolygon(accessible_area):
buffered = polygon.buffer(0.001)
found_altitude = None
for altitude, area in areas_by_altitude.items():
if buffered.intersects(area[0]):
if found_altitude is not None:
found_altitude = None
break
found_altitude = altitude
if found_altitude is None:
remaining_polygons.append(polygon)
else:
areas_by_altitude[found_altitude].append(polygon)
return cascaded_union(remaining_polygons)
@cached_property
def min_altitude(self):
return min(self.altitudeareas.all(), key=attrgetter('altitude'), default=self.base_altitude).altitude
@ -150,134 +99,3 @@ class Level(SpecificLocation, models.Model):
def bounds(self):
return cascaded_union(tuple(item.geometry.buffer(0)
for item in chain(self.altitudeareas.all(), self.buildings.all()))).bounds
def _render_scad_polygon(self, f, geometry, altitude, height=Decimal('0.0'), low_clip=()):
for low_altitude, low_area in low_clip:
intersection = geometry.intersection(low_area)
if not intersection.is_empty:
geometry = geometry.difference(intersection)
low_height = max(altitude - low_altitude, 0)
total_height = low_height+height
if total_height:
f.write(' ')
f.write('translate([0, 0, %.2f]) ' % (altitude - low_height))
f.write(add_indent(polygon_scad(intersection, total_height))[4:])
if not geometry.is_empty:
f.write(' ')
f.write('translate([0, 0, %.2f]) ' % (altitude - Decimal('0.5')))
f.write(add_indent(polygon_scad(geometry, height+Decimal('0.5')))[4:])
def _render_scad(self, f, low_clip=(), spaces=None, request=None):
f.write(' // '+self.title+'\n')
if spaces is None:
from c3nav.mapdata.models import Area, Space
spaces = self.spaces.filter(Space.q_for_request(request, allow_none=True)).prefetch_related(
Prefetch('areas', Area.qs_for_request(request, allow_none=True)),
'groups', 'columns', 'holes', 'areas__groups',
'stairs', 'obstacles', 'lineobstacles'
)
f.write('')
for area in self.altitudeareas.all():
area.geometry = area.geometry.buffer(0)
self._render_scad_polygon(f, area.geometry, area.altitude, low_clip=low_clip)
draw_obstacles = {}
height_spaces = {}
for space in spaces:
columns = cascaded_union(tuple(columns.geometry for columns in space.columns.all()))
space.geometry = space.geometry.difference(columns)
if self.on_top_of_id is None and not space.outside:
height = space.height or self.default_height
height_spaces.setdefault(height, []).append(space.geometry)
holes = cascaded_union(tuple(hole.geometry for hole in space.holes.all()))
for lineobstacle in space.lineobstacles.all():
lineobstacle.geometry = lineobstacle.buffered_geometry
for obstacle in chain(space.obstacles.all(), space.lineobstacles.all()):
geometry = obstacle.geometry.intersection(space.geometry).difference(holes)
for altitudearea in self.altitudeareas.all():
intersection = geometry.intersection(altitudearea.geometry)
if not intersection.is_empty:
geometry = geometry.difference(intersection.buffer(0.001, join_style=JOIN_STYLE.mitre))
draw_obstacles.setdefault((altitudearea.altitude, obstacle.height), []).append(intersection)
if not geometry.is_empty:
for polygon in assert_multipolygon(geometry):
center = polygon.centroid
altitude = min(self.altitudeareas.all(), key=lambda a: a.geometry.distance(center)).altitude
draw_obstacles.setdefault((altitude, obstacle.height), []).append(polygon)
for (altitude, height), polygons in draw_obstacles.items():
self._render_scad_polygon(f, cascaded_union(polygons), altitude, height, low_clip=low_clip)
spaces_geom = cascaded_union(tuple(space.geometry for space in self.spaces.all() if not space.outside))
buildings_geom = cascaded_union(tuple(building.geometry for building in self.buildings.all()))
doors_geom = cascaded_union(tuple(door.geometry for door in self.doors.all()))
walls_geom = buildings_geom.difference(doors_geom).difference(spaces_geom)
drawn_walls = {}
for height, polygons in sorted(height_spaces.items(), key=itemgetter(0)):
polygons = cascaded_union(polygons)
for area in self.altitudeareas.all():
intersection = area.geometry.intersection(polygons)
if not intersection.is_empty:
walls = intersection.buffer(0.5, join_style=JOIN_STYLE.mitre).intersection(walls_geom)
walls = walls.buffer(0.001, join_style=JOIN_STYLE.mitre)
self._render_scad_polygon(f, walls, area.altitude+height, low_clip=low_clip)
drawn_walls.setdefault(area.altitude+height, []).append(walls)
remaining_walls_geom = walls_geom.difference(cascaded_union(tuple(chain(*drawn_walls.values()))))
drawn_walls = {altitude: cascaded_union(walls) for altitude, walls in drawn_walls.items()}
drawn_walls_sorted = sorted(drawn_walls.items(), key=itemgetter(0))
for wall in assert_multipolygon(remaining_walls_geom):
buffered = wall.buffer(0.001, join_style=JOIN_STYLE.mitre)
try:
altitude = next(iter(altitude for altitude, geom in drawn_walls_sorted if geom.intersects(buffered)))
except StopIteration:
altitude = min(drawn_walls_sorted, key=lambda a: buffered.distance(a[1]))[0]
self._render_scad_polygon(f, buffered, altitude, low_clip=low_clip)
@classmethod
def _render_scad_levels(cls, levels, filename, level_spaces):
bounds = cascaded_union(tuple(box(*level.bounds) for level in levels)).bounds
center = tuple(box(*bounds).centroid.coords[0])
min_altitude = min((level.min_altitude for level in levels), default=0)
filename = os.path.join(settings.RENDER_ROOT, filename)
with open(filename, 'w') as f:
f.write('translate([%.2f, %.2f, %.2f]) {\n' % (0-center[0], 0-center[1], 0-min_altitude+Decimal('0.5')))
first = True
for level in levels:
low_clip = []
if first:
low_clip = [(level.min_altitude-Decimal('0.5'), box(*bounds))]
first = False
level._render_scad(f, spaces=level_spaces.get(level.pk, []), low_clip=low_clip)
f.write('}\n')
@classmethod
def render_scad_all(cls, levels=None, request=None):
from c3nav.mapdata.models import Level, Area, Space
spaces = Space.objects.filter(Space.q_for_request(request, allow_none=True)).prefetch_related(
Prefetch('areas', Area.qs_for_request(request, allow_none=True)),
'groups', 'columns', 'holes', 'areas__groups',
'stairs', 'obstacles', 'lineobstacles'
)
level_spaces = {}
for space in spaces:
level_spaces.setdefault(space.level_id, []).append(space)
if levels is None:
levels = Level.objects
levels = levels.prefetch_related('buildings', 'doors', 'altitudeareas').order_by('base_altitude')
cls._render_scad_levels(levels, 'all.levels.scad', level_spaces)
for level in levels:
if level.on_top_of_id is not None:
continue
sublevels = tuple(sublevel for sublevel in levels if sublevel.on_top_of_id == level.pk)
cls._render_scad_levels((level, )+sublevels, level.get_slug()+'.scad', level_spaces)