team-3/src/c3nav/mapdata/models/graph.py

95 lines
3.8 KiB
Python

from decimal import Decimal
from django.core.validators import MinValueValidator
from django.db import models
from django.utils.translation import gettext_lazy as _
from c3nav.mapdata.fields import GeometryField, I18nField
from c3nav.mapdata.models.access import AccessRestrictionMixin
from c3nav.mapdata.models.base import SerializableMixin
from c3nav.mapdata.models.geometry.space import SpaceGeometryMixin
from c3nav.mapdata.utils.geometry import smart_mapping
class GraphNode(SpaceGeometryMixin, models.Model):
"""
A graph node
"""
geometry = GeometryField('point')
class Meta:
verbose_name = _('Graph Node')
verbose_name_plural = _('Graph Nodes')
default_related_name = 'graphnodes'
def get_geojson_properties(self, *args, **kwargs) -> dict:
result = super().get_geojson_properties(*args, **kwargs)
return result
@property
def coords(self):
return smart_mapping(self.geometry)['coordinates']
class WayType(SerializableMixin, models.Model):
"""
A special way type
"""
title = I18nField(_('Title'), plural_name='titles', fallback_any=True)
title_plural = I18nField(_('Title (Plural)'), plural_name='titles_plural', fallback_any=True)
join_edges = models.BooleanField(_('join consecutive edges'), default=True)
up_separate = models.BooleanField(_('upwards separately'), default=True)
walk = models.BooleanField(_('walking'), default=False)
color = models.CharField(max_length=32, verbose_name=_('edge color'))
icon_name = models.CharField(_('icon name'), max_length=32, null=True, blank=True)
extra_seconds = models.PositiveSmallIntegerField(_('extra seconds per edge'), default=0)
speed = models.DecimalField(_('speed (m/s)'), max_digits=3, decimal_places=1, default=1,
validators=[MinValueValidator(Decimal('0.1'))])
description = I18nField(_('description'), fallback_any=True)
speed_up = models.DecimalField(_('speed upwards (m/s)'), max_digits=3, decimal_places=1, default=1,
validators=[MinValueValidator(Decimal('0.1'))])
description_up = I18nField(_('description upwards'), fallback_any=True)
level_change_description = I18nField(_('level change description'))
class Meta:
verbose_name = _('Way Type')
verbose_name_plural = _('Way Types')
default_related_name = 'waytypes'
class GraphEdge(AccessRestrictionMixin, models.Model):
"""
A directed edge connecting two graph nodes
"""
from_node = models.ForeignKey(GraphNode, on_delete=models.PROTECT, related_name='edges_from_here',
verbose_name=_('from node'))
to_node = models.ForeignKey(GraphNode, on_delete=models.PROTECT, related_name='edges_to_here',
verbose_name=_('to node'))
waytype = models.ForeignKey(WayType, null=True, blank=True, on_delete=models.PROTECT, verbose_name=_('Way Type'))
class Meta:
verbose_name = _('Graph Edge')
verbose_name_plural = _('Graph Edges')
default_related_name = 'graphedges'
unique_together = (('from_node', 'to_node'), )
def to_geojson(self, instance=None) -> dict:
result = {
'type': 'Feature',
'properties': {
'id': self.pk,
'type': 'graphedge',
'from_node': self.from_node_id,
'to_node': self.to_node_id,
},
'geometry': {
'type': 'LineString',
'coordinates': (self.from_node.coords, self.to_node.coords),
},
}
if self.waytype_id is not None:
result['properties']['color'] = self.waytype.color
return result
def get_geojson_key(self):
return (self.__class__.__name__.lower(), self.pk)