diff options
author | Étienne Loks <etienne.loks@peacefrogs.net> | 2019-02-06 14:25:30 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2019-04-24 19:38:56 +0200 |
commit | 172eb15954d2403831b073c785c38cac84505927 (patch) | |
tree | 7d2e9da91f30d86a408ec1cc6d984997993a4bfd | |
parent | 06747b5bef984838030667cf3b17e466cf5d27f7 (diff) | |
download | Ishtar-172eb15954d2403831b073c785c38cac84505927.tar.bz2 Ishtar-172eb15954d2403831b073c785c38cac84505927.zip |
Geo: manage autogen of polygons
-rw-r--r-- | archaeological_context_records/migrations/0040_auto_20190206_1423.py | 35 | ||||
-rw-r--r-- | archaeological_context_records/models.py | 17 | ||||
-rw-r--r-- | archaeological_finds/migrations/0060_auto_20190206_1423.py | 35 | ||||
-rw-r--r-- | archaeological_finds/models_finds.py | 15 | ||||
-rw-r--r-- | archaeological_operations/migrations/0050_auto_20190206_1423.py | 55 | ||||
-rw-r--r-- | archaeological_operations/models.py | 36 | ||||
-rw-r--r-- | ishtar_common/tests.py | 4 | ||||
-rw-r--r-- | ishtar_common/utils.py | 84 |
8 files changed, 256 insertions, 25 deletions
diff --git a/archaeological_context_records/migrations/0040_auto_20190206_1423.py b/archaeological_context_records/migrations/0040_auto_20190206_1423.py new file mode 100644 index 000000000..b3c5a6837 --- /dev/null +++ b/archaeological_context_records/migrations/0040_auto_20190206_1423.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2019-02-06 14:23 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_context_records', '0039_auto_20190122_1550'), + ] + + operations = [ + migrations.AddField( + model_name='contextrecord', + name='multi_polygon_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Multi-polygon source'), + ), + migrations.AddField( + model_name='contextrecord', + name='point_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Point source'), + ), + migrations.AddField( + model_name='historicalcontextrecord', + name='multi_polygon_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Multi-polygon source'), + ), + migrations.AddField( + model_name='historicalcontextrecord', + name='point_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Point source'), + ), + ] diff --git a/archaeological_context_records/models.py b/archaeological_context_records/models.py index 89526076a..4b41fddb7 100644 --- a/archaeological_context_records/models.py +++ b/archaeological_context_records/models.py @@ -28,7 +28,7 @@ from django.utils.translation import ugettext_lazy as _, pgettext, \ from django.utils.text import slugify from ishtar_common.utils import cached_label_changed, \ - m2m_historization_changed, post_save_point + m2m_historization_changed, post_save_geo from ishtar_common.models import Document, GeneralType, \ BaseHistorizedItem, HistoricalRecords, OwnPerms, ShortMenuItem, \ @@ -485,8 +485,16 @@ class ContextRecord(BulkUpdatedItem, BaseHistorizedItem, blank=True, null=True) point_2d = models.PointField(_(u"Point (2D)"), blank=True, null=True) point = models.PointField(_(u"Point (3D)"), blank=True, null=True, dim=3) + point_source = models.CharField( + _(u"Point source"), + choices=(('T', _(u"Town")), ('P', _(u"Precise"))), max_length=1, + blank=True, null=True) multi_polygon = models.MultiPolygonField(_(u"Multi polygon"), blank=True, null=True) + multi_polygon_source = models.CharField( + _(u"Multi-polygon source"), + choices=(('T', _(u"Town")), ('P', _(u"Precise"))), max_length=1, + blank=True, null=True) documents = models.ManyToManyField( Document, related_name='context_records', verbose_name=_(u"Documents"), blank=True) @@ -528,6 +536,11 @@ class ContextRecord(BulkUpdatedItem, BaseHistorizedItem, return self.town.center return self.operation.get_town_centroid() + def get_town_polygons(self): + if self.town: + return self.town.limit + return self.operation.get_town_polygon() + @classmethod def cached_label_bulk_update(cls, operation_id=None, parcel_id=None, transaction_id=None): @@ -752,7 +765,7 @@ class ContextRecord(BulkUpdatedItem, BaseHistorizedItem, def context_record_post_save(sender, **kwargs): cached_label_changed(sender=sender, **kwargs) - post_save_point(sender=sender, **kwargs) + post_save_geo(sender=sender, **kwargs) post_save.connect(context_record_post_save, sender=ContextRecord) diff --git a/archaeological_finds/migrations/0060_auto_20190206_1423.py b/archaeological_finds/migrations/0060_auto_20190206_1423.py new file mode 100644 index 000000000..6ddfa5145 --- /dev/null +++ b/archaeological_finds/migrations/0060_auto_20190206_1423.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2019-02-06 14:23 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_finds', '0059_auto_20190204_1134'), + ] + + operations = [ + migrations.AddField( + model_name='basefind', + name='multi_polygon_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Multi-polygon source'), + ), + migrations.AddField( + model_name='basefind', + name='point_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Point source'), + ), + migrations.AddField( + model_name='historicalbasefind', + name='multi_polygon_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Multi-polygon source'), + ), + migrations.AddField( + model_name='historicalbasefind', + name='point_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Point source'), + ), + ] diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py index da872ab53..3f0ade1df 100644 --- a/archaeological_finds/models_finds.py +++ b/archaeological_finds/models_finds.py @@ -30,7 +30,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.utils.translation import ugettext_lazy as _, pgettext_lazy\ from ishtar_common.data_importer import post_importer_action, ImporterError -from ishtar_common.utils import cached_label_changed, post_save_point, \ +from ishtar_common.utils import cached_label_changed, post_save_geo, \ m2m_historization_changed from ishtar_common.alternative_configs import ALTERNATE_CONFIGS @@ -306,9 +306,17 @@ class BaseFind(BulkUpdatedItem, BaseHistorizedItem, OwnPerms): blank=True, null=True) point_2d = models.PointField(_(u"Point (2D)"), blank=True, null=True) point = models.PointField(_(u"Point (3D)"), blank=True, null=True, dim=3) + point_source = models.CharField( + _(u"Point source"), + choices=(('T', _(u"Town")), ('P', _(u"Precise"))), max_length=1, + blank=True, null=True) line = models.LineStringField(_(u"Line"), blank=True, null=True) multi_polygon = models.MultiPolygonField(_(u"Multi polygon"), blank=True, null=True) + multi_polygon_source = models.CharField( + _(u"Multi-polygon source"), + choices=(('T', _(u"Town")), ('P', _(u"Precise"))), max_length=1, + blank=True, null=True) cache_short_id = models.TextField( _(u"Short ID"), blank=True, null=True, db_index=True, help_text=_(u"Cached value - do not edit")) @@ -357,6 +365,9 @@ class BaseFind(BulkUpdatedItem, BaseHistorizedItem, OwnPerms): def get_town_centroid(self): return self.context_record.get_town_centroid() + def get_town_polygons(self): + return self.context_record.get_town_polygons() + def generate_index(self): """ Generate index based on operation or context record (based on @@ -592,7 +603,7 @@ class BaseFind(BulkUpdatedItem, BaseHistorizedItem, OwnPerms): def post_save_basefind(sender, **kwargs): cached_label_changed(sender, **kwargs) - post_save_point(sender, **kwargs) + post_save_geo(sender, **kwargs) post_save.connect(post_save_basefind, sender=BaseFind) diff --git a/archaeological_operations/migrations/0050_auto_20190206_1423.py b/archaeological_operations/migrations/0050_auto_20190206_1423.py new file mode 100644 index 000000000..a632b6059 --- /dev/null +++ b/archaeological_operations/migrations/0050_auto_20190206_1423.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2019-02-06 14:23 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_operations', '0049_auto_20190122_1621'), + ] + + operations = [ + migrations.AddField( + model_name='archaeologicalsite', + name='multi_polygon_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Multi-polygon source'), + ), + migrations.AddField( + model_name='archaeologicalsite', + name='point_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Point source'), + ), + migrations.AddField( + model_name='historicalarchaeologicalsite', + name='multi_polygon_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Multi-polygon source'), + ), + migrations.AddField( + model_name='historicalarchaeologicalsite', + name='point_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Point source'), + ), + migrations.AddField( + model_name='historicaloperation', + name='multi_polygon_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Multi-polygon source'), + ), + migrations.AddField( + model_name='historicaloperation', + name='point_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Point source'), + ), + migrations.AddField( + model_name='operation', + name='multi_polygon_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Multi-polygon source'), + ), + migrations.AddField( + model_name='operation', + name='point_source', + field=models.CharField(blank=True, choices=[(b'T', 'Commune'), (b'P', 'Precise')], max_length=1, null=True, verbose_name='Point source'), + ), + ] diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index a8f1d4faf..2335155ed 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -41,7 +41,7 @@ from ishtar_common.models import BaseHistorizedItem, Dashboard, \ document_attached_changed, HistoryModel, SearchAltName, \ SpatialReferenceSystem from ishtar_common.utils import cached_label_changed, \ - force_cached_label_changed, mode, m2m_historization_changed, post_save_point + force_cached_label_changed, mode, m2m_historization_changed, post_save_geo class RemainType(GeneralType): @@ -277,8 +277,16 @@ class ArchaeologicalSite(BaseHistorizedItem, OwnPerms, ValueGetter, blank=True, null=True) point = models.PointField(_(u"Point"), blank=True, null=True, dim=3) point_2d = models.PointField(_(u"Point (2D)"), blank=True, null=True) + point_source = models.CharField( + _(u"Point source"), + choices=(('T', _(u"Town")), ('P', _(u"Precise"))), max_length=1, + blank=True, null=True) multi_polygon = models.MultiPolygonField(_(u"Multi polygon"), blank=True, null=True) + multi_polygon_source = models.CharField( + _(u"Multi-polygon source"), + choices=(('T', _(u"Town")), ('P', _(u"Precise"))), max_length=1, + blank=True, null=True) documents = models.ManyToManyField( Document, related_name="sites", verbose_name=_(u"Documents"), @@ -392,6 +400,13 @@ class ArchaeologicalSite(BaseHistorizedItem, OwnPerms, ValueGetter, return None return q.all()[0].centroid + def get_town_polygons(self): + q = self.towns.filter(limit__isnull=False).annotate( + poly=Union('limit')).all() + if not q.count(): + return None + return q.all()[0].poly + def _get_base_image_path(self): return u"{}/{}".format(self.SLUG, self.reference) @@ -447,7 +462,7 @@ class ArchaeologicalSite(BaseHistorizedItem, OwnPerms, ValueGetter, def site_post_save(sender, **kwargs): cached_label_changed(sender=sender, **kwargs) - post_save_point(sender=sender, **kwargs) + post_save_geo(sender=sender, **kwargs) post_save.connect(site_post_save, sender=ArchaeologicalSite) @@ -940,8 +955,16 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter, blank=True, null=True) point = models.PointField(_(u"Point"), blank=True, null=True, dim=3) point_2d = models.PointField(_(u"Point (2D)"), blank=True, null=True) + point_source = models.CharField( + _(u"Point source"), + choices=(('T', _(u"Town")), ('P', _(u"Precise"))), max_length=1, + blank=True, null=True) multi_polygon = models.MultiPolygonField(_(u"Multi polygon"), blank=True, null=True) + multi_polygon_source = models.CharField( + _(u"Multi-polygon source"), + choices=(('T', _(u"Town")), ('P', _(u"Precise"))), max_length=1, + blank=True, null=True) history = HistoricalRecords(bases=[HistoryModel]) class Meta: @@ -1115,6 +1138,13 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter, return None return q.all()[0].centroid + def get_town_polygons(self): + q = self.towns.filter(limit__isnull=False).annotate( + poly=Union('limit')).all() + if not q.count(): + return None + return q.all()[0].poly + def context_record_relations_q(self): from archaeological_context_records.models \ import RecordRelations as CRRL @@ -1464,7 +1494,7 @@ for attr in Operation.HISTORICAL_M2M: def operation_post_save(sender, **kwargs): if not kwargs['instance']: return - post_save_point(sender=sender, **kwargs) + post_save_geo(sender=sender, **kwargs) operation = kwargs['instance'] operation.skip_history_when_saving = True diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py index 8ecf98255..53ad67faa 100644 --- a/ishtar_common/tests.py +++ b/ishtar_common/tests.py @@ -45,7 +45,7 @@ from django.test.runner import DiscoverRunner from ishtar_common import models from ishtar_common import views from ishtar_common.apps import admin_site -from ishtar_common.utils import post_save_point, update_data, move_dict_data, \ +from ishtar_common.utils import post_save_geo, update_data, move_dict_data, \ rename_and_simplify_media_name, try_fix_file @@ -1589,7 +1589,7 @@ class GeomaticTest(TestCase): x=2, y=3, z=4, spatial_reference_system=srs) self.assertIsNone(obj.point_2d) - post_save_point(None, instance=obj) + post_save_geo(None, instance=obj) self.assertIsNotNone(obj.point_2d) self.assertIsNotNone(obj.point) diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py index 20957c43e..0f33fd30d 100644 --- a/ishtar_common/utils.py +++ b/ishtar_common/utils.py @@ -469,10 +469,11 @@ def convert_coordinates_to_point(x, y, z=None, srid=4326): return geom -def post_save_point(sender, **kwargs): +def post_save_geo(sender, **kwargs): """ Convert raw x, y, z point to real geo field """ + from ishtar_common.models import SpatialReferenceSystem if not kwargs.get('instance'): return instance = kwargs.get('instance') @@ -481,21 +482,72 @@ def post_save_point(sender, **kwargs): from ishtar_common.models import get_current_profile # not clean but utils # must be loaded before models profile = get_current_profile() - if instance.x and instance.y and \ - instance.spatial_reference_system and \ - instance.spatial_reference_system.auth_name == 'EPSG' and \ - instance.spatial_reference_system.srid != 0: - point_2d = convert_coordinates_to_point( - instance.x, instance.y, srid=instance.spatial_reference_system.srid) - if instance.z: - point = convert_coordinates_to_point( - instance.x, instance.y, instance.z, - srid=instance.spatial_reference_system.srid) - elif profile.use_town_for_geo: - point_2d = instance.get_town_centroid() - if point_2d != instance.point_2d or point != instance.point: - instance.point = point - instance.point_2d = point_2d + modified = False + + if (point or point_2d) and instance.x is None: # db source + if point: + current_point = point + instance.z = point.z + else: + current_point = point_2d + instance.x = current_point.x + instance.y = current_point.y + try: + srs = SpatialReferenceSystem.objects.get( + srid=int(current_point.srid)) + except SpatialReferenceSystem.DoesNotExist: + srs = SpatialReferenceSystem.objects.create( + srid=int(current_point.srid), + auth_name='EPSG', + label=u"EPSG-{}".format(current_point.srid), + txt_idx=u"epsg-{}".format(current_point.srid), + ) + instance.spatial_reference_system = srs + instance.point_source = 'P' + if not point_2d: + instance.point_2d = convert_coordinates_to_point( + instance.point.x, instance.point.y, + srid=current_point.srid) + elif not point_2d: + source = None + if instance.x and instance.y and \ + instance.spatial_reference_system and \ + instance.spatial_reference_system.auth_name == 'EPSG' and \ + instance.spatial_reference_system.srid != 0: # form input + try: + point_2d = convert_coordinates_to_point( + instance.x, instance.y, + srid=instance.spatial_reference_system.srid) + except forms.ValidationError: + return # irrelevant data in DB + if point_2d: + source = 'P' # precise + if instance.z: + point = convert_coordinates_to_point( + instance.x, instance.y, instance.z, + srid=instance.spatial_reference_system.srid) + elif profile.use_town_for_geo: # + point_2d = instance.get_town_centroid() + source = 'T' # town + + if point_2d != instance.point_2d or point != instance.point: + instance.point = point + instance.point_2d = point_2d + instance.point_source = source + modified = True + + if instance.multi_polygon and not instance.multi_polygon_source: + # should be a db source + instance.multi_polygon_source = 'P' + modified = True + elif profile.use_town_for_geo and instance.multi_polygon_source != 'P': + poly = instance.get_town_polygons() + if poly and poly != instance.multi_polygon: + instance.multi_polygon_source = 'T' # town + instance.multi_polygon = poly + modified = True + + if modified: instance.skip_history_when_saving = True instance.save() return |