feat: GEOINT-Toolkit mit 6 neuen Features
- 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
Dieser Commit ist enthalten in:
120
static/js/layers/celltowers.js
Normale Datei
120
static/js/layers/celltowers.js
Normale Datei
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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'); }
|
||||
},
|
||||
};
|
||||
36
static/js/layers/nightlights.js
Normale Datei
36
static/js/layers/nightlights.js
Normale Datei
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Nachtlicht-Layer: NASA VIIRS Black Marble Nighttime Lights.
|
||||
*/
|
||||
const NightlightsLayer = {
|
||||
_viewer: null,
|
||||
_layer: null,
|
||||
|
||||
start: function(viewer) {
|
||||
if (this._layer) return;
|
||||
this._viewer = viewer;
|
||||
this._layer = viewer.imageryLayers.addImageryProvider(
|
||||
new Cesium.WebMapTileServiceImageryProvider({
|
||||
url: 'https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/VIIRS_Black_Marble/default/2024-01-01/500m/{TileMatrix}/{TileRow}/{TileCol}.png',
|
||||
layer: 'VIIRS_Black_Marble',
|
||||
style: 'default',
|
||||
tileMatrixSetID: '500m',
|
||||
tileMatrixLabels: [
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8',
|
||||
],
|
||||
format: 'image/png',
|
||||
tilingScheme: new Cesium.GeographicTilingScheme(),
|
||||
tileWidth: 512,
|
||||
tileHeight: 512,
|
||||
credit: 'NASA VIIRS Black Marble',
|
||||
})
|
||||
);
|
||||
this._layer.alpha = 0.85;
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
if (this._layer && this._viewer) {
|
||||
this._viewer.imageryLayers.remove(this._layer);
|
||||
this._layer = null;
|
||||
}
|
||||
},
|
||||
};
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren