- EXIF-Extraktion: Automatische GPS/Kamera/Zeitstempel-Analyse bei Bildupload - Sonnenstand-Rechner: Azimut, Elevation, Schattenverhaeltnis fuer beliebige Position/Zeit - Reverse Geolocation: Erweiterte VLM-Analyse mit Landschaftsmerkmalen (Vegetation, Architektur, Strassen, Schilder) - Nachtlichter: NASA VIIRS Black Marble Layer - Hoehenprofil: Interaktives 2-Punkte-Tool mit SVG-Chart und Sichtlinienanalyse - Funkmasten: Mobilfunkinfrastruktur via Overpass (zoomabhaengig) Backend: data_geoint.py (EXIF, Sun, Elevation, Celltowers) Frontend: GEOINT Tools Section im Layer Panel
121 Zeilen
4.5 KiB
JavaScript
121 Zeilen
4.5 KiB
JavaScript
/**
|
|
* Funkmasten-Layer: Mobilfunkmasten aus OpenStreetMap via Overpass.
|
|
*/
|
|
const CelltowersLayer = {
|
|
_viewer: null,
|
|
_points: null,
|
|
_labels: null,
|
|
_count: 0,
|
|
_interval: null,
|
|
_lastBbox: null,
|
|
|
|
start: function(viewer) {
|
|
if (this._points) return;
|
|
this._viewer = viewer;
|
|
this._points = viewer.scene.primitives.add(new Cesium.PointPrimitiveCollection());
|
|
this._labels = viewer.scene.primitives.add(new Cesium.LabelCollection());
|
|
this._fetch();
|
|
var self = this;
|
|
this._interval = setInterval(function() { self._fetchIfMoved(); }, 8000);
|
|
},
|
|
|
|
stop: function() {
|
|
if (this._interval) { clearInterval(this._interval); this._interval = null; }
|
|
if (this._points && this._viewer) { this._viewer.scene.primitives.remove(this._points); this._points = null; }
|
|
if (this._labels && this._viewer) { this._viewer.scene.primitives.remove(this._labels); this._labels = null; }
|
|
this._count = 0;
|
|
this._lastBbox = null;
|
|
var c = document.getElementById('count-celltowers');
|
|
if (c) c.textContent = '-';
|
|
},
|
|
|
|
_getBbox: function() {
|
|
var rect = this._viewer.camera.computeViewRectangle();
|
|
if (!rect) return null;
|
|
return {
|
|
south: Cesium.Math.toDegrees(rect.south),
|
|
west: Cesium.Math.toDegrees(rect.west),
|
|
north: Cesium.Math.toDegrees(rect.north),
|
|
east: Cesium.Math.toDegrees(rect.east),
|
|
};
|
|
},
|
|
|
|
_fetchIfMoved: function() {
|
|
var bbox = this._getBbox();
|
|
if (!bbox) return;
|
|
// Nur bei deutlicher Bewegung neu laden
|
|
if (this._lastBbox) {
|
|
var dLat = Math.abs(bbox.south - this._lastBbox.south) + Math.abs(bbox.north - this._lastBbox.north);
|
|
var dLon = Math.abs(bbox.west - this._lastBbox.west) + Math.abs(bbox.east - this._lastBbox.east);
|
|
if (dLat + dLon < 0.5) return;
|
|
}
|
|
// Nur bei Zoom nah genug (< ~500 km Sichtfeld)
|
|
var cam = this._viewer.camera.positionCartographic;
|
|
if (cam && cam.height > 600000) return;
|
|
this._fetch();
|
|
},
|
|
|
|
_fetch: function() {
|
|
var bbox = this._getBbox();
|
|
if (!bbox) return;
|
|
// Viewport zu gross -> nicht laden
|
|
if (Math.abs(bbox.north - bbox.south) > 5 || Math.abs(bbox.east - bbox.west) > 5) {
|
|
var s = document.getElementById('status-celltowers');
|
|
if (s) { s.textContent = 'Naeher heranzoomen'; s.classList.add('active'); }
|
|
return;
|
|
}
|
|
this._lastBbox = bbox;
|
|
var self = this;
|
|
fetch('/api/geoint/celltowers', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(bbox),
|
|
})
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
self._render(data.towers || []);
|
|
})
|
|
.catch(function() {});
|
|
},
|
|
|
|
_render: function(towers) {
|
|
if (!this._points) return;
|
|
this._points.removeAll();
|
|
this._labels.removeAll();
|
|
|
|
var color = Cesium.Color.fromCssColorString('#e040fb');
|
|
var colorDim = color.withAlpha(0.6);
|
|
|
|
for (var i = 0; i < towers.length; i++) {
|
|
var t = towers[i];
|
|
this._points.add({
|
|
position: Cesium.Cartesian3.fromDegrees(t.lon, t.lat, 0),
|
|
pixelSize: 6,
|
|
color: color,
|
|
outlineColor: Cesium.Color.BLACK,
|
|
outlineWidth: 1,
|
|
});
|
|
var label = t.operator || t.name || '';
|
|
if (label && towers.length < 200) {
|
|
this._labels.add({
|
|
position: Cesium.Cartesian3.fromDegrees(t.lon, t.lat, 0),
|
|
text: label,
|
|
font: '9px monospace',
|
|
fillColor: colorDim,
|
|
outlineColor: Cesium.Color.BLACK,
|
|
outlineWidth: 2,
|
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
|
pixelOffset: new Cesium.Cartesian2(6, -4),
|
|
scale: 0.6,
|
|
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 100000),
|
|
});
|
|
}
|
|
}
|
|
this._count = towers.length;
|
|
var c = document.getElementById('count-celltowers');
|
|
if (c) c.textContent = this._count.toLocaleString('de-DE');
|
|
var s = document.getElementById('status-celltowers');
|
|
if (s) { s.textContent = ''; s.classList.remove('active'); }
|
|
},
|
|
};
|