143 lines
2.5 KiB
JavaScript
143 lines
2.5 KiB
JavaScript
// 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,
|
|
};
|
|
})();
|