-
Notifications
You must be signed in to change notification settings - Fork 1
/
shp2svg.py
196 lines (159 loc) · 7.06 KB
/
shp2svg.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
import os
import shapefile
class SvgLooper:
def __init__(self, in_path, out_path, pixels_size):
self.files = []
self.in_path = os.path.realpath(in_path)
self.out_path = out_path
self.pixels_size = pixels_size
self.generator = SvgGenerator(out_path, pixels_size)
def setFilesListed(self):
for file in os.listdir(self.in_path):
if '.shp' in file:
self.files.append(os.path.join(self.in_path, file))
def run(self, id_field):
for file in self.files:
self.generator.run(file, id_field)
def setup(self):
self.setFilesListed()
print self.generator.printFields(self.files[0])
class SvgGenerator:
def __init__(self, out_path, width_pixels):
self.out_path = os.path.realpath(out_path)
self.width_pixels = width_pixels
def writeToFile(self, ofile, svg):
svg_filename = ofile.split('.')[0] + '.svg'
output = svg
file = open(svg_filename, "wb")
for line in output:
file.write(line.encode('utf-8'))
file.close()
print 'SVG generated: ' + svg_filename
def printFields(self, ifile):
fieldsList = []
layer = shapefile.Reader(ifile)
for field in layer.fields:
if type(field) is tuple:
continue
else:
fieldsList.append(field[0])
print
print fieldsList
print
def feature2svg(self, feature, field_num, layer_extent, mupp):
geom = feature[1]
id = self.sanitizeStr(unicode(feature[0][field_num], 'utf-8').lower())
svgGroup = [u'<g id="' + id + '">\n']
if len(geom.parts) == 1:
svgGroup.extend(self.polygon2path(geom, layer_extent, mupp))
elif len(geom.parts) > 1:
svgGroup.extend(self.multiPolygon2path(geom, layer_extent, mupp))
else:
pass
svgGroup.append('</g>\n')
return svgGroup
def multiPolygon2path(self, geom, layer_extent, mupp):
svgPolygon = []
geom.parts.append(len(geom.points))
poly_list = []
parts_counter = 0
while parts_counter < len(geom.parts) - 1:
coord_count = geom.parts[parts_counter]
no_of_points = abs(geom.parts[parts_counter] - geom.parts[parts_counter + 1])
part_list = []
end_point = coord_count + no_of_points
while coord_count < end_point:
for coords in geom.points[coord_count:end_point]:
x, y = coords[0], coords[1]
poly_coord = [float(x), float(y)]
part_list.append(poly_coord)
coord_count = coord_count + 1
poly_list.append(part_list)
parts_counter = parts_counter + 1
for ring in poly_list:
svgPath = '<path d="M '
last_pixel = [0, 0]
coordCount = 0
for latLng in ring:
x, y = latLng[0], latLng[1]
if layer_extent[0] > 0 and layer_extent[2] > 0 or layer_extent[0] > 0 and layer_extent[2] > 0:
pixpoint = self.w2p(x, y, abs(layer_extent[0] - layer_extent[2]) / mupp, layer_extent[0],
layer_extent[3])
else:
pixpoint = self.w2p(x, y, (abs(layer_extent[0]) + abs(layer_extent[2])) / mupp, layer_extent[0],
layer_extent[3])
if last_pixel <> pixpoint:
coordCount += 1
if coordCount > 1:
svgPath += 'L '
svgPath += (str(pixpoint[0]) + ',' + str(pixpoint[1]) + ' ')
last_pixel = pixpoint
if coordCount > 2:
svgPath += '" />\n'
svgPolygon.extend([svgPath])
return svgPolygon
def polygon2path(self, geom, layer_extent, mupp):
svgPolygon = []
svgPath = '<path d="M '
last_pixel = [0, 0]
coordCount = 0
for latLng in geom.points:
x, y = latLng[0], latLng[1]
if layer_extent[0] > 0 and layer_extent[2] > 0 or layer_extent[0] > 0 and layer_extent[2] > 0:
xExtension = abs(layer_extent[0] - layer_extent[2])
yExtension = abs(layer_extent[1]) + abs(layer_extent[3])
pixpoint = self.w2p(x, y, abs(layer_extent[0] - layer_extent[2]) / mupp, layer_extent[0], layer_extent[3])
else:
xExtension = abs(layer_extent[0]) + abs(layer_extent[2])
yExtension = abs(layer_extent[1]) + abs(layer_extent[3])
pixpoint = self.w2p(x, y, (abs(layer_extent[0]) + abs(layer_extent[2])) / mupp, layer_extent[0],
layer_extent[3])
if last_pixel <> pixpoint:
coordCount += 1
if coordCount > 1:
svgPath += 'L '
svgPath += (str(pixpoint[0]) + ',' + str(pixpoint[1]) + ' ')
last_pixel = pixpoint
if coordCount > 2:
svgPath += '" />\n'
svgPolygon.extend([svgPath])
return svgPolygon
def w2p(self, x, y, mupp, minx, maxy):
pix_x = (x - minx) / mupp
pix_y = (y - maxy) / mupp
return [round(float(pix_x), 1), round(float(-pix_y), 1)]
def sanitizeStr(self, string):
return string.replace(' ', '_').replace('/', '_').replace(',', '_').replace('.', '_').replace('-', '_')
def run(self, in_file, id_name):
# Definim les variables d'entrada per al proces
layer = shapefile.Reader(in_file)
out_file = os.path.join(self.out_path, os.path.basename(in_file))
field_name = id_name
count_fields = 0
field_num = 0
mupp = self.width_pixels
for field in layer.fields:
if type(field) is tuple:
continue
else:
if field[0] == field_name:
field_num = count_fields
else:
count_fields += 1
# Generant la bounding box del shapefile i convertint-la en variable
layer_extent = layer.bbox
boxConstructor = shapefile.Writer(shapefile.POLYGON)
boxConstructor.poly(parts=[[[layer_extent[0], layer_extent[1]], [layer_extent[2], layer_extent[3]]]])
# Generant la llista de fields i geometries asociades per a cada element grafic del shapefile
records = layer.records()
shapes = layer.shapes()
features = zip(records, shapes)
# Escrivint les capsaleres de l'arxiu SVG
svg = [u'<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n']
svg.append(
u'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n')
svg.append(u'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">\n')
for feature in features:
svg.extend(self.feature2svg(feature, field_num, layer_extent, mupp))
svg.append(u'</svg>')
self.writeToFile(out_file, svg)