[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> – 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> – 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