# How it works

## Why a style filter is not enough

A MapLibre filter decides per feature, and a vector tile does not hold one feature per border. The tile
builder merges lines. At zoom 1 to 4 the basemap packs several different disputed borders into a single
long line, and a filter such as "hide disputed lines inside this box" tests that whole merged line, so
either all of it goes or none of it does. That is why a box filter leaves stray Line of Control and Line
of Actual Control fragments at world zoom, and why a box that is big enough to catch them also removes
real borders (Myanmar, Bhutan) from Arunachal Pradesh when you zoom in.

So this module cuts the geometry itself.

## The tile rewrite

`install(maplibregl)` registers a tile protocol, `indiafix`. `fixStyle` points the basemap's vector source
at it, so a tile URL becomes `indiafix://https://.../{z}/{x}/{y}.pbf`. When the map asks for a tile:

1. Fetch the real tile, gunzip it if it is gzipped.
2. Work out which removal regions touch this tile (`src/config.js`, `REGIONS`). Most tiles touch none and
   are returned unchanged, with no decoding cost beyond a bounding-box test.
3. Decode the `boundary` layer. For every feature that is a country line (`admin_level` 2), not at sea
   (`maritime` 0) and flagged `disputed`, cut each line against the regions in tile pixel space and keep
   only the parts outside.
4. Where a cut leaves a new end close to the drawn line, extend it up to the drawn line so the two meet
   (`snapCutEnds`, reach about 1.6 km).
5. Re-encode the tile and hand it to the map.

Regions are polygons, because one box cannot separate the China side of Arunachal Pradesh from the
Myanmar and Bhutan borders that the basemap also flags as disputed. The Arunachal region is generated by
`scripts/make-region.mjs` as a strip on the China side of the drawn line, narrowing to nothing at both
ends of the drawn line. Those two ends are the points where the line meets the Bhutan and Myanmar borders.

## The replacement lines

`fixStyle` finds every style layer that draws country lines, by source layer and filter rather than by id
(`PROFILE.isCountryLayer`), and adds a copy after it that reads the built-in GeoJSON. The copy keeps the
original's paint, layout and zoom range, so the border looks the same as its neighbours in light and dark
styles.

## Checking it

`npm run verify:coverage` downloads real tiles over the regions at each zoom, applies the rewrite, and
looks for gaps:

* a basemap country line that ends in empty space near a region, farther than 3 screen pixels from both a
  drawn line and another basemap line;
* an end of a drawn line that touches no border.

Zero of both at every zoom means the border has no break. Results for 0.1.0: zoom 1 to 10 report zero. Zoom 11
reports 3 ends near the Bhutan junction (0.15 to 0.6 km from the drawn line) and zoom 12 reports one end 60 m
from it, in Gilgit; looking at the map at those zooms shows no stub or break, so they are tile-edge pieces
and not visible gaps. Zoom 13 and above is checked by eye only. The check does not look at whether a leftover
basemap line runs parallel to a drawn one, so also look at the map: `examples/maplibre.html` is a page
for that.

## Changing the regions

Edit `REGIONS` in `src/config.js`. The Jammu and Kashmir region is a plain box. For Arunachal Pradesh, rerun
`node scripts/make-region.mjs [margin]`, which rewrites `src/arunachal-region.js`. Then run the coverage
check and look at the map at zoom 3, 6, 9 and 12.
