Country posters print fast on a phone: the sea-name scan and the label placement skip any land ring whose bbox cannot hold the point, and the scan tests the frame first. Exact: all 286 sheets are byte-identical; generation is 3.4-4.4x faster (China's 3x4 sheet 10.3 s -> 3.1 s).
This commit is contained in:
parent
3a6d392a1a
commit
c9a7ef9368
2 changed files with 21 additions and 6 deletions
|
|
@ -2,13 +2,13 @@
|
|||
// The sha384 of library/packet/poster-render.js. The browser fetches the served copy of that file
|
||||
// (<assets>/lib/poster-render.js), hashes it, and runs it only when it matches this pin: code loaded at
|
||||
// print time is integrity-pinned like every embed, because it executes on partner pages.
|
||||
export const POSTER_RENDER_SHA384 = 'sha384-BNFUrsdCCaEetmp5cSBzDklAUsB5XBEefQEcCd3+dNNDghxRuZNytNsVfl5mBOeP'
|
||||
export const POSTER_RENDER_SHA384 = 'sha384-sR7a+BDeXAxY0eZS+crqAXtYtVySYAeDKSek4aHPFYzsUaq9pVi+v2RkmkwjadCV'
|
||||
// The sha384 of library/scripts/posters/data/ne-places.json, served at <assets>/boundaries/ne-places.json.
|
||||
// Data, not code, but pinned the same way: a sheet uses the places only when they are the pinned ones.
|
||||
export const NE_PLACES_SHA384 = 'sha384-Qtz2q8mcnA9Ei8Kwa2MRMyX95hSbSnUXjXdtsy8rHTX++mgSCih4LO4Rdrb2MIQy'
|
||||
// The sha384 of the classic-script copy (<assets>/lib/poster-render.global.js, globalVariant of the file above),
|
||||
// loaded with <script integrity> where a page's policy forbids importing a blob: of the verified text.
|
||||
export const POSTER_RENDER_GLOBAL_SHA384 = 'sha384-idoDSzFXNuBK27dktAJffZD6QhubGkNOk+g9vwPobzs0HWHfnUq3cSyX7FyzwvtQ'
|
||||
export const POSTER_RENDER_GLOBAL_SHA384 = 'sha384-bc9b4cbOEA6LG0PxZhSYvOQPd+f7wptSbTT2knIUx+U7U+4KTHgttWKGPQDkJaoJ'
|
||||
// The sha384 of library/scripts/posters/packet-strings.json, served at <assets>/lib/packet-strings.json. The
|
||||
// packet, list and card text in every language, fetched at print time (packet/packetStrings.js) and used only
|
||||
// when it matches; otherwise the print falls back to the bundled English block.
|
||||
|
|
|
|||
|
|
@ -114,6 +114,13 @@ function geoToPath(geom, project) {
|
|||
}
|
||||
return d;
|
||||
}
|
||||
// A ring's own bbox [minX, minY, maxX, maxY] (one pass), for the point-in-ring skips.
|
||||
function ringBox(ring) {
|
||||
let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
|
||||
for (const [x, y] of ring) { if (x < x0) x0 = x; if (x > x1) x1 = x; if (y < y0) y0 = y; if (y > y1) y1 = y; }
|
||||
return [x0, y0, x1, y1];
|
||||
}
|
||||
|
||||
function bboxOf(geom) {
|
||||
const rings = geom.type === 'Polygon' ? geom.coordinates
|
||||
: geom.type === 'MultiPolygon' ? geom.coordinates.flat() : [];
|
||||
|
|
@ -1205,12 +1212,14 @@ async function renderPoster(zone, pins, zoneFC) {
|
|||
return hit;
|
||||
};
|
||||
const cand = [];
|
||||
const R = ringsOf(f.geometry);
|
||||
// Each ring with its bbox: a point outside a ring's bbox is never inside it (the parity test gives false), so
|
||||
// skipping those rings gives exactly the same answers and spares the vertex walk (the mobile print speed).
|
||||
const R = ringsOf(f.geometry).map((ring) => [ring, ringBox(ring)]);
|
||||
for (let gx = 1; gx <= 7; gx++) {
|
||||
for (let gy = 1; gy <= 7; gy++) {
|
||||
const cxp = best[0] + ((best[2] - best[0]) * gx) / 8;
|
||||
const cyp = best[1] + ((best[3] - best[1]) * gy) / 8;
|
||||
if (!R.some((ring) => inRing(cxp, cyp, ring))) continue;
|
||||
if (!R.some(([ring, b]) => cxp >= b[0] && cxp <= b[2] && cyp >= b[1] && cyp <= b[3] && inRing(cxp, cyp, ring))) continue;
|
||||
// score = distance to the nearest edge of the clipped box (keeps it central)
|
||||
const d = Math.min(cxp - best[0], best[2] - cxp, cyp - best[1], best[3] - cyp);
|
||||
cand.push({ cxp, cyp, d });
|
||||
|
|
@ -1356,7 +1365,13 @@ async function renderPoster(zone, pins, zoneFC) {
|
|||
else if (g.type === 'MultiPolygon') for (const poly of g.coordinates) landRings.push(poly[0]);
|
||||
}
|
||||
}
|
||||
const onLand = (lng, lat) => landRings.some((ring) => {
|
||||
// ★ MOBILE PRINT SPEED: every ring carries its bbox, and a point outside it skips the vertex walk. Exact: outside the
|
||||
// bbox the parity test is always false (no edge spans the latitude, or every crossing lies on one side of a closed
|
||||
// ring). On a phone this scan was most of a country poster's time (China ~45 s at CPU x4).
|
||||
const landBoxes = landRings.map(ringBox);
|
||||
const onLand = (lng, lat) => landRings.some((ring, k) => {
|
||||
const b = landBoxes[k];
|
||||
if (lng < b[0] || lng > b[2] || lat < b[1] || lat > b[3]) return false;
|
||||
let hit = false;
|
||||
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
||||
const [xi, yi] = ring[i], [xj, yj] = ring[j];
|
||||
|
|
@ -1386,10 +1401,10 @@ async function renderPoster(zone, pins, zoneFC) {
|
|||
const patches = [];
|
||||
for (let lng = viewBbox[0]; lng <= viewBbox[2]; lng += stepX) {
|
||||
for (let lat = viewBbox[1]; lat <= viewBbox[3]; lat += stepY) {
|
||||
if (onLand(lng, lat)) continue;
|
||||
const [px2, py2] = proj(lng, lat);
|
||||
if (px2 < FRAME_X + 60 || px2 > FRAME_X + FRAME_W - 60) continue;
|
||||
if (py2 < FRAME_Y + 40 || py2 > FRAME_Y + FRAME_H - 40) continue;
|
||||
if (onLand(lng, lat)) continue; // after the frame test: a point outside the frame never needed it
|
||||
patches.push({ lng, lat, px: px2, py: py2 });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue