-
Notifications
You must be signed in to change notification settings - Fork 1
/
mappyfile_geojson.py
111 lines (83 loc) · 3.1 KB
/
mappyfile_geojson.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
from collections import OrderedDict
__version__ = "1.0.0"
def explode(coords):
"""
From https://gist.github.com/sgillies/3975665
Explode a GeoJSON geometry's coordinates object and yield
coordinate tuples. As long as the input is conforming,
the type of the geometry doesn't matter.
"""
for e in coords:
if isinstance(e, (float, int)):
yield coords[:2] # strip out any Z values from the coords
break
else:
for f in explode(e):
yield f
def bbox(f):
x, y = zip(*list(explode(f.geometry.coordinates)))
return min(x), min(y), max(x), max(y)
def get_extent(features, buffer=0):
extents = [bbox(f) for f in features]
all_extents = list(zip(*extents))
full_extent = (
min(all_extents[0]) - buffer,
min(all_extents[1]) - buffer,
max(all_extents[2]) + buffer,
max(all_extents[3]) + buffer,
)
# use integers if floats have no precision e.g. use 5 for 5.0
full_extent = (
int(c) if isinstance(c, float) and c.is_integer() else c for c in full_extent
)
return list(full_extent)
def create_inline_feature(feat, props):
geom = feat.geometry
f = OrderedDict()
f["__type__"] = "feature"
coords = geom.coordinates
if geom.type == "Point":
coords = [coords] # put coords in an outer list
elif geom.type == "MultiPolygon":
coords = [c[0] for c in coords] # remove one layer of list nesting
f["points"] = coords
# note items use semicolons and not commas as used elsewhere
values = [str(feat.properties[p]) for p in props]
f["items"] = ";".join(values)
return f
def get_features(gj):
if gj.type == "FeatureCollection":
features = gj.features
elif gj.type == "Feature":
features = [gj]
return features
def create_layer(features, bbox):
first_feature = features[0]
# properties will be an unsorted dict, so
# sort to ensure consistency
props = sorted(first_feature.properties.keys())
geom_type = first_feature.geometry.type
mapfile_features = [create_inline_feature(f, props) for f in features]
layer = OrderedDict()
layer["__type__"] = "layer"
layer["extent"] = bbox
layer["status"] = "on"
if geom_type in ("LineString", "MultiLineString"):
layer_type = "line"
elif geom_type in ("Point", "MultiPoint"):
layer_type = "point"
elif geom_type in ("Polygon", "MultiPolygon"):
layer_type = "polygon"
else:
msg = "The geometry type {} is not yet implemented".format(geom_type)
raise NotImplementedError(msg)
# layer type must be set before adding inline features!!
layer["type"] = layer_type
layer["processing"] = ["ITEMS={}".format(",".join(props))]
layer["features"] = mapfile_features
return layer
def convert(gj, extent_buffer=0):
features = get_features(gj)
bbox = get_extent(features, buffer=extent_buffer)
layer = create_layer(features, bbox)
return layer