Mvt Reader
Protobuf-free reader for Mapbox Vector Tile (MVT) 2.1 bytes.
Replaces no.ecc.vectortile.VectorTileDecoder plus the PruningVectorTileDecoder that used to sit alongside it in that package. Both depended on generated protobuf message classes, which hard-require com.google.protobuf:protobuf-java; that jar defines the same class names as protobuf-javalite and so fails dexing for any consumer app that uses javalite for its own protos (github issue #37). The MVT schema is small and frozen by the spec, so reading the wire format directly costs less than the dependency did.
Behavioural parity
Output is intended to be identical to the decoder it replaces, run with autoScale = false (the only mode this SDK ever used). MvtReaderParityTest asserts that against the reference implementation. In particular the polygon ring-grouping rule -- group rings by the sign of their shoelace area, first non-degenerate ring establishes the exterior winding, zero-area rings dropped -- is a direct port, because it decides which rings become holes, and getting it subtly wrong would misrender polygons rather than fail loudly.
Two intentional divergences, neither reachable from a valid tile:
JTS validated rings in
createLinearRingand threw for an unclosed ring or one with 1..3 points. Those rings are already dropped here by the zero-area test that runs first (a ring with fewer than 4 points is degenerate or collinear, so its area is 0), so the validation never fired. This reader is simply permissive instead.A
ClosePathorLineToarriving before anyMoveTothrew NullPointerException in the reference. Here the former is ignored and the latter opens a ring.
Allocation
The old path went through generated protobuf messages, which materialised the whole tile as an object tree before anything was read: a List<Integer> of boxed geometry commands per feature, an attribute HashMap per feature, and layer-level key/value lists. A heap dump taken during the playback burst attributed ~1.95M HashMap$Node + ~893k UnmodifiableEntry + ~1.26M String to that. This reader streams the wire format instead and never boxes a geometry command, and it keeps the attribute pruning PruningVectorTileDecoder added (see decode's allowed parameter), so tags no consumer declared never become map entries at all.
decode is stateless and safe to call concurrently from the parse coroutines -- all cursor and scratch state lives on a per-call MvtParser.
Functions
Decodes every feature in data, across all layers, in tile-local coordinates.