// public/js/map/spatialIndex.js // =============================== // INDICE SPAZIALE FOTO (RBush) // =============================== (function () { "use strict"; if (!window.GP) { window.GP = {}; } if (!window.GP.libs?.RBush) { console.error("[spatialIndex] RBush non disponibile"); return; } const tree = new window.GP.libs.RBush(); const indexedIds = new Set(); let indexed = false; let totalItems = 0; function makeNode(item) { const lat = Number(item?.gps?.lat); const lng = Number(item?.gps?.lng); if ( item?.id == null || !Number.isFinite(lat) || !Number.isFinite(lng) || lat < -90 || lat > 90 || lng < -180 || lng > 180 ) { return null; } return { minX: lng, minY: lat, maxX: lng, maxY: lat, id: String(item.id), lat, lng, item, }; } function build(items) { tree.clear(); indexedIds.clear(); totalItems = 0; const nodes = []; for (const item of (Array.isArray(items) ? items : [])) { const node = makeNode(item); if (!node || indexedIds.has(node.id)) continue; indexedIds.add(node.id); nodes.push(node); } tree.load(nodes); indexed = true; totalItems = nodes.length; console.log("[spatialIndex] indicizzate", totalItems, "foto"); } function append(items) { if (!indexed) { build(items); return; } let added = 0; for (const item of (Array.isArray(items) ? items : [])) { const node = makeNode(item); if (!node || indexedIds.has(node.id)) continue; indexedIds.add(node.id); tree.insert(node); totalItems++; added++; } if (added) { console.log( "[spatialIndex] aggiunte", added, "foto; totale", totalItems ); } } function search(bounds) { if (!indexed) { return []; } // ricerca globale if (!bounds) { return tree.all(); } return tree.search({ minX: bounds.getWest(), minY: bounds.getSouth(), maxX: bounds.getEast(), maxY: bounds.getNorth(), }); } function clear() { tree.clear(); indexedIds.clear(); indexed = false; totalItems = 0; } function stats() { return { indexed, totalItems, }; } function isBuilt() { return indexed; } window.MapSpatialIndex = { build, append, search, clear, stats, isBuilt, }; })();