Files
gods-eye-view/src/layers/streetLevel/decode.js
T
German KhokhlovandClaude Fable 5.1 e214129e45 refactor(street-level): drop hover, legend and byte-budget cache; flatten the provider directory
- No pointer cursor over coverage lines (no other layer has one); a click
  test replaces the hover tests.
- No legend: one source, one colour.
- The on-globe credit lives in index.js; credits.js is gone.
- Billboard glyphs are SVG data URLs with the same geometry, so tests need
  no canvas stub.
- The tile cache keeps the 120 most recently used tiles, same 24 h TTL,
  instead of a byte budget; listTileLayers was test-only.
- providers/mapillary/ is flattened into the layer and its policy merged
  into one policy.js; the source's method list is a literal in the catalog.
- One fakeCesiumViewer for the layer tests.
- The fixture gate keeps the steps the unit tests do not cover: coverage and
  credit, a rejected key, line -> cone -> photo, close, a keyless page.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-10-08 19:17:45 +04:00

41 lines
1.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { PbfReader } from 'pbf';
import { VectorTile } from '@mapbox/vector-tile';
import { tileLocalToLonLat } from './tileMath.js';
/**
* Decode a `mly1_public` coverage tile (z11–14) into sequences. The z14
* `image` layer, which can hold >150k points, is skipped.
* @param {Uint8Array} bytes
* @param {{x:number,y:number,z:number}} address
*/
export function decodeCoverageTile(bytes, address) {
const result = { sequences: [] };
if (!bytes || !bytes.length) return result;
const tile = new VectorTile(new PbfReader(bytes));
const { x, y, z } = address;
const sequenceLayer = tile.layers.sequence;
if (sequenceLayer) {
for (let i = 0; i < sequenceLayer.length; i++) {
const feature = sequenceLayer.feature(i);
const props = feature.properties || {};
// A sequence with a capture gap is a multi-line: keep each part as its
// own line, so no straight segment is drawn across the gap.
const parts = [];
for (const line of feature.loadGeometry()) {
const part = line.map((point) =>
tileLocalToLonLat(point.x, point.y, sequenceLayer.extent, x, y, z),
);
if (part.length >= 2) parts.push(part);
}
if (!parts.length) continue;
result.sequences.push({
id: String(props.id ?? feature.id ?? `${x}/${y}/${i}`),
capturedAt: Number(props.captured_at) || 0,
isPano: props.is_pano === true,
parts,
});
}
}
return result;
}