Skip to main content

Module kml

Module kml 

Source
Expand description

KML files holding a GPS track, as AltOS, Missile Works’ RTx, Big Red Bee’s BeeLine, fw2kml, GPS Visualizer and others write a flight’s path for Google Earth.

KML (Keyhole Markup Language) is XML, standardized as OGC 07-147r2 (OGC KML, version 2.2.0, 2008). A flight’s path is a Placemark holding a geometry: a LineString, whose coordinates list one tuple per point, or Google’s extension gx:Track, which pairs each point’s when with its gx:coord:

<Placemark><name>Flight Track</name>
  <LineString><altitudeMode>absolute</altitudeMode>
    <coordinates>-97.10000,35.20000,402 -97.10001,35.20002,415</coordinates>
  </LineString>
</Placemark>
<Placemark><name>fw2kml - Flight 0</name>
  <gx:Track><altitudeMode>absolute</altitudeMode>
    <when>2026-05-23T10:15:00.000Z</when><gx:coord>-97.10000 35.20000 402.0</gx:coord>
  </gx:Track>
</Placemark>

What the standard sets. A tuple is longitude, latitude and an optional altitude, comma separated, tuples separated by whitespace (§16.9.1); degrees are WGS84’s, and “altitude is measured from the vertical datum, which is the WGS84 EGM96 Geoid” (§6.2), in meters (§16.1.1). How a viewer places the altitude is the geometry’s altitudeMode (§9.17, §16.1.1): absolute, “a value in meters relative to the vertical datum”; relativeToGround, “in meters relative to the terrain elevation”; clampToGround, the default, “ignore the altitude specification”. Google adds gx:altitudeMode’s relativeToSeaFloor and clampToSeaFloor, and gx:Track, whose “number of <when> elements … must be equal to the number of <gx:coord> elements”, each coordinate “three values for longitude, latitude, and altitude, with no comma separators” (Google, KML Reference, developers.google.com/kml/documentation/ kmlreference, <gx:Track>). A when is an XML Schema date-time (§15.3.3.1, §16.10.1), with Z for UTC or a ±hh:mm offset; one that states no zone is “the time in the timezone of some unspecified locality” (W3C, XML Schema Part 2, §3.2.7).

Tracks and channels. A KML file holds tracks of positions, not an altimeter’s record over time: even an altitude AltOS took from its barometer (below) is one value of a track’s points. So the record’s primary track is empty and every value is a channel, with a note, as the GPS logs’ decision, ADR-254 §2, has it. Each geometry, in the file’s order, inside a MultiGeometry too, is a track: each LineString, gx:Track and Point. A track’s channels are named after its Placemark’s name, or track if it has none; a placemark holding several geometries numbers them, <name> part 2, and a name already used gains (2), (3) …, so no two tracks share a name:

ChannelQuantityFrom
<name> latitude, <name> longitudeQuantity::Latitude, Quantity::Longitudethe tuple’s second and first numbers
<name> altitudeQuantity::GnssAltitude, mthe third number, in mode absolute
<name> altitudeQuantity::AltitudeMsl, mthe same, in an AltOS track whose altitude is the barometer’s (below)
<name> height above ground, <name> height above sea floorQuantity::Distance, mthe third number, in mode relativeToGround or relativeToSeaFloor: a height above the terrain, not above sea level
<name> altitudeQuantity::Unrecognized, as writtenthe third number, in a mode that tells a viewer to ignore it (clampToGround, clampToSeaFloor, or none stated), in a mode the standard doesn’t name, or from GPS Visualizer (below)
<name> GPS altitudeQuantity::GnssAltitude, mAltOS’s comment alt, where it differs from the tuple’s, in a file where it equals the tuple’s at some point
<name> GPS altitudeQuantity::Unrecognized, as writtenthe same, in a file where it equals the tuple’s at no point, so nothing in the file shows its unit
<name> AltQuantity::Unrecognized, as writtenthe Seconds layout’s Alt, where it differs from the tuple’s
<name> timeQuantity::Unrecognized, as writtenAltOS’s comment time, where its steps don’t show it is in seconds (below; none of the samples)
<name> satellitesQuantity::Numbera comment’s sats
<name> offsetQuantity::Numberthe BeeLine comment’s first number

A track whose tuples carry no altitude (a two-number tuple’s altitude is absent, not 0: the standard calls it optional) has no altitude channel. A Point is a track of one sample. A tuple that isn’t two or three numbers, or a latitude or longitude out of range, is a gap, NaN, counted in a note.

