Skip to content

Instantly share code, notes, and snippets.

@slinkp
Created December 10, 2010 18:16
Show Gist options
  • Save slinkp/736549 to your computer and use it in GitHub Desktop.
Save slinkp/736549 to your computer and use it in GitHub Desktop.
import re
import string
import sys
import optparse
from django.contrib.gis.gdal import DataSource
from ebpub.metros.models import Metro
from ebpub.streets.models import Block
from ebpub.streets.name_utils import make_pretty_name
from ebpub.utils.text import slugify
FIELD_MAP = {
# ESRI # Block
'LEFT_FROM' : 'left_from_num',
'LEFT_TO' : 'left_to_num',
'RIGHT_FROM' : 'right_from_num',
'RIGHT_TO' : 'right_to_num',
# 'POSTAL_L' : 'left_zip',
# 'POSTAL_R' : 'right_zip',
# 'GEONAME_L' : 'left_city',
# 'GEONAME_R' : 'right_city',
# 'STATE_L' : 'left_state',
# 'STATE_R' : 'right_state',
}
NAME_FIELD_MAP = {
'RD_NAME' : 'street',
'RD_SUFFIX' : 'suffix',
# 'RD_PREFIX' : 'predir',
'RD_DIRECTI' : 'postdir',
}
# FCC == feature classification code: indicates the type of road
VALID_FCC_PREFIXES = (
'A1', # primary highway with limited access
'A2', # primary road without limited access
'A3', # secondary and connecting road
'A4' # local, neighborhood, and rural road
)
ENCODING = 'cp1252'
print >> sys.stderr, 'Starting block importer.'
class EsriImporter(object):
def __init__(self, shapefile, city=None, layer_id=0):
print >> sys.stderr, 'Opening %s' % shapefile
ds = DataSource(shapefile)
self.layer = ds[layer_id]
self.city = "OTTAWA" #city and city or Metro.objects.get_current().name
self.fcc_pat = re.compile('^(' + '|'.join(VALID_FCC_PREFIXES) + ')\d$')
def save(self, verbose=False):
alt_names_suff = (u'',)
num_created = 0
for i, feature in enumerate(self.layer):
#if not self.fcc_pat.search(feature.get('FCC')):
# continue
parent_id = None
fields = {}
for esri_fieldname, block_fieldname in FIELD_MAP.items():
value = feature.get(esri_fieldname)
#print >> sys.stderr, 'Looking at %s' % esri_fieldname
if isinstance(value, basestring):
value = value.upper()
elif isinstance(value, int) and value == 0:
value = None
fields[block_fieldname] = value
if not ((fields['left_from_num'] and fields['left_to_num']) or
(fields['right_from_num'] and fields['right_to_num'])):
continue
# Sometimes the "from" number is greater than the "to"
# number in the source data, so we swap them into proper
# ordering
for side in ('left', 'right'):
from_key, to_key = '%s_from_num' % side, '%s_to_num' % side
if fields[from_key] > fields[to_key]:
fields[from_key], fields[to_key] = fields[to_key], fields[from_key]
if feature.geom.geom_name != 'LINESTRING':
continue
for suffix in alt_names_suff:
name_fields = {}
for esri_fieldname, block_fieldname in NAME_FIELD_MAP.items():
key = esri_fieldname + suffix
name_fields[block_fieldname] = feature.get(key).upper()
#if block_fieldname == 'postdir':
#print >> sys.stderr, 'Postdir block %s' % name_fields[block_fieldname]
if not name_fields['street']:
continue
# Skip blocks with bare number street names and no suffix / type
if not name_fields['suffix'] and re.search('^\d+$', name_fields['street']):
continue
fields.update(name_fields)
for key, val in fields.items():
if isinstance(val, str):
fields[key] = val.decode(ENCODING)
fields['street_pretty_name'], fields['pretty_name'] = make_pretty_name(
fields['left_from_num'],
fields['left_to_num'],
fields['right_from_num'],
fields['right_to_num'],
u'',
fields['street'],
fields['suffix'],
fields['postdir'],
)
#print >> sys.stderr, 'Looking at block pretty name %s' % fields['street']
fields['street_slug'] = slugify(u' '.join((fields['street'], fields['suffix'])))
# Watch out for addresses like '247B' which can't be
# saved as an IntegerField.
for addr_key in ('left_from_num', 'left_to_num', 'right_from_num', 'right_to_num'):
fields[addr_key] = fields[addr_key].rstrip(string.letters)
block = Block(**fields)
block.geom = feature.geom.geos
print >> sys.stderr, u'Looking at block %s' % fields['street']
block.save()
if parent_id is None:
parent_id = block.id
else:
block.parent_id = parent_id
block.save()
num_created += 1
#if verbose:
print >> sys.stderr, 'Created block %s' % block
return num_created
def main(argv=None):
if argv is None:
argv = sys.argv[1:]
parser = optparse.OptionParser(usage='%prog edges.shp')
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False)
parser.add_option('-c', '--city', dest='city', help='A city name to filter against')
(options, args) = parser.parse_args(argv)
if len(args) != 1:
return parser.error('must provide at least 1 arguments, see usage')
args.append(options.city)
args.append(options.verbose)
esri = EsriImporter(*args)
num_created = esri.save(options.verbose)
#if options.verbose:
# print "Created %d blocks" % num_created
if __name__ == '__main__':
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment