[NUUG fiksgatami] [patch] First draft for importing area unions into MapIt

Petter Reinholdtsen pere at hungry.com
Sat Apr 2 21:51:02 CEST 2011


Here is my first draft patch to import a new type of areas in to
Mapit.  We want the Norwegian Public Roads Administration regions into
MapIt, to be able to notify them about road problems.

The patch add a new type PRA for this kind of area.  I put the area
type outside the norwegian types, because I suspect other countries
have similar roads administration.  Please let me know if this is a
bad idea.

The import script is tested and found to be working, but the error
handling is bogus and I have not yet understood the generation stuff.

The import script is generic, and can combine any existing area into a
new area, and I expect we will use it here in Norway to create areas
for power grid distribution areas etc.

An example import is available from
<URL: http://mapit-dev.nuug.no/areas/NRA.html >.

Matthew, please provide your feedback on the approach. :)

Happy hacking,
-- 
Petter Reinholdtsen
-------------- next part --------------
diff --git a/pylib/mapit/areas/models.py b/pylib/mapit/areas/models.py
index 37bcc72..98a9871 100644
--- a/pylib/mapit/areas/models.py
+++ b/pylib/mapit/areas/models.py
@@ -190,6 +190,7 @@ class Area(models.Model):
             ('NFY', 'Norway Fylke'),
             ('NKO', 'Norway Kommune'),
         )),
+        ('PRA', 'Public Roads Administration'),
     ))
     country = models.CharField(max_length=1, choices=(
         ('E', 'England'),
diff --git a/pylib/mapit/templates/no/index.html b/pylib/mapit/templates/no/index.html
index 284c166..0819575 100644
--- a/pylib/mapit/templates/no/index.html
+++ b/pylib/mapit/templates/no/index.html
@@ -77,7 +77,7 @@ information you would get from single geometry calls.
 <li>/areas/<i>[type OR types]</i> &ndash; all the areas in a specific area type
 or types (separated by commas). You may specific a minimum generation with the
 min_generation parameter. The current list of types is: 
-<small>NKO (kommune), NFY (fylke)</small>.
+<small>NKO (kommune), NFY (fylke), PRA (vegvesenregion)</small>.
 <a href="/areas/NKO.html">Example kommune lookup</a>.
 
 <li>/areas/<i>[name]</i> &ndash; all areas that start with the specified text. You
--- /dev/null	2011-03-02 15:23:05.503124221 +0100
+++ pylib/mapit/areas/management/commands/import_area_unions.py	2011-04-02 21:37:03.000000000 +0200
@@ -0,0 +1,106 @@
+# import_area_unions.py:
+# This script is used to import regions (combinations of existing
+# areas into a new area) into MaPit.
+#
+# Copyright (c) 2011 Petter Reinholdtsen.  Some rights reserved using
+# the GPL.  Based on import_norway_osm.py by Matthew Somerville
+
+import csv
+import sys
+import re
+from optparse import make_option
+from django.core.management.base import LabelCommand
+from django.contrib.gis.gdal import *
+from django.contrib.gis.geos import GEOSGeometry
+from mapit.areas.models import Area, Generation, Geometry
+from utils import save_polygons
+
+# CVS format is
+# ID;code;name;area1,area2,...;other;fields
+
+class Command(LabelCommand):
+    help = 'Import region data'
+    args = '<CSV file listing name and which existing areas to combine into regions>'
+    option_list = LabelCommand.option_list + (
+        make_option('--commit', action='store_true', dest='commit', help='Actually update the database'),
+    )
+
+    def handle_label(self, filename, **options):
+        current_generation = Generation.objects.current()
+        new_generation = Generation.objects.new()
+        if not new_generation:
+            new_generation = current_generation
+#            raise Exception, "No new generation to be used for import!"
+
+        print filename
+
+        csv.register_dialect('semicolon', delimiter = ';')
+        region_line = csv.reader(open(filename), dialect='semicolon')
+        # FIXME: Need to skip comments starting with '#'
+        for regionid, area_type, regionname, area_names, email in region_line:
+            print "Building region '%s'" % regionname
+            if area_names:
+                # Look up areas using the names, find their geometry
+                # and build a geometric union to set as the geometry
+                # of the region.
+                geometry = None
+                for name in area_names.split(','):
+                    name.strip()
+                    name.lstrip()
+                    print "Looking up name '%s'" % name
+
+                    args = {
+                        'name__iexact': name,
+                        'generation_low__lte': current_generation,
+                        'generation_high__gte': new_generation,
+                        }
+                    area_id = Area.objects.filter(**args).only('id')
+                    try:
+                        print "ID:", area_id[0].id
+                        args = {
+                            'area__exact': area_id[0].id,
+#                            'generation_low__lte': current_generation,
+#                            'generation_high__gte': new_generation,
+                            }
+                        if geometry:
+                            geometry = geometry | Geometry.objects.filter(**args)
+                        else:
+                            geometry = Geometry.objects.filter(**args)
+                    except:
+                        print sys.exc_info()[0]
+                        raise
+#                        raise Exception, "Area with name %s was not found!" % name
+
+# Alternative idea from Matthew:
+# i think you want to construct a Geometry GeoQuerySet of all the area
+# ids that match and then use unionagg() on that?
+                    unionoutline = geometry.unionagg()
+
+                def update_or_create():
+                    country = 'O' # Norway
+                    try:
+                        m = Area.objects.get(id=regionid)
+                    except Area.DoesNotExist:
+                        m = Area(
+                            id = regionid,
+                            name = regionname,
+                            type = area_type,
+                            country = country,
+                            generation_low = new_generation,
+                            generation_high = new_generation,
+                            )
+
+                    if m.generation_high and current_generation \
+                            and m.generation_high.id < current_generation.id:
+                        raise Exception, "Area %s found, but not in current generation %s" % (m, current_generation)
+                    m.generation_high = new_generation
+
+                    g =GEOSGeometry( unionoutline).ogr
+                    poly = [ g ]
+                    if options['commit']:
+                        m.save()
+                        save_polygons({ regionid : (m, poly) })
+
+                update_or_create()
+            else:
+                raise Exception, "No area names found for region with name %s!" % regionname


More information about the fiksgatami mailing list