Times. A point’s time is the one the file gives it (ADR-254 §3): a gx:Track’s when; a Point placemark’s TimeStamp; or, where a writer puts a comment right after a tuple, the time in the comment. The log’s zero is the first point the file times, and a note names it. A point the file gives no time keeps its place with its time a gap, NaN (§4), as every point of a path without times does, with a note. Times stay in the file’s order; a note says how often and how far they go back. A Point with a time is also an Event named after its placemark. Times on two kinds of clock in one file (none of the samples) can’t share a zero: those not on the first timed point’s clock are gaps, with a note. A time of day that steps back by more than 12 h has passed midnight, and a day is added from there on, at most MAX_MIDNIGHTS times; the times of day after that are gaps, with a note.

Comments beside points. Three layouts are read, case aside:

  • AltOS: <!-- alt 1000.0000000 time 2.5000000 sats 6 -->: the GPS receiver’s altitude, a time and its satellite count.
  • <!-- Alt 250.0 Seconds 9.5 -->, in files styled after AltOS’s but not named by it.
  • Big Red Bee’s BeeLine: <!-- 1003 sats:8 UTC 12:34:56 -->: a number that steps by 15 a point, the record’s place in the logger’s memory as far as the files show, the satellite count, and the UTC time of day.

A comment is a point’s only if it follows the point’s tuple with nothing but whitespace between, and before the next tuple; other comments are counted in a note and not read, nor is their text quoted.

The writers, among the project’s sample logs. As of 2026-10-12, 43 distinct KML files:

  • fw2kml (14), the community converter of Featherweight GPS logs (a Rocketry Forum post, 2023-01-06; github.com/pirate21213/fw2kml): one Placemark named fw2kml - Flight N. 12 hold a LineString with no times; 2 a gx:Track with a when per point, in UTC to the tenth of a second, and a gx:Tour of camera views, which isn’t a track. One of the two is the same KML document four times over: a later document identical to the first is skipped with a note. A later document that differs (none of the samples) is read as more tracks, with a note, up to MAX_DOCUMENTS.
  • Missile Works’ RTx (12): document RTx/GPS Flight, KML 2.1’s namespace, a byte-order mark and CR LF; a Folder holding Flight Track, a path of whole meters with no times, and in 3 files a second path, Ground Track, the same positions with no altitude, clampToGround. The RTx’s manual says its GPS altitude “is always expressed as Mean Sea Level” (RTx User Manual, 2016-11-26, p13). In 10 of the 12, all from pads near sea level, the altitude reads exactly 0 for the first hundreds of points, and in none does it go below 0, as a receiver’s altitude clamped at sea level would; it is kept as written.
  • AltOS (11), AltosUI’s KML export (Altus Metrum, AltOS manual, §12.5.2): a document named AO Flight#N S/N: M, from which the flight number and serial number are read, and a comment beside every point. 7 files hold one GPS Altitude path, whose tuple altitude equals the comment’s alt; their Snippet names the product and firmware, read into the record. 3 older files hold one path per flight state (pad, boost, …) and an unset date (2147483647-…, or 0000-00-00). 1 holds a Barometric Altitude path and a GPS Altitude path, each with Point placemarks at the flight’s events (Boost (Baro) …), and a byte that isn’t UTF-8 in its text; AltOS’s release notes say that since 1.8.3 the “KML export now reports both barometric and GPS altitude data”. In the flight-state paths the tuple’s altitude climbs while the comment’s alt holds still with few satellites, and in the barometric path the two differ at every point: the tuple’s is the barometer’s. So in an AltOS track whose tuple altitude differs from its comments’ alt at more than half of the points that carry both, the tuple altitude is read as a barometric altitude above sea level, Quantity::AltitudeMsl, and the comments’ alt as the GPS altitude, a channel of its own; otherwise the tuple’s is the GPS altitude, and the comments’ alt a channel only if it differs somewhere. In every sample track the two differ at all the points or at none, so no single point decides a track. The comments’ alt is read in meters where it equals the tuple’s, meters by the standard, at some point of the file, as in the GPS path beside the barometric one; in the flight-state files it equals it nowhere, so nothing in them shows its unit and it is kept as written. The time is 0 in every comment of the 7 GPS-only files and the barometric one, which this reader takes as unset: those points have no time. In the flight-state files it runs on, stepping by about a second between GPS fixes, from an unstated zero (a negative time on the pad in one, hundreds of seconds in the others). It is read in seconds where the median step between a track’s points of distinct times is 0.5 to 2 s, as a receiver reporting once a second gives and a time in tenths, milliseconds or minutes wouldn’t; otherwise those points have no time, and the time is a channel kept as written. The Snippet’s Max baro height is read as the stated apogee.
  • Big Red Bee’s BeeLine (2): KML 2.0’s namespace, CR LF, one Placemark named gps with a MultiGeometry path of zero-padded whole meters (00850), the BeeLine comment beside each point, in one file comments of the flight’s particulars before the first point, and after the document a comment opening BRBDATA holding the logger’s memory in hexadecimal, 128 KiB of it: none of these is read, each counted in a note. Big Red Bee’s manuals say the logger records “latitude, longitude, altitude, GPS time, and number of satellites in view” once a second (BeeLine GPS, 2024-11, p3) and writes a KML file for Google Earth (p8); no manual describes the comments.
  • Unnamed, AltOS-styled (2): styles named as AltOS names them (ao-flightstate-…), a document named by a hexadecimal id, one Path in mode relativeToGround, and the Alt/Seconds comment beside each point; Alt equals the tuple’s altitude. Seconds runs from a small negative number, a time from liftoff. The logger is KML.
  • GPS Visualizer (1), named in the document’s Snippet: one placemark of 48 paths in a MultiGeometry, 47 of a single point.
  • A map drawn in Google Earth (1): predicted tracks and pins in nested documents, not a flight log; it is read as any KML file is (the survey of sample logs files it apart, by id). The logger is KML: the file names no writer of its own.

