rudimentary theme support

This commit is contained in:
Gwendolyn 2024-01-06 13:26:34 +01:00
parent b44197a1c5
commit 9399e5c377
23 changed files with 925 additions and 307 deletions

View file

@ -14,7 +14,7 @@ from c3nav.mapdata.fields import GeometryField, I18nField
from c3nav.mapdata.grid import grid
from c3nav.mapdata.models import Space
from c3nav.mapdata.models.access import AccessRestrictionMixin
from c3nav.mapdata.models.base import SerializableMixin
from c3nav.mapdata.models.base import SerializableMixin, TitledMixin
from c3nav.mapdata.models.geometry.base import GeometryMixin
from c3nav.mapdata.models.locations import SpecificLocation
from c3nav.mapdata.utils.cache.changes import changed_geometries
@ -38,7 +38,8 @@ class SpaceGeometryMixin(GeometryMixin):
def get_geojson_properties(self, *args, instance=None, **kwargs) -> dict:
result = super().get_geojson_properties(*args, **kwargs)
if hasattr(self, 'get_color'):
color = self.get_color(instance=instance)
from c3nav.mapdata.render.theme import ColorManager
color = self.get_color(ColorManager.for_theme(None), instance=instance)
if color:
result['color'] = color
if hasattr(self, 'opacity'):
@ -175,16 +176,42 @@ class Ramp(SpaceGeometryMixin, models.Model):
default_related_name = 'ramps'
class ObstacleGroup(TitledMixin, models.Model):
color = models.CharField(max_length=32, null=True, blank=True)
class Meta:
verbose_name = _('Obstacle Group')
verbose_name_plural = _('Obstacle Groups')
default_related_name = 'groups'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.orig_color = self.color
def save(self, *args, **kwargs):
if self.pk and (self.orig_color != self.color):
self.register_changed_geometries()
super().save(*args, **kwargs)
def delete(self, *args, **kwargs):
self.register_changed_geometries()
super().delete(*args, **kwargs)
def register_changed_geometries(self, do_query=True):
for obj in self.obstacles.select_related('space'):
obj.register_change(force=True)
class Obstacle(SpaceGeometryMixin, models.Model):
"""
An obstacle
"""
group = models.ForeignKey(ObstacleGroup, null=True, blank=True, on_delete=models.SET_NULL)
geometry = GeometryField('polygon')
height = models.DecimalField(_('height'), max_digits=6, decimal_places=2, default=0.8,
validators=[MinValueValidator(Decimal('0'))])
altitude = models.DecimalField(_('altitude above ground'), max_digits=6, decimal_places=2, default=0,
validators=[MinValueValidator(Decimal('0'))])
color = models.CharField(null=True, blank=True, max_length=32, verbose_name=_('color (optional)'))
class Meta:
verbose_name = _('Obstacle')
@ -194,22 +221,31 @@ class Obstacle(SpaceGeometryMixin, models.Model):
def get_geojson_properties(self, *args, instance=None, **kwargs) -> dict:
result = super().get_geojson_properties(*args, **kwargs)
if self.color:
result['color'] = self.color
from c3nav.mapdata.render.theme import ColorManager
color = self.get_color(ColorManager.for_theme(None), instance=instance)
if color:
result['color'] = color
return result
def _serialize(self, geometry=True, **kwargs):
result = super()._serialize(geometry=geometry, **kwargs)
result['height'] = float(str(self.height))
result['altitude'] = float(str(self.altitude))
result['color'] = self.color
from c3nav.mapdata.render.theme import ColorManager
result['color'] = self.get_color(ColorManager.for_theme(None))
return result
def get_color(self, color_manager: 'ThemeColorManager', instance=None):
if instance is None:
instance = self
return color_manager.obstaclegroup_fill_color(instance.group) if instance.group is not None else color_manager.obstacles_default_fill
class LineObstacle(SpaceGeometryMixin, models.Model):
"""
An obstacle that is a line with a specific width
"""
group = models.ForeignKey(ObstacleGroup, null=True, blank=True, on_delete=models.SET_NULL)
geometry = GeometryField('linestring')
width = models.DecimalField(_('width'), max_digits=4, decimal_places=2, default=0.15)
height = models.DecimalField(_('height'), max_digits=6, decimal_places=2, default=0.8,
@ -217,6 +253,7 @@ class LineObstacle(SpaceGeometryMixin, models.Model):
altitude = models.DecimalField(_('altitude above ground'), max_digits=6, decimal_places=2, default=0,
validators=[MinValueValidator(Decimal('0'))])
color = models.CharField(null=True, blank=True, max_length=32, verbose_name=_('color (optional)'))
# TODO: migrate away from color same as for Obstacle
class Meta:
verbose_name = _('Line Obstacle')
@ -226,8 +263,10 @@ class LineObstacle(SpaceGeometryMixin, models.Model):
def get_geojson_properties(self, *args, instance=None, **kwargs) -> dict:
result = super().get_geojson_properties(*args, **kwargs)
if self.color:
result['color'] = self.color
from c3nav.mapdata.render.theme import ColorManager
color = self.get_color(ColorManager.for_theme(None), instance=instance)
if color:
result['color'] = color
return result
def _serialize(self, geometry=True, **kwargs):
@ -235,11 +274,18 @@ class LineObstacle(SpaceGeometryMixin, models.Model):
result['width'] = float(str(self.width))
result['height'] = float(str(self.height))
result['altitude'] = float(str(self.altitude))
result['color'] = self.color
from c3nav.mapdata.render.theme import ColorManager
result['color'] = self.get_color(ColorManager.for_theme(None))
if geometry:
result['buffered_geometry'] = format_geojson(mapping(self.buffered_geometry))
return result
def get_color(self, color_manager: 'ThemeColorManager', instance=None):
if instance is None:
instance = self
# TODO: should line obstacles use border color?
return color_manager.obstaclegroup_fill_color(instance.group) if instance.group is not None else color_manager.obstacles_default_fill
@property
def buffered_geometry(self):
return self.geometry.buffer(float(self.width / 2), join_style=JOIN_STYLE.mitre, cap_style=CAP_STYLE.flat)