-
Notifications
You must be signed in to change notification settings - Fork 49
/
generate_shapefile_countries.py
210 lines (171 loc) · 6.01 KB
/
generate_shapefile_countries.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# -*- coding: utf-8 -*-
import os
import shutil
import zipfile
import shapefile
from django.conf import settings
from django.core.management.base import BaseCommand
from django.contrib.gis.geos import Polygon
from django.forms.models import fields_for_model
from localities.models import Country
from localities_osm.models.locality import LocalityOSM, LocalityOSMView # noqa
from localities_osm.queries import filter_locality
directory_cache = settings.CACHE_DIR
directory_media = settings.SHAPEFILE_DIR
def zipdir(path, ziph):
# ziph is zipfile handle
abs_src = os.path.abspath(path)
for root, dirs, files in os.walk(path):
for file in files:
absname = os.path.abspath(os.path.join(root, file))
arcname = absname[len(abs_src) + 1:]
ziph.write(absname, arcname)
# funtion to generate a .prj file
def getWKT_PRJ(epsg_code):
import urllib
wkt = \
urllib.urlopen(
'http://spatialreference.org/ref/epsg/{0}/prettywkt/'.format(
epsg_code))
remove_spaces = wkt.read().replace(' ', '')
output = remove_spaces.replace('\n', '')
return output
def get_shapefile_folder(counter_name):
""" Return shapefile folder for a country"""
shp_filename = counter_name.replace('.', '')
return os.path.join(directory_cache, 'shapefiles', shp_filename)
def country_data_into_shapefile(country=None):
""" Convert country osm data into shapefile
:param country: Country name
:type: str
"""
if country == 'World' or country == 'world':
country = None
queryset = filter_locality(
extent=None,
country=country).order_by('row')
country_name = 'World'
if country:
country_name = country
# get field that needs to be saved
fields = fields_for_model(LocalityOSM).keys()
# get the folders
shp_filename = country_name.replace('.', '')
dir_cache = get_shapefile_folder(country_name)
dir_shapefile = os.path.join(dir_cache, 'output')
# delete the cache
try:
shutil.rmtree(dir_shapefile)
except OSError:
pass
# generate the node shapefile
insert_to_shapefile(
query=queryset.filter(osm_type=LocalityOSMView.NODE),
fields=fields,
dir_shapefile=dir_shapefile,
shp_filename=u'{}-node'.format(shp_filename),
TYPE=shapefile.POINT)
# generate the way shapefile
insert_to_shapefile(
query=queryset.filter(osm_type=LocalityOSMView.WAY),
fields=fields,
dir_shapefile=dir_shapefile,
shp_filename=u'{}-way'.format(shp_filename),
TYPE=shapefile.POLYGON)
# zip this output
print 'rezipping the files'
if not os.path.exists(directory_media):
os.makedirs(directory_media)
filename = os.path.join(directory_media, '%s.zip' % country_name)
try:
os.remove(filename)
except OSError:
pass
zipf = zipfile.ZipFile(filename, 'w', allowZip64=True)
zipdir(dir_shapefile, zipf)
zipf.close()
try:
shutil.rmtree(dir_cache)
except OSError:
pass
def insert_to_shapefile(query, fields, dir_shapefile, shp_filename, TYPE):
""" Convert and insert data into shapefile
"""
from localities_osm.serializer.locality_osm import (
LocalityOSMGeoSerializer
)
# Insert data into shapefile
print 'generating shape object for ' + shp_filename
shapefile_output = os.path.join(dir_shapefile, shp_filename)
shp = shapefile.Writer(shapefile_output, TYPE)
for field in fields:
shp.field(str(field), 'C', 100)
# insert data
for healthsite_obj in query:
values = []
healthsite = LocalityOSMGeoSerializer(healthsite_obj).data
properties = healthsite['properties']
if not properties['centroid'] or not properties['centroid']['coordinates']:
continue
for field in fields:
value = ''
if field in properties['attributes']:
value = properties['attributes'][field]
elif field in properties:
value = properties[field]
try:
value = str(value.encode('utf8'))
except AttributeError:
pass
values.append(value)
if not values:
continue
if TYPE == shapefile.POINT:
shp.point(
properties['centroid']['coordinates'][0],
properties['centroid']['coordinates'][1])
elif TYPE == shapefile.POLYGON:
coordinates = healthsite['geometry']['coordinates']
if isinstance(healthsite_obj.geometry, Polygon):
shp.poly(coordinates)
else:
shp.poly(coordinates[0])
shp.record(*values)
shp.close()
# create .cpg
cpg_file = os.path.join(dir_shapefile, shp_filename + '.cpg')
file = open(cpg_file, 'w+')
file.write('UTF-8')
file.close()
# create .prj
prj_file = os.path.join(dir_shapefile, shp_filename + '.prj')
prj = open(prj_file, 'w+')
epsg = getWKT_PRJ('4326')
prj.write(epsg)
prj.close()
class Command(BaseCommand):
help = 'generate shapefile for data in bulk'
def add_arguments(self, parser):
parser.add_argument(
'--country',
help='country name',
)
def handle(self, *args, **options):
country = options.get('country', None)
# generate shapefiles for world
if not country or country.lower() == 'world':
try:
country_data_into_shapefile('')
except Exception as e:
print '{}'.format(e)
# generate shapefiles for countries
countries = Country.objects.all()
if country:
countries = countries.filter(name__iexact=country)
countries = countries.order_by('name')
for country in countries:
# generate shapefiles for country
try:
country_data_into_shapefile(country.name)
except Exception as e:
print '{}'.format(e)