forked from topojson/topojson
-
Notifications
You must be signed in to change notification settings - Fork 7
/
topojson.py
112 lines (89 loc) · 3.42 KB
/
topojson.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
""" topojson.py
Functions that extract GeoJSON-ish data structures from TopoJSON
(https://github.com/mbostock/topojson) topology data.
Author: Sean Gillies (https://github.com/sgillies)
"""
from itertools import chain
def rel2abs(arc, scale=None, translate=None):
"""Yields absolute coordinate tuples from a delta-encoded arc.
If either the scale or translate parameter evaluate to False, yield the
arc coordinates with no transformation."""
if scale and translate:
a, b = 0, 0
for ax, bx in arc:
a += ax
b += bx
yield scale[0]*a + translate[0], scale[1]*b + translate[1]
else:
for x, y in arc:
yield x, y
def coordinates(arcs, topology_arcs, scale=None, translate=None):
"""Return GeoJSON coordinates for the sequence(s) of arcs.
The arcs parameter may be a sequence of ints, each the index of a
coordinate sequence within topology_arcs
within the entire topology -- describing a line string, a sequence of
such sequences -- describing a polygon, or a sequence of polygon arcs.
The topology_arcs parameter is a list of the shared, absolute or
delta-encoded arcs in the dataset.
The scale and translate parameters are used to convert from delta-encoded
to absolute coordinates. They are 2-tuples and are usually provided by
a TopoJSON dataset.
"""
if isinstance(arcs[0], int):
coords = [
list(
rel2abs(
topology_arcs[arc if arc >= 0 else ~arc],
scale,
translate )
)[::arc >= 0 or -1][i > 0:] \
for i, arc in enumerate(arcs) ]
return list(chain.from_iterable(coords))
elif isinstance(arcs[0], (list, tuple)):
return list(
coordinates(arc, topology_arcs, scale, translate) for arc in arcs)
else:
raise ValueError("Invalid input %s", arcs)
def geometry(obj, topology_arcs, scale=None, translate=None):
"""Converts a topology object to a geometry object.
The topology object is a dict with 'type' and 'arcs' items, such as
{'type': "LineString", 'arcs': [0, 1, 2]}.
See the coordinates() function for a description of the other three
parameters.
"""
return {
"type": obj['type'],
"coordinates": coordinates(
obj['arcs'], topology_arcs, scale, translate )}
if __name__ == "__main__":
# An example.
import json
import pprint
data = """{
"arcs": [
[[0, 0], [1, 0]],
[[1.0, 0.0], [0.0, 1.0]],
[[0.0, 1.0], [0.0, 0.0]],
[[1.0, 0.0], [1.0, 1.0]],
[[1.0, 1.0], [0.0, 1.0]]
],
"transform": {
"scale": [0.035896033450880604, 0.005251163636665131],
"translate": [-179.14350338367416, 18.906117143691233]
},
"objects": [
{"type": "Polygon", "arcs": [[0, 1, 2]]},
{"type": "Polygon", "arcs": [[3, 4, 1]]}
]
}"""
topology = json.loads(data)
scale = topology['transform']['scale']
translate = topology['transform']['translate']
p = geometry({'type': "LineString", 'arcs': [0]}, topology['arcs'])
pprint.pprint(p)
q = geometry({'type': "LineString", 'arcs': [0, 1]}, topology['arcs'])
pprint.pprint(q)
r = geometry(topology['objects'][0], topology['arcs'])
pprint.pprint(r)
s = geometry(topology['objects'][1], topology['arcs'], scale, translate)
pprint.pprint(s)