mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-13 06:42:23 +00:00
tighten remaining voice outline review items
- join street pieces at up to 3 m again (inclusive), as before the shared stitcher - share one default outline tile source across outline rung instances - cover Japanese and Thai street names that differ only by a mark - restore main's text for formatting-only CURRENT-STATE hunks
This commit is contained in:
1 parent
a71443a0ef
commit
e6ad7fe34f
6 files changed
+96
-9
No files matched your search
@@ -3812,7 +3812,7 @@ Shipped locales: **en** (source and fallback), **de**, **es**, **fr**, **it**, *
|
|||||||
[`docs/TRANSLATORS.md`](./TRANSLATORS.md).
|
[`docs/TRANSLATORS.md`](./TRANSLATORS.md).
|
||||||
|
|
||||||
- **Keys are the English text.** `t('Save keys')`, `tn(count, '{count} camera',
|
- **Keys are the English text.** `t('Save keys')`, `tn(count, '{count} camera',
|
||||||
'{count} cameras')`, and `msg('Live Flights')` for text stored in data and
|
'{count} cameras')`, and `msg('Live Flights')` for text stored in data and
|
||||||
translated later. Markup opts in with `data-i18n` (element text) and
|
translated later. Markup opts in with `data-i18n` (element text) and
|
||||||
`data-i18n-title` / `-aria-label` / `-placeholder` (that attribute's English
|
`data-i18n-title` / `-aria-label` / `-placeholder` (that attribute's English
|
||||||
value). English has no catalog; every other locale is
|
value). English has no catalog; every other locale is
|
||||||
@@ -3924,6 +3924,7 @@ MLAT-positioned GPS loss, derived-field exclusions and the NIC 0 exception.
|
|||||||
anchors, recovery, keyboard and mobile states; emergency repainting is covered
|
anchors, recovery, keyboard and mobile states; emergency repainting is covered
|
||||||
by `scripts/qa-emergency-squawk.mjs`. Both accept `--timeout-ms` for slow boot.
|
by `scripts/qa-emergency-squawk.mjs`. Both accept `--timeout-ms` for slow boot.
|
||||||
|
|
||||||
|
|
||||||
Fire Perimeters uses capped, timed server reads with stale-on-error caching and a per-client limit. A stale snapshot is served for at most 24 hours; the layer row then reads STALE, dated by that snapshot's fetch, and `get_fire_perimeters` returns `stale` and `retrieved_at` with "(data may be stale)" in its summary. Unchanged snapshots retain geometry; link checks cancel on disable or selection change, and the row legend shows reported containment.
|
Fire Perimeters uses capped, timed server reads with stale-on-error caching and a per-client limit. A stale snapshot is served for at most 24 hours; the layer row then reads STALE, dated by that snapshot's fetch, and `get_fire_perimeters` returns `stale` and `retrieved_at` with "(data may be stale)" in its summary. Unchanged snapshots retain geometry; link checks cancel on disable or selection change, and the row legend shows reported containment.
|
||||||
|
|
||||||
Street Level is a docked, collapsible right-rail panel (`#street-level-panel`,
|
Street Level is a docked, collapsible right-rail panel (`#street-level-panel`,
|
||||||
@@ -4089,7 +4090,8 @@ that does not answer in 20 s is asked once more, and one that is not a line
|
|||||||
list is not cached. A click on a line reaches
|
list is not cached. A click on a line reaches
|
||||||
`handlePick(id, {groundPoint})`, and the provider asks the core
|
`handlePick(id, {groundPoint})`, and the provider asks the core
|
||||||
(`actions.openNearest`) for its nearest showable photo within 50 m, without
|
(`actions.openNearest`) for its nearest showable photo within 50 m, without
|
||||||
framing: many photos are archived (their file answers 409, while a HEAD says 200) or have no file, so the six nearest are probed at once with a GET cut
|
framing: many photos are archived (their file answers 409, while a HEAD says
|
||||||
|
200) or have no file, so the six nearest are probed at once with a GET cut
|
||||||
off at the headers, and where all are gone the panel says KartaView's photos
|
off at the headers, and where all are gone the panel says KartaView's photos
|
||||||
there are archived. Only a definite answer (403/404/409/410, or 200) is
|
there are archived. Only a definite answer (403/404/409/410, or 200) is
|
||||||
remembered; a storage timeout or 5xx is asked again. The open photo's
|
remembered; a storage timeout or 5xx is asked again. The open photo's
|
||||||
@@ -5590,6 +5592,7 @@ Vite's development filesystem deny list excludes local `.gev-logs/` and
|
|||||||
dependency `dist/` assets. Checkout glob characters are escaped. This does not
|
dependency `dist/` assets. Checkout glob characters are escaped. This does not
|
||||||
apply to `public/` assets or built-preview serving.
|
apply to `public/` assets or built-preview serving.
|
||||||
|
|
||||||
|
|
||||||
- Recommended launcher: `./scripts/dev-fresh.sh` (also: `dev-secure.sh` for stricter bindings, `dev-cctv.sh` for CCTV source-pack tuning)
|
- Recommended launcher: `./scripts/dev-fresh.sh` (also: `dev-secure.sh` for stricter bindings, `dev-cctv.sh` for CCTV source-pack tuning)
|
||||||
- A successful Pinokio install writes the owner-only `pinokio/.installed`
|
- A successful Pinokio install writes the owner-only `pinokio/.installed`
|
||||||
marker. The nested launcher menu resolves that marker from its own directory:
|
marker. The nested launcher menu resolves that marker from its own directory:
|
||||||
|
|||||||
@@ -163,8 +163,14 @@ export function streetFootprint(street) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rungs built without their own tiles share one outline source, so a second
|
||||||
|
// resolver instance cannot add another outline cache to the tile budget.
|
||||||
|
let defaultOutlineTiles = null;
|
||||||
|
const sharedOutlineTiles = () =>
|
||||||
|
(defaultOutlineTiles ??= createOpenFreeMapOutlineSource());
|
||||||
|
|
||||||
export function createOutlineRungs({
|
export function createOutlineRungs({
|
||||||
tiles = createOpenFreeMapOutlineSource(),
|
tiles = sharedOutlineTiles(),
|
||||||
nominatim = createNominatimOutlineClient(),
|
nominatim = createNominatimOutlineClient(),
|
||||||
} = {}) {
|
} = {}) {
|
||||||
/** Decoded tiles around a point, or null when the tiles cannot be read. */
|
/** Decoded tiles around a point, or null when the tiles cannot be read. */
|
||||||
|
|||||||
@@ -154,6 +154,56 @@ test('a street comes from tiles before the configured ladder, as merged ribbons'
|
|||||||
assert.equal(nominatim.asks.length, 0, 'streets never reach Nominatim');
|
assert.equal(nominatim.asks.length, 0, 'streets never reach Nominatim');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('rungs built without their own tiles share one outline tile cache', async (t) => {
|
||||||
|
const tileRequests = [];
|
||||||
|
const bytes = (y) =>
|
||||||
|
readFileSync(
|
||||||
|
new URL(
|
||||||
|
`../data/fixtures/ofm-outlines-austin-14-3743-${y}.pbf`,
|
||||||
|
import.meta.url,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
t.mock.method(globalThis, 'fetch', async (url) => {
|
||||||
|
const href = String(url);
|
||||||
|
if (href.endsWith('/planet'))
|
||||||
|
return Response.json({
|
||||||
|
tiles: [
|
||||||
|
'https://tiles.openfreemap.org/planet/shared-test/{z}/{x}/{y}.pbf',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
tileRequests.push(href);
|
||||||
|
const y = href.match(/\/(\d+)\.pbf$/)?.[1];
|
||||||
|
return new Response(y === '6746' ? bytes(6746) : bytes(6745));
|
||||||
|
});
|
||||||
|
const ask = () =>
|
||||||
|
ctx({
|
||||||
|
scope: 'street',
|
||||||
|
target: 'Congress Avenue',
|
||||||
|
matchName: 'Congress Avenue',
|
||||||
|
});
|
||||||
|
const first = await createOutlineRungs({
|
||||||
|
nominatim: fakeNominatim(null),
|
||||||
|
}).resolve(ask(), ladder(UNAVAILABLE));
|
||||||
|
assert.ok(first.ring.length > 6);
|
||||||
|
const fetched = tileRequests.length;
|
||||||
|
assert.ok(fetched > 0);
|
||||||
|
const second = await createOutlineRungs({
|
||||||
|
nominatim: fakeNominatim(null),
|
||||||
|
}).resolve(ask(), ladder(UNAVAILABLE));
|
||||||
|
assert.ok(second.ring.length > 6);
|
||||||
|
assert.equal(
|
||||||
|
tileRequests.length,
|
||||||
|
fetched,
|
||||||
|
'a second rung set reuses the shared outline tiles',
|
||||||
|
);
|
||||||
|
const own = fixtureTiles();
|
||||||
|
await createOutlineRungs({
|
||||||
|
tiles: own,
|
||||||
|
nominatim: fakeNominatim(null),
|
||||||
|
}).resolve(ask(), ladder(UNAVAILABLE));
|
||||||
|
assert.equal(own.asked.length, 1, 'explicit tiles are still used');
|
||||||
|
});
|
||||||
|
|
||||||
test('a street the tiles do not name falls through to the ladder', async () => {
|
test('a street the tiles do not name falls through to the ladder', async () => {
|
||||||
const run = ladder(UNAVAILABLE);
|
const run = ladder(UNAVAILABLE);
|
||||||
const result = await createOutlineRungs({
|
const result = await createOutlineRungs({
|
||||||
|
|||||||
@@ -15,15 +15,18 @@ export function ringAreaM2(ring) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Join line pieces whose ends meet (within `toleranceM`) into as few chains as
|
* Join line pieces whose ends meet (closer than `toleranceM`, or at most it
|
||||||
* possible. Each chain grows greedily from the first unused piece.
|
* when `inclusive`) into as few chains as possible. Each chain grows greedily
|
||||||
|
* from the first unused piece.
|
||||||
*/
|
*/
|
||||||
export function stitchLines(
|
export function stitchLines(
|
||||||
segments,
|
segments,
|
||||||
{ toleranceM = 2, maxChains = Infinity } = {},
|
{ toleranceM = 2, inclusive = false, maxChains = Infinity } = {},
|
||||||
) {
|
) {
|
||||||
const same = (a, b) =>
|
const same = (a, b) => {
|
||||||
approximateDistanceM(a[1], a[0], b[1], b[0]) < toleranceM;
|
const d = approximateDistanceM(a[1], a[0], b[1], b[0]);
|
||||||
|
return inclusive ? d <= toleranceM : d < toleranceM;
|
||||||
|
};
|
||||||
const remaining = segments.map((s) => s.slice());
|
const remaining = segments.map((s) => s.slice());
|
||||||
const chains = [];
|
const chains = [];
|
||||||
while (remaining.length && chains.length < maxChains) {
|
while (remaining.length && chains.length < maxChains) {
|
||||||
|
|||||||
@@ -383,7 +383,7 @@ export function streetFromTiles(
|
|||||||
if (!pieces.length) return null;
|
if (!pieces.length) return null;
|
||||||
const chains = stitchLines(
|
const chains = stitchLines(
|
||||||
pieces.filter((piece) => piece.length >= 2),
|
pieces.filter((piece) => piece.length >= 2),
|
||||||
{ toleranceM: JOIN_TOLERANCE_M },
|
{ toleranceM: JOIN_TOLERANCE_M, inclusive: true },
|
||||||
)
|
)
|
||||||
.map((line) => ({ line, length: lengthM(line) }))
|
.map((line) => ({ line, length: lengthM(line) }))
|
||||||
.filter((entry) => entry.length >= STREET_MIN_CHAIN_M)
|
.filter((entry) => entry.length >= STREET_MIN_CHAIN_M)
|
||||||
|
|||||||
@@ -61,6 +61,14 @@ test('street names compare with abbreviations and a leading direction only', ()
|
|||||||
assert.ok(!streetNameMatches('कुल मार्ग', 'काली मार्ग'));
|
assert.ok(!streetNameMatches('कुल मार्ग', 'काली मार्ग'));
|
||||||
assert.ok(streetNameMatches('काली मार्ग', 'काली मार्ग'));
|
assert.ok(streetNameMatches('काली मार्ग', 'काली मार्ग'));
|
||||||
assert.ok(streetNameMatches('Champs-Élysées', 'Champs Elysees'));
|
assert.ok(streetNameMatches('Champs-Élysées', 'Champs Elysees'));
|
||||||
|
// Japanese: dakuten and handakuten are kept, so these stay distinct.
|
||||||
|
assert.ok(!streetNameMatches('ハシ通り', 'バシ通り'));
|
||||||
|
assert.ok(!streetNameMatches('ハシ通り', 'パシ通り'));
|
||||||
|
assert.ok(streetNameMatches('表参道', '表参道'));
|
||||||
|
// Thai: vowel and tone marks are kept.
|
||||||
|
assert.ok(!streetNameMatches('ถนนสุขุมวิท', 'ถนนสุขมวท'));
|
||||||
|
assert.ok(!streetNameMatches('ถนนข้าวสาร', 'ถนนขาวสาร'));
|
||||||
|
assert.ok(streetNameMatches('ถนนสุขุมวิท', 'ถนนสุขุมวิท'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('same-name segments merge into polylines around the point (Congress Avenue)', () => {
|
test('same-name segments merge into polylines around the point (Congress Avenue)', () => {
|
||||||
@@ -112,6 +120,23 @@ test('merge joins reversed and out-of-order pieces and keeps gaps apart', () =>
|
|||||||
[0.011, 0],
|
[0.011, 0],
|
||||||
]; // separate
|
]; // separate
|
||||||
const chains = stitchLines([b, c, a], { toleranceM: 3 });
|
const chains = stitchLines([b, c, a], { toleranceM: 3 });
|
||||||
|
|
||||||
|
test('stitchLines joins at exactly the tolerance only when inclusive', () => {
|
||||||
|
const a = [
|
||||||
|
[0, 0],
|
||||||
|
[0.001, 0],
|
||||||
|
];
|
||||||
|
const b = [
|
||||||
|
[0.00102, 0],
|
||||||
|
[0.002, 0],
|
||||||
|
];
|
||||||
|
const gap = approximateDistanceM(0, 0.001, 0, 0.00102);
|
||||||
|
assert.equal(
|
||||||
|
stitchLines([a, b], { toleranceM: gap, inclusive: true }).length,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
assert.equal(stitchLines([a, b], { toleranceM: gap }).length, 2);
|
||||||
|
});
|
||||||
assert.equal(chains.length, 2);
|
assert.equal(chains.length, 2);
|
||||||
assert.equal(chains.find((ch) => ch.length === 3).length, 3);
|
assert.equal(chains.find((ch) => ch.length === 3).length, 3);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in new issue
Block a user