Skip to content

Commit 3f63bd9

Browse files
committed
lib/kmlread: provide alternate interface for reading KML
1 parent 18e642f commit 3f63bd9

File tree

1 file changed

+123
-8
lines changed

1 file changed

+123
-8
lines changed

Diff for: MAVProxy/modules/lib/kmlread.py

+123-8
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,28 @@
99
from io import BytesIO as SIO
1010
from zipfile import ZipFile
1111
import pathlib
12+
import re
1213

1314
namespaces = {'kml': 'http://www.opengis.net/kml/2.2'}
1415

1516

17+
class Style():
18+
def __init__(self, id):
19+
self.id = id
20+
self.line_colour = None
21+
22+
23+
class StyleMap():
24+
def __init__(self, id, otherstyle):
25+
self.id = id
26+
self.otherstyle = otherstyle
27+
28+
1629
class Polygon():
17-
def __init__(self, name, latlon):
30+
def __init__(self, name, latlon, line_colour=None):
1831
self.name = name
1932
self.vertexes = latlon
33+
self.line_colour = line_colour
2034

2135

2236
class Point():
@@ -27,6 +41,15 @@ def __init__(self, name, latlon):
2741

2842
def readkmz(filename):
2943
'''reads in a kmz file and returns xml nodes'''
44+
xpath = xpath = ".//kml:Placemark"
45+
46+
tree = etree_for_filepath(filename)
47+
48+
return tree.findall(xpath, namespaces)
49+
50+
51+
def etree_for_filepath(filename):
52+
'''reads in a kmz file and returns lxml.etree.ElementTree'''
3053
# Strip quotation marks if neccessary
3154
filename.strip('"')
3255
# Open the zip file (as applicable)
@@ -48,10 +71,7 @@ def readkmz(filename):
4871
raise Exception(f"load expects a .kml or .kmz file, got ({suffix}) from ({filename})")
4972

5073
parser = etree.XMLParser(encoding='utf-8', recover=True)
51-
tree = etree.parse(SIO(fstring), parser)
52-
xpath = xpath = ".//kml:Placemark"
53-
54-
return tree.findall(xpath, namespaces)
74+
return etree.parse(SIO(fstring), parser)
5575

5676

5777
def find_tag(node, tagname):
@@ -92,13 +112,108 @@ def readObject(innode):
92112
for c in coordinates.text.split():
93113
s = c.split(',')
94114
latlon.append((float(s[1]), float(s[0])))
115+
95116
return Polygon(name.text, latlon)
96117

97118
return ('Unknown', None, None)
98119

99120

121+
class KMLRead():
122+
def __init__(self, filepath):
123+
self.filepath = filepath
124+
125+
def placemark_nodes(self):
126+
return self.tree.findall(".//kml:Placemark", namespaces)
127+
128+
def readObject(self, innode):
129+
'''reads in a node and returns as a tuple: (type, name, points[])'''
130+
# get name
131+
name = find_tag(innode, 'name')
132+
if name is None:
133+
return None
134+
point = find_tag(innode, 'Point')
135+
if point is not None:
136+
coordinates = find_tag(point, 'coordinates')
137+
if coordinates is None:
138+
return None
139+
s = coordinates.text.split(',')
140+
return Point(name.text, (float(s[1]), float(s[0])))
141+
142+
coordinates = find_tag_recursive(innode, 'coordinates')
143+
if coordinates is not None:
144+
# a Polygon
145+
latlon = []
146+
for c in coordinates.text.split():
147+
s = c.split(',')
148+
latlon.append((float(s[1]), float(s[0])))
149+
150+
styleURL = find_tag_recursive(innode, 'styleUrl')
151+
line_colour = None
152+
if styleURL is not None:
153+
styleurl_name = styleURL.text.lstrip('#')
154+
if styleurl_name in self.stylemap:
155+
stylemap = self.stylemap[styleurl_name]
156+
otherstyle = stylemap.otherstyle
157+
if otherstyle in self.style:
158+
style = self.style[otherstyle]
159+
line_colour = style.line_colour
160+
161+
return Polygon(name.text, latlon, line_colour=line_colour)
162+
163+
return ('Unknown', None, None)
164+
165+
def parse(self):
166+
self.tree = etree_for_filepath(self.filepath)
167+
168+
# extract styles:
169+
self.style = {}
170+
for s in self.tree.findall(".//kml:Style", namespaces):
171+
_id = s.get("id")
172+
style = Style(_id)
173+
self.style[_id] = style
174+
line_style = find_tag_recursive(s, 'LineStyle')
175+
if line_style is None:
176+
continue
177+
colour = find_tag_recursive(line_style, 'color')
178+
g = re.match("(?P<alpha>..)(?P<r>..)(?P<g>..)(?P<b>..)", colour.text)
179+
if g is None:
180+
continue
181+
style.line_colour = (
182+
int(g.group("r"), 16),
183+
int(g.group("g"), 16),
184+
int(g.group("b"), 16)
185+
)
186+
187+
# extract stylemaps:
188+
self.stylemap = {}
189+
for s in self.tree.findall(".//kml:StyleMap", namespaces):
190+
_id = s.get("id")
191+
styleurl_obj = None
192+
for pair in s.getchildren():
193+
if pair is None:
194+
continue
195+
if find_tag_recursive(pair, "key").text == "normal":
196+
styleurl_obj = find_tag_recursive(pair, "styleUrl")
197+
if styleurl_obj is not None:
198+
break
199+
break
200+
201+
if styleurl_obj is None:
202+
continue
203+
stylemap = StyleMap(_id, styleurl_obj.text.lstrip('#'))
204+
self.stylemap[_id] = stylemap
205+
206+
100207
if __name__ == '__main__':
101208
import sys
102-
nodes = readkmz(sys.argv[1])
103-
for n in nodes:
104-
print(readObject(n))
209+
210+
kml = KMLRead(sys.argv[1])
211+
kml.parse()
212+
213+
for n in kml.placemark_nodes():
214+
obj = kml.readObject(n)
215+
if obj is None:
216+
continue
217+
218+
# for n in readkmz(sys.argv[1]):
219+
# print(readObject(n))

0 commit comments

Comments
 (0)