@@ -1168,13 +1168,25 @@ message DrawnShape {
11681168 */
11691169 bool labels_on = 11 ;
11701170 /*
1171- * Vertex list for polyline/polygon/rectangle shapes. Capped at 32 by
1172- * the nanopb pool; senders MUST truncate longer inputs and set
1173- * `truncated = true`.
1171+ * Vertex list for polyline/polygon/rectangle/telestration shapes, stored as
1172+ * two PACKED parallel columns of signed deltas from the event anchor
1173+ * (TAKPacketV2.latitude_i/longitude_i), in 1e-7 degree units. vertex N is
1174+ * (lat_deltas[N], lon_deltas[N]); the two columns MUST stay the same length.
1175+ *
1176+ * Replaces the former `repeated CotGeoPoint vertices = 12` (one length-
1177+ * delimited sub-message per vertex = ~2 B framing each). Packing into two
1178+ * `repeated sint32` columns pays the field framing ONCE per column instead
1179+ * of once per vertex — ~58 B saved on a 32-vertex telestration — while
1180+ * keeping the same zigzag small-delta win CotGeoPoint had. Capped at 32 by
1181+ * the nanopb pool; senders MUST truncate longer inputs and set `truncated`.
1182+ *
1183+ * Tag 12 (the old repeated-message field) is reserved to prevent reuse.
11741184 */
1175- repeated CotGeoPoint vertices = 12 ;
1185+ reserved 12 ;
1186+ repeated sint32 vertex_lat_deltas = 18 ;
1187+ repeated sint32 vertex_lon_deltas = 19 ;
11761188 /*
1177- * True if the sender truncated `vertices` to fit the pool.
1189+ * True if the sender truncated the vertex columns to fit the pool.
11781190 */
11791191 bool truncated = 13 ;
11801192 // --- Bullseye-only fields. All ignored unless kind == Kind_Bullseye. ---
@@ -2036,7 +2048,14 @@ message TAKPacketV2 {
20362048 */
20372049 sfixed32 longitude_i = 7 ;
20382050 /*
2039- * Altitude in meters (HAE)
2051+ * Altitude in meters (HAE). ATAK's "no altitude" sentinel is hae=9999999.0.
2052+ *
2053+ * NOTE: an earlier v0.4.0 attempt made this `optional` to omit the 9999999
2054+ * sentinel from the wire, but measurement showed it was net-negative: the
2055+ * zstd dictionary already compresses the literal 9999999 to ~nothing, while
2056+ * proto3 `optional` forces a genuine 0 m HAE (common on routes/drawings that
2057+ * carry hae="0.0" or omit hae → parsed as 0) to encode explicitly (+2 bytes),
2058+ * which REGRESSED the worst-case route fixture. Kept as a plain field.
20402059 */
20412060 sint32 altitude = 8 ;
20422061 /*
@@ -2126,10 +2145,11 @@ message TAKPacketV2 {
21262145 */
21272146 optional SensorFov sensor_fov = 26 ;
21282147
2129- reserved 27 , 28 ;
2130- // Tags 27, 28 reserved for future top-level annotations before the
2131- // payload_variant oneof resumes at 30. Tag 29 was previously reserved
2132- // and is now consumed by `marti` below.
2148+ reserved 27 , 28 , 30 ;
2149+ // Tags 27, 28 reserved for future top-level annotations. Tag 29 is consumed
2150+ // by `marti` below. Tag 30 was the former `bool pli` oneof arm — dropped
2151+ // (PLI is now the implicit payload); reserved here at the message level
2152+ // because proto3 forbids `reserved` inside a oneof.
21332153
21342154 /*
21352155 * Directed-routing recipient list (CoT <marti><dest callsign='X'/>…</marti>).
@@ -2147,10 +2167,12 @@ message TAKPacketV2 {
21472167 * The payload of the packet
21482168 */
21492169 oneof payload_variant {
2150- /*
2151- * Position report (true = PLI, no extra fields beyond the common ones above)
2152- */
2153- bool pli = 30 ;
2170+ // Tag 30 was `bool pli` — a PLI carries no fields beyond the common
2171+ // envelope (position is in latitude_i/longitude_i), so the boolean was
2172+ // pure overhead (~3 wire bytes on every position beacon, the highest-
2173+ // frequency packet). PLI is now the IMPLICIT payload: a packet with NO
2174+ // payload_variant set decodes as a position report. Tag 30 is reserved at
2175+ // the message level (proto3 forbids `reserved` inside a oneof).
21542176 /*
21552177 * ATAK GeoChat message
21562178 */
0 commit comments