Skip to content

Commit 7542431

Browse files
committed
tile_id = 0 for the full extent of JIS mesh
1 parent 0c1b881 commit 7542431

File tree

8 files changed

+94
-2
lines changed

8 files changed

+94
-2
lines changed

README.ja.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pnpm cli decode test/fixtures/uncompressed.tile --output decoded.csv
9595

9696
`tile_id` の意味:
9797

98-
- `mesh_kind=jis-x0410`: `tile_id` は JIS メッシュコード整数です。
98+
- `mesh_kind=jis-x0410`: `tile_id` は JIS メッシュコード整数です。推奨: `tile_id=0` を JIS ルートタイル(JIS メッシュ対象範囲全体: `west=122`, `south=20`, `east=154`, `north=46`)として扱います。
9999
- `mesh_kind=xyz`: `tile_id``(zoom << 58) | quadkey_integer` でパックされます。`quadkey_integer` は quadkey を base-4 整数として解釈した値で、zoom の最大値は `29` です。
100100

101101
任意メタデータ:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ Required metadata:
101101

102102
`tile_id` semantics:
103103

104-
- `mesh_kind=jis-x0410`: `tile_id` is the JIS mesh code integer.
104+
- `mesh_kind=jis-x0410`: `tile_id` is the JIS mesh code integer. Recommendation: use `tile_id=0` as a root tile for the full JIS mesh scope (`west=122`, `south=20`, `east=154`, `north=46`).
105105
- `mesh_kind=xyz`: `tile_id` is packed as `(zoom << 58) | quadkey_integer`, where `quadkey_integer` is the quadkey interpreted as base-4, and zoom max is `29`.
106106

107107
Optional metadata:

references/rust/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ Out of scope:
1313
- GeoJSON/vector conversion.
1414
- Map rendering integrations.
1515

16+
JIS root-tile recommendation:
17+
- For `mesh_kind=JisX0410`, `tile_id=0` is a recommended convention for a root tile
18+
representing the full JIS mesh scope (`west=122`, `south=20`, `east=154`, `north=46`).
19+
- This crate treats `tile_id` as metadata for JIS tiles and accepts `0` as a valid value.
20+
1621
## Run tests
1722

1823
From repository root:

spec/tile-format-v1.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ File := FixedHeaderV1 || Payload
6363
### 4.4 `tile_id` (u64) by `mesh_kind`
6464

6565
- `mesh_kind=JIS_X0410` (`1`): `tile_id` is the JIS mesh code value as an unsigned integer.
66+
Recommended convention for interoperability: `tile_id=0` may be used as a JIS root tile meaning
67+
the full JIS mesh scope (`west=122`, `south=20`, `east=154`, `north=46`).
6668
- `mesh_kind=XYZ` (`2`): `tile_id` stores zoom + quadkey integer in a single u64.
6769
- Bits `63..58` (most significant 6 bits): `zoom` (`0..29`)
6870
- Bits `57..0`: `quadkey_integer` (the XYZ tile quadkey interpreted as base-4 integer)

