-
Notifications
You must be signed in to change notification settings - Fork 0
/
boundary_check.py
119 lines (98 loc) · 3.56 KB
/
boundary_check.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
import os
import errno
import re
import shutil
from copy import deepcopy
import fiona
from shapely.geometry import mapping, shape
from osgeo import ogr, osr
class BoundaryCheck:
def __init__(self, path):
self.path = path
src = fiona.open(self.path)
self.src_driver = src.driver
self.src_crs = src.crs
self.src_schema = src.schema
# self.shps = deepcopy(src)
self.shps = src
def make_dir(self, path):
try:
os.makedirs(path)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
def projection_check(self):
error = None
driver = ogr.GetDriverByName('ESRI Shapefile')
dataset = driver.Open(self.path)
layer = dataset.GetLayer()
inSpatialRef = layer.GetSpatialRef()
sr = osr.SpatialReference(str(inSpatialRef))
# should be `None` when WGS84/EPSG:4326
projection = sr.GetAttrValue('PROJCS')
geogcs = sr.GetAttrValue('GEOGCS')
geogcs = re.sub(' ', '', geogcs)
geogcs_passlist = ['GCS_WGS_1984', 'WGS84']
valid = (projection is None) and (geogcs in geogcs_passlist)
if not valid:
if projection is not None and geogcs not in geogcs_passlist:
error = "geogcs: {0}, projection: {1}".format(geogcs, projection)
elif projection is not None:
error = "projection: {0}".format(projection)
else:
error = "geogcs: {0}".format(geogcs)
return valid, error
def boundary_check(self):
error = None
# tolerance
tol = 1e-12
xmin, ymin, xmax, ymax = self.shps.bounds
valid = (xmin >= -180-tol) and (xmax <= 180+tol) and (ymin >= -90-tol) and (ymax <= 90+tol)
if not valid:
error = "xmin: {0}, xmax: {1}, ymin: {2}, ymax: {3}".format(xmin, xmax, ymin, ymax)
return valid, error
def _save_shapely_fixes(self, shapes):
fix_path = self.path.replace("extract", "fixed")
fix_dir = os.path.dirname(fix_path)
self.make_dir(fix_dir)
with fiona.open(fix_path, 'w', driver=self.src_driver, crs=self.src_crs, schema=self.src_schema) as c:
c.writerecords(shapes)
shutil.make_archive(fix_dir, "zip", fix_dir)
shutil.rmtree(fix_dir)
def shapely_check(self):
valid = True
error = None
fixed = []
for feature in self.shps:
raw_shape = shape(feature['geometry'])
valid = raw_shape.is_valid
if valid:
fixed.append(feature)
if not valid:
fixed_shape = raw_shape.buffer(0)
fix_valid = fixed_shape.is_valid
if fix_valid and error is None:
error = "fixable"
feature["geometry"] = mapping(fixed_shape)
fixed.append(feature)
elif not fix_valid:
if error is not None:
error = "partial"
else:
error = "failed"
break
if error == "fixable":
self._save_shapely_fixes(fixed)
return valid, error
def mongo_check(self, c_features):
valid = True
error = None
for feature in self.shps:
geom = feature['geometry']
try:
c_features.insert(geom)
except Exception as e:
error = e
valid = False
break
return valid, error