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:
| Channel | Quantity | From |
|---|---|---|
<name> latitude, <name> longitude | Quantity::Latitude, Quantity::Longitude | the tuple’s second and first numbers |
<name> altitude | Quantity::GnssAltitude, m | the third number, in mode absolute |
<name> altitude | Quantity::AltitudeMsl, m | the same, in an AltOS track whose altitude is the barometer’s (below) |
<name> height above ground, <name> height above sea floor | Quantity::Distance, m | the third number, in mode relativeToGround or relativeToSeaFloor: a height above the terrain, not above sea level |
<name> altitude | Quantity::Unrecognized, as written | the 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 altitude | Quantity::GnssAltitude, m | AltOS’s comment alt, where it differs from the tuple’s, in a file where it equals the tuple’s at some point |
<name> GPS altitude | Quantity::Unrecognized, as written | the same, in a file where it equals the tuple’s at no point, so nothing in the file shows its unit |
<name> Alt | Quantity::Unrecognized, as written | the Seconds layout’s Alt, where it differs from the tuple’s |
<name> time | Quantity::Unrecognized, as written | AltOS’s comment time, where its steps don’t show it is in seconds (below; none of the samples) |
<name> satellites | Quantity::Number | a comment’s sats |
<name> offset | Quantity::Number | the 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
Placemarknamedfw2kml - Flight N. 12 hold aLineStringwith no times; 2 agx:Trackwith awhenper point, in UTC to the tenth of a second, and agx:Tourof 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 toMAX_DOCUMENTS. - Missile Works’ RTx (12): document
RTx/GPS Flight, KML 2.1’s namespace, a byte-order mark and CR LF; aFolderholdingFlight 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 oneGPS Altitudepath, whose tuple altitude equals the comment’salt; theirSnippetnames the product and firmware, read into the record. 3 older files hold one path per flight state (pad,boost, …) and an unset date (2147483647-…, or0000-00-00). 1 holds aBarometric Altitudepath and aGPS Altitudepath, each withPointplacemarks 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’saltholds 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’altat 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’altas the GPS altitude, a channel of its own; otherwise the tuple’s is the GPS altitude, and the comments’alta 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’altis 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. Thetimeis 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 thetimeis a channel kept as written. TheSnippet’sMax baro heightis read as the stated apogee. - Big Red Bee’s BeeLine (2): KML 2.0’s namespace, CR LF, one
Placemarknamedgpswith aMultiGeometrypath 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 openingBRBDATAholding 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, onePathin moderelativeToGround, and theAlt/Secondscomment beside each point;Altequals the tuple’s altitude.Secondsruns from a small negative number, a time from liftoff. The logger isKML. - GPS Visualizer (1), named in the document’s
Snippet: one placemark of 48 paths in aMultiGeometry, 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.orkreader’s is (hpr_io::ork). The sample files nest at most 9 deep; 64 is as deep as the.orkreader 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.