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
|
"""Shared helpers for building simple KML documents from polygon data."""
import xml.etree.ElementTree as ET
KML_NS = "http://www.opengis.net/kml/2.2"
ET.register_namespace("", KML_NS)
def new_document(name: str) -> tuple[ET.Element, ET.Element]:
"""Create a <kml><Document> pair and return (root, document).
Args:
name (str): Name of the document, shown as the map/layer title.
Returns:
tuple[ET.Element, ET.Element]: The root <kml> element and its child <Document> element.
"""
root = ET.Element("kml", xmlns=KML_NS)
document = ET.SubElement(root, "Document")
ET.SubElement(document, "name").text = name
return root, document
def add_placemark(document: ET.Element, name: str = "", description: str = "") -> ET.Element:
"""Add a <Placemark> to `document` and return it.
Args:
document (ET.Element): The <Document> element to attach the placemark to.
name (str, optional): Placemark name. Defaults to "".
description (str, optional): Placemark description. Defaults to "".
Returns:
ET.Element: The newly created <Placemark> element.
"""
placemark = ET.SubElement(document, "Placemark")
ET.SubElement(placemark, "name").text = name
ET.SubElement(placemark, "description").text = description
return placemark
def add_polygon(parent: ET.Element, ring: list[tuple[float, float]]) -> ET.Element:
"""Add a single-ring <Polygon> to `parent`.
Args:
parent (ET.Element): Element to attach the polygon to (a <Placemark> or <MultiGeometry>).
ring (list[tuple[float, float]]): Outer boundary points as (longitude, latitude) pairs.
Returns:
ET.Element: The newly created <Polygon> element.
"""
polygon = ET.SubElement(parent, "Polygon")
outer = ET.SubElement(polygon, "outerBoundaryIs")
linear_ring = ET.SubElement(outer, "LinearRing")
coordinates = ET.SubElement(linear_ring, "coordinates")
coordinates.text = "\n".join(f"{lon},{lat}" for lon, lat in ring)
return polygon
def add_multi_polygon(placemark: ET.Element, rings: list[list[tuple[float, float]]]) -> ET.Element:
"""Add a <MultiGeometry> made of one <Polygon> per ring to `placemark`.
Args:
placemark (ET.Element): The <Placemark> element to attach the geometry to.
rings (list[list[tuple[float, float]]]): One outer boundary ring per polygon.
Returns:
ET.Element: The newly created <MultiGeometry> element.
"""
multi_geometry = ET.SubElement(placemark, "MultiGeometry")
for ring in rings:
add_polygon(multi_geometry, ring)
return multi_geometry
def write_kml(root: ET.Element, output_file: str) -> None:
"""Indent and write a KML tree to `output_file`.
Args:
root (ET.Element): The root <kml> element to write.
output_file (str): Path to the output KML file.
"""
tree = ET.ElementTree(root)
ET.indent(tree)
tree.write(output_file, encoding="utf-8", xml_declaration=True)
|