change altitudearea model to support multiple points

This commit is contained in:
Laura Klünder 2024-08-17 21:17:54 +02:00
parent 02411b0181
commit 732cd8a4ea
2 changed files with 90 additions and 6 deletions

View file

@ -0,0 +1,67 @@
# Generated by Django 5.0.8 on 2024-08-17 17:50
import django.core.serializers.json
import django_pydantic_field.compat.django
import django_pydantic_field.fields
import types
import typing
from django.db import migrations, models
from shapely.geometry import Point
from c3nav.mapdata.models.geometry.level import AltitudeAreaPoint
def forwards_func(apps, schema_editor):
AltitudeArea = apps.get_model('mapdata', 'AltitudeArea')
for area in AltitudeArea.objects.all():
if area.point1 is not None:
area.points = [
AltitudeAreaPoint(coordinates=[area.point1.x, area.point1.y], altitude=float(area.altitude1)),
AltitudeAreaPoint(coordinates=[area.point2.x, area.point2.y], altitude=float(area.altitude))
]
area.altitude = None
area.save()
def backwards_func(apps, schema_editor):
AltitudeArea = apps.get_model('mapdata', 'AltitudeArea')
for area in AltitudeArea.objects.all():
if area.points is not None:
area.point1 = Point(*area.points[0].coordinates)
area.point2 = Point(*area.points[-1].coordinates)
area.altitude = area.points[0].altitude
area.altitude2 = area.points[-1].altitude
area.save()
class Migration(migrations.Migration):
dependencies = [
('mapdata', '0106_rename_wifi_to_beaconmeasurement'),
]
operations = [
migrations.AddField(
model_name='altitudearea',
name='points',
field=django_pydantic_field.fields.PydanticSchemaField(config=None, encoder=django.core.serializers.json.DjangoJSONEncoder, null=True, schema=django_pydantic_field.compat.django.GenericContainer(typing.Union, (django_pydantic_field.compat.django.GenericContainer(list, (AltitudeAreaPoint,)), types.NoneType))),
),
migrations.AlterField(
model_name='altitudearea',
name='altitude',
field=models.DecimalField(decimal_places=2, max_digits=6, null=True, verbose_name='altitude'),
),
migrations.RunPython(forwards_func, backwards_func),
migrations.RemoveField(
model_name='altitudearea',
name='altitude2',
),
migrations.RemoveField(
model_name='altitudearea',
name='point1',
),
migrations.RemoveField(
model_name='altitudearea',
name='point2',
),
]

View file

@ -3,20 +3,26 @@ from collections import deque
from decimal import Decimal
from itertools import chain, combinations
from operator import attrgetter, itemgetter
from typing import Sequence, Optional
import numpy as np
from django.core.validators import MinValueValidator
from django.db import models
from django.db.models import CheckConstraint, Q
from django.urls import reverse
from django.utils.functional import cached_property
from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy as _
from pydantic import Field as APIField
from scipy.interpolate._rbfinterp import RBFInterpolator
from shapely import prepared
from shapely.affinity import scale
from shapely.geometry import JOIN_STYLE, LineString, MultiPolygon
from shapely.geometry import JOIN_STYLE, LineString, MultiPolygon, Point
from shapely.geometry.polygon import orient
from django_pydantic_field import SchemaField
from shapely.ops import unary_union
from c3nav.api.schema import BaseSchema
from c3nav.mapdata.fields import GeometryField, I18nField
from c3nav.mapdata.grid import grid
from c3nav.mapdata.models import Level
@ -170,15 +176,26 @@ class ItemWithValue:
return self._func()
class AltitudeAreaPoint(BaseSchema):
coordinates: tuple[float, float] = APIField(
example=[1, 2.5]
)
altitude: float
class AltitudeArea(LevelGeometryMixin, models.Model):
"""
An altitude area
"""
geometry = GeometryField('multipolygon')
altitude = models.DecimalField(_('altitude'), null=False, max_digits=6, decimal_places=2)
altitude2 = models.DecimalField(_('second altitude'), null=True, max_digits=6, decimal_places=2)
point1 = GeometryField('point', null=True)
point2 = GeometryField('point', null=True)
geometry: MultiPolygon = GeometryField('multipolygon')
altitude = models.DecimalField(_('altitude'), null=True, max_digits=6, decimal_places=2)
points: Sequence[AltitudeAreaPoint] = SchemaField(schema=list[AltitudeAreaPoint], null=True)
constraints = (
CheckConstraint(check=(Q(points__isnull=True, altitude__isnull=False) |
Q(points__isnull=False, altitude__isnull=True)),
name="altitudearea_needs_precisely_one_of_altitude_or_points"),
)
class Meta:
verbose_name = _('Altitude Area')