""" Author: Michel Peltriaux Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany Contact: michel.peltriaux@sgdnord.rlp.de Created on: 04.01.22 """ import datetime from django.contrib.gis.db.models.functions import Area from konova.management.commands.setup import BaseKonovaCommand from konova.models import Geometry, ParcelIntersection class Command(BaseKonovaCommand): help = "Recalculates parcels for entries with geometry but missing parcel information" def add_arguments(self, parser): parser.add_argument( "--force-all", action="store_true", default=False, help="If Attribute set, all entries parcels will be recalculated" ) def handle(self, *args, **options): try: self.recalculate_parcels(options) except KeyboardInterrupt: self._break_line() exit(-1) def recalculate_parcels(self, options: dict): force_all = options.get("force_all", False) geometry_objects = Geometry.objects.filter( geom__isempty=False, ).exclude( geom=None ) if not force_all: # Fetch all intersections intersection_objs = ParcelIntersection.objects.filter( geometry__in=geometry_objects ) # Just take the geometry ids, which seem to have intersections geom_with_intersection_ids = intersection_objs.values_list( "geometry__id", flat=True ) # ... and resolve into Geometry objects again ... intersected_geom_objs = Geometry.objects.filter( id__in=geom_with_intersection_ids ) # ... to be able to use the way more efficient difference() function ... geometry_objects_ids = geometry_objects.difference(intersected_geom_objs).values_list("id", flat=True) # ... so we can resolve these into proper Geometry objects again for further annotation usage geometry_objects = Geometry.objects.filter(id__in=geometry_objects_ids) self._write_warning("=== Update parcels and districts ===") # Order geometries by size to process smaller once at first geometries = geometry_objects.annotate( area=Area("geom") ).order_by( 'area' ) self._write_warning(f"Process parcels for {geometries.count()} geometry entries now ...") i = 0 num_geoms = geometries.count() geoms_with_errors = {} for geometry in geometries: self._write_warning(f"--- {datetime.datetime.now()} Process {geometry.id} now ...") try: geometry.update_parcels() self._write_warning(f"--- Processed {geometry.get_underlying_parcels().count()} underlying parcels") except Exception as e: geoms_with_errors[geometry.id] = str(e) i += 1 self._write_warning(f"--- {i}/{num_geoms} processed") self._write_success("Updating parcels done!") for key, val in geoms_with_errors.items(): self._write_error(f" Error on {key}: {val}") self._write_success(f"{num_geoms - len(geoms_with_errors)} geometries successfuly recalculated!") self._break_line()