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:
manjunath committed 2026-10-30 21:27:53 +05:30
1 parent a71443a0ef
commit e6ad7fe34f
6 files changed
+96 -9

No files matched your search

+7 -1
View File
@@ -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({
tiles = createOpenFreeMapOutlineSource(),
tiles = sharedOutlineTiles(),
nominatim = createNominatimOutlineClient(),
} = {}) {
/** Decoded tiles around a point, or null when the tiles cannot be read. */
+50
View File
@@ -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');
});
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 () => {
const run = ladder(UNAVAILABLE);
const result = await createOutlineRungs({
+8 -5
View File
@@ -15,15 +15,18 @@ export function ringAreaM2(ring) {
}
/**
* Join line pieces whose ends meet (within `toleranceM`) into as few chains as
* possible. Each chain grows greedily from the first unused piece.
* Join line pieces whose ends meet (closer than `toleranceM`, or at most it
* when `inclusive`) into as few chains as possible. Each chain grows greedily
* from the first unused piece.
*/
export function stitchLines(
segments,
{ toleranceM = 2, maxChains = Infinity } = {},
{ toleranceM = 2, inclusive = false, maxChains = Infinity } = {},
) {
const same = (a, b) =>
approximateDistanceM(a[1], a[0], b[1], b[0]) < toleranceM;
const same = (a, b) => {
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 chains = [];
while (remaining.length && chains.length < maxChains) {
+1 -1
View File
@@ -383,7 +383,7 @@ export function streetFromTiles(
if (!pieces.length) return null;
const chains = stitchLines(
pieces.filter((piece) => piece.length >= 2),
{ toleranceM: JOIN_TOLERANCE_M },
{ toleranceM: JOIN_TOLERANCE_M, inclusive: true },
)
.map((line) => ({ line, length: lengthM(line) }))
.filter((entry) => entry.length >= STREET_MIN_CHAIN_M)
+25
View File
@@ -61,6 +61,14 @@ test('street names compare with abbreviations and a leading direction only', ()
assert.ok(!streetNameMatches('कुल मार्ग', 'काली मार्ग'));
assert.ok(streetNameMatches('काली मार्ग', 'काली मार्ग'));
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)', () => {
@@ -112,6 +120,23 @@ test('merge joins reversed and out-of-order pieces and keeps gaps apart', () =>
[0.011, 0],
]; // separate
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.find((ch) => ch.length === 3).length, 3);
});