The altitude’s unit. Meters, from the standard, but for GPS Visualizer’s. Against a barometric logger flown on the same flight, among the project’s sample logs, the track’s rise above its first point is 0.99 to 1.06 times the logger’s peak in meters in 9 of 11 fw2kml files, 0.73 to 1.15 in 11 of 12 RTx files, 0.76 to 1.06 in 8 of 10 AltOS files and 1.05 in a BeeLine file, where feet would make it 3.28 times. The others are a track whose receiver lost the rocket, two pairings with what may be another flight, and two AltOS files whose first path is the pad’s alone. The GPS Visualizer file’s rise is 3.24 times its flight’s barometric peak in meters: its altitudes are feet written as meters. GPS Visualizer reads a source’s altitude “as meters unless “(ft.)” or “(feet)” is included in the field name“ (gpsvisualizer.com/tutorials/waypoints.php), so its KML holds meters only when its source said which unit it used, and the file can’t say whether it did: its altitude is kept as written, Quantity::Unrecognized. The two unnamed files’ rise is 0.42 times their flight’s barometric peak, which neither unit explains; their altitude is read in meters, from the standard, as a height above the ground.

Each decision is a note in one grammar, the same before the colon for every file decided alike, such as `coordinates` read in meters, from the KML standard: …, with this file’s evidence after it.

Hostile input. roxmltree parses the XML, with its default refusal of a document type declaration, so no entity can expand, and a limit of MAX_NODES nodes over all the file’s documents together. The parser descends the tree on the stack, so the text’s nesting is counted first and a file nesting elements deeper than MAX_DEPTH is refused. At most MAX_TRACKS tracks and MAX_POINTS points are read, the rest counted in a note; notes about single places are capped as every reader’s are. Every track’s channels hold one value per point read, so the record never holds more than the file wrote.

Where this comes from. The standard and Google’s reference as cited, and the files themselves; no KML reader was ported. Debrief, the project owner’s own earlier tool, writes KML but doesn’t read it.

Constants§

MAX_DEPTH
The deepest the XML may nest its elements. The parser underneath, roxmltree, descends the tree on the stack, so a file nesting far enough would exhaust it, a crash where an error is due: the nesting is counted before the text is parsed, as the .ork reader’s is (hpr_io::ork). The sample files nest at most 9 deep; 64 is as deep as the .ork reader allows.
MAX_DOCUMENTS
The most KML documents read from one file, one after another; past it, the rest are counted in a note. A later document identical to the first doesn’t count.
MAX_MIDNIGHTS
The most times a time of day is carried past midnight in one file; the times of day after are gaps. A BeeLine’s memory holds a few hours of points at one a second, so a flight’s file passes midnight once at most, and the bound keeps the days added from overflowing on a hostile file.
MAX_NODES
The most XML nodes the parser builds for one file, over all the documents it holds together, so a file of many tiny elements, in one document or several, can’t fill memory. The sample files hold well under 100,000.
MAX_POINTS
The most points read from one file, over all its tracks; past it, the rest are counted in a note. The sample files hold at most 8,736.
MAX_TRACKS
The most tracks (geometries) one file gives; past it, the rest are counted in a note. The sample files hold at most 48.

Functions§

read
Reads a KML file’s tracks into a flight record.