src/browser.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export type {
2020
export {
2121
JIS_MESH_LEVELS,
2222
JIS_MESH_PLACEHOLDER_LEVELS,
23+
JIS_MESH_ROOT_TILE_ID,
24+
JIS_MESH_SCOPE_BOUNDS,
2325
toJisMeshLevel,
2426
toJisMeshCode,
2527
toJisMeshPoint,

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export type {
2020
export {
2121
JIS_MESH_LEVELS,
2222
JIS_MESH_PLACEHOLDER_LEVELS,
23+
JIS_MESH_ROOT_TILE_ID,
24+
JIS_MESH_SCOPE_BOUNDS,
2325
toJisMeshLevel,
2426
toJisMeshCode,
2527
toJisMeshPoint,

src/jismesh.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,18 @@ export interface JisMeshBounds {
2222
west: number;
2323
}
2424

25+
export const JIS_MESH_ROOT_TILE_ID = 0n;
26+
27+
// Recommended JIS root tile extent (`tile_id=0`) used by this repository.
28+
export const JIS_MESH_SCOPE_BOUNDS: Readonly<JisMeshBounds> = Object.freeze({
29+
west: 122,
30+
south: 20,
31+
east: 154,
32+
north: 46,
33+
});
34+
2535
const JIS_MESH_LEVEL_SET = new Set<number>(Object.values(JIS_MESH_LEVELS));
36+
const JIS_MESH_ROOT_TILE_CODE = JIS_MESH_ROOT_TILE_ID.toString();
2637

2738
export const JIS_MESH_PLACEHOLDER_LEVELS: Readonly<Record<string, JisMeshLevel>> = Object.freeze({
2839
lv1: JIS_MESH_LEVELS.lv1,
@@ -91,6 +102,33 @@ export function toJisMeshPoint(
91102
level?: JisMeshLevel
92103
): [number, number] {
93104
const code = normalizeMeshCode(meshCode);
105+
if (code === JIS_MESH_ROOT_TILE_CODE) {
106+
if (level !== undefined) {
107+
throw createError(
108+
'INVALID_FIELD_VALUE',
109+
'JIS root tile "0" does not have a JIS mesh level. Omit the level argument.'
110+
);
111+
}
112+
113+
switch (point) {
114+
case 'sw':
115+
return [JIS_MESH_SCOPE_BOUNDS.south, JIS_MESH_SCOPE_BOUNDS.west];
116+
case 'nw':
117+
return [JIS_MESH_SCOPE_BOUNDS.north, JIS_MESH_SCOPE_BOUNDS.west];
118+
case 'ne':
119+
return [JIS_MESH_SCOPE_BOUNDS.north, JIS_MESH_SCOPE_BOUNDS.east];
120+
case 'se':
121+
return [JIS_MESH_SCOPE_BOUNDS.south, JIS_MESH_SCOPE_BOUNDS.east];
122+
case 'center':
123+
return [
124+
(JIS_MESH_SCOPE_BOUNDS.north + JIS_MESH_SCOPE_BOUNDS.south) / 2,
125+
(JIS_MESH_SCOPE_BOUNDS.east + JIS_MESH_SCOPE_BOUNDS.west) / 2,
126+
];
127+
default:
128+
throw createError('INVALID_FIELD_VALUE', `Unsupported JIS mesh point "${point as string}".`);
129+
}
130+
}
131+
94132
const detectedLevel = toJisMeshLevel(code);
95133
if (detectedLevel === null) {
96134
throw createError('INVALID_FIELD_VALUE', `Invalid JIS mesh code "${code}".`);

test/maplibre-source.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import { describe, it } from 'node:test';
55
import { fromGeojsonVt } from '@maplibre/vt-pbf';
66
import {
77
JIS_MESH_LEVELS,
8+
JIS_MESH_ROOT_TILE_ID,
9+
JIS_MESH_SCOPE_BOUNDS,
810
MAPLIBRE_MESH_PROTOCOL_DEFAULT_LAYER_NAME,
911
MAPLIBRE_MESH_PROTOCOL_DEFAULT_VECTOR_EXTENT,
1012
MAPLIBRE_MESH_PROTOCOL_DEFAULT_VECTOR_VERSION,
1113
createMapLibreMeshTileProtocol,
1214
createMapLibreSourceHandler,
1315
decodeTile,
1416
decodedMeshTileToGeoJson,
17+
encodeTile,
1518
getJisMeshCodesWithinBounds,
1619
renderMeshTileUrlTemplate,
1720
toJisMeshCode,
@@ -88,6 +91,19 @@ describe('maplibre source helpers', () => {
8891
assertAlmostEqual(center[1], 139.71875);
8992
});
9093

94+
it('maps tile_id=0 to the recommended JIS root-tile scope', () => {
95+
const sw = toJisMeshPoint(JIS_MESH_ROOT_TILE_ID, 'sw');
96+
const ne = toJisMeshPoint(JIS_MESH_ROOT_TILE_ID, 'ne');
97+
const center = toJisMeshPoint(JIS_MESH_ROOT_TILE_ID, 'center');
98+
99+
assert.deepEqual(sw, [JIS_MESH_SCOPE_BOUNDS.south, JIS_MESH_SCOPE_BOUNDS.west]);
100+
assert.deepEqual(ne, [JIS_MESH_SCOPE_BOUNDS.north, JIS_MESH_SCOPE_BOUNDS.east]);
101+
assert.deepEqual(center, [
102+
(JIS_MESH_SCOPE_BOUNDS.north + JIS_MESH_SCOPE_BOUNDS.south) / 2,
103+
(JIS_MESH_SCOPE_BOUNDS.east + JIS_MESH_SCOPE_BOUNDS.west) / 2,
104+
]);
105+
});
106+
91107
it('resolves japanmesh codes within bounds', () => {
92108
const codes = getJisMeshCodesWithinBounds(
93109
{
@@ -173,6 +189,33 @@ describe('maplibre source helpers', () => {
173189
});
174190
});
175191

192+
it('converts decoded JIS root tile (tile_id=0) to full-scope GeoJSON polygons', async () => {
193+
const encoded = await encodeTile({
194+
tile_id: JIS_MESH_ROOT_TILE_ID,
195+
mesh_kind: 'jis-x0410',
196+
rows: 1,
197+
cols: 1,
198+
bands: 1,
199+
dtype: 'uint8',
200+
endianness: 'little',
201+
compression: 'none',
202+
no_data: null,
203+
data: [7],
204+
});
205+
206+
const decoded = await decodeTile(encoded.bytes);
207+
const geojson = decodedMeshTileToGeoJson(decoded);
208+
209+
assert.equal(geojson.features.length, 1);
210+
assert.deepEqual(geojson.features[0].geometry.coordinates[0], [
211+
[JIS_MESH_SCOPE_BOUNDS.west, JIS_MESH_SCOPE_BOUNDS.south],
212+
[JIS_MESH_SCOPE_BOUNDS.east, JIS_MESH_SCOPE_BOUNDS.south],
213+
[JIS_MESH_SCOPE_BOUNDS.east, JIS_MESH_SCOPE_BOUNDS.north],
214+
[JIS_MESH_SCOPE_BOUNDS.west, JIS_MESH_SCOPE_BOUNDS.north],
215+
[JIS_MESH_SCOPE_BOUNDS.west, JIS_MESH_SCOPE_BOUNDS.south],
216+
]);
217+
});
218+
176219
it('fetches, decodes, and converts tiles via maplibre source handler', async () => {
177220
const fixturePath = join(process.cwd(), 'test', 'fixtures', 'xyz-uncompressed.tile');
178221
const bytes = new Uint8Array(await fs.readFile(fixturePath));

0 commit comments

Comments
 (0)