aboutsummaryrefslogtreecommitdiff
path: root/src/kml_utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/kml_utils.py')
-rw-r--r--src/kml_utils.py80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/kml_utils.py b/src/kml_utils.py
new file mode 100644
index 0000000..70319f8
--- /dev/null
+++ b/src/kml_utils.py
@@ -0,0 +1,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)