feat: Globe-Suche nutzt jetzt EXIF + Region + Overpass kombiniert

- EXIF-GPS: Marker direkt auf Globus + Kamera fliegt hin
- EXIF-GPS als BBox (0.5 Grad Radius) fuer praezisere Overpass-Suche
- Region aus VLM/Landscape Clues als Fallback-BBox
- Statusanzeige zeigt alle genutzten Datenquellen
- Overpass-Ergebnisse werden mit EXIF-Marker kombiniert
Dieser Commit ist enthalten in:
Claude Dev
2026-03-26 09:18:38 +01:00
Ursprung ea436a4338
Commit 446b8b9228

Datei anzeigen

@@ -279,9 +279,10 @@ const VlmUI = {
_confirmAndSearch: function() {
if (!this._currentAnalysis) return;
var analysis = this._currentAnalysis;
// Ausgewaehlte Objekte sammeln
var objects = this._currentAnalysis.objects || [];
var objects = analysis.objects || [];
var selected = [];
objects.forEach(function(obj, idx) {
var cb = document.getElementById('vlm-obj-' + idx);
@@ -295,8 +296,49 @@ const VlmUI = {
return;
}
// BBox: Standard weltweit (null), optional auf Viewport einschraenken
// === EXIF-GPS: Marker setzen + dorthin fliegen ===
var exif = analysis.exif;
var hasExifGps = exif && exif.has_gps && exif.latitude && exif.longitude;
if (hasExifGps) {
// EXIF-Position als Marker auf dem Globus
OverpassLayer.start(Globe.viewer);
OverpassLayer.setColor('#e040fb');
var exifNode = {
nodes: [{
id: 'exif-gps',
lat: exif.latitude,
lon: exif.longitude,
tags: {
'source': 'EXIF GPS',
'camera': (exif.camera_make || '') + ' ' + (exif.camera_model || ''),
'timestamp': exif.timestamp || '',
'altitude': exif.altitude ? exif.altitude + 'm' : '',
},
name: 'EXIF GPS-Position',
}],
ways: [],
relations: [],
total: 1,
};
OverpassLayer.render(exifNode);
// Zur EXIF-Position fliegen
Globe.viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(exif.longitude, exif.latitude, 50000),
duration: 2,
});
}
// === BBox bestimmen: EXIF-GPS > Viewport-Checkbox > Region ===
var bbox = null;
if (hasExifGps) {
// 0.5 Grad um EXIF-Position
bbox = [
exif.latitude - 0.5,
exif.longitude - 0.5,
exif.latitude + 0.5,
exif.longitude + 0.5,
];
} else {
var bboxCb = document.getElementById('vlm-use-bbox');
if (bboxCb && bboxCb.checked && Globe.viewer) {
var rect = Globe.viewer.camera.computeViewRectangle();
@@ -309,28 +351,35 @@ const VlmUI = {
];
}
}
// Kein explizites BBox? Region wird vom Backend aus estimated_location_type abgeleitet
}
var btn = document.getElementById('vlm-search-btn');
if (btn) { btn.disabled = true; btn.textContent = 'SUCHE LAEUFT...'; }
var searchResult = document.getElementById('vlm-search-result');
if (searchResult) { searchResult.style.display = 'block'; searchResult.textContent = 'Generiere Overpass-Queries...'; searchResult.style.color = 'var(--text-dim)'; }
var statusParts = [];
if (hasExifGps) statusParts.push('EXIF GPS-Marker gesetzt');
if (searchResult) { searchResult.style.display = 'block'; searchResult.textContent = statusParts.join(' | ') + (statusParts.length ? ' | ' : '') + 'Generiere Overpass-Queries...'; searchResult.style.color = 'var(--text-dim)'; }
// 1. Queries generieren
// === Overpass-Suche mit allen verfuegbaren Daten ===
var startTime = Date.now();
fetch('/api/vlm/generate-queries', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ objects: selected, bbox: bbox, estimated_location_type: VlmUI._currentAnalysis.estimated_location_type || null }),
body: JSON.stringify({
objects: selected,
bbox: bbox,
estimated_location_type: analysis.estimated_location_type || null,
}),
})
.then(function(r) {
if (!r.ok) return r.json().then(function(d) { throw new Error(d.detail || 'Fehler'); });
return r.json();
})
.then(function(data) {
var regionInfo = data.region ? ' (Region: ' + data.region + ')' : ' (weltweit)';
if (searchResult) searchResult.textContent = 'Query generiert (' + data.tag_count + ' Tags)' + regionInfo + '. Suche OSM-Daten...';
var src = hasExifGps ? 'EXIF BBox' : (data.region ? 'Region: ' + data.region : 'weltweit');
if (searchResult) searchResult.textContent = statusParts.join(' | ') + (statusParts.length ? ' | ' : '') + 'Query generiert (' + data.tag_count + ' Tags, ' + src + '). Suche OSM-Daten...';
// 2. Overpass-Query direkt ausfuehren
OverpassLayer.setColor('#e040fb');
return fetch('/api/overpass/query', {
method: 'POST',
@@ -343,27 +392,47 @@ const VlmUI = {
return r.json().then(function(d) { throw new Error(d.detail || 'Rate-Limit'); });
}
if (!r.ok) {
return r.json().then(function(d) { throw new Error(d.detail || 'Overpass-Fehler'); });
return r.text().then(function(txt) {
try { var d = JSON.parse(txt); throw new Error(d.detail || 'Overpass-Fehler'); }
catch(e) { if (e.message && !e.message.startsWith('Unexpected')) throw e; throw new Error('Overpass-Fehler ' + r.status); }
});
}
return r.json();
})
.then(function(data) {
var elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
// Bei EXIF-GPS: Overpass-Ergebnisse zu bestehendem Marker hinzufuegen
if (hasExifGps && data.total > 0) {
// Bestehende EXIF-Daten beibehalten, Overpass hinzufuegen
var combined = {
nodes: [{ id: 'exif-gps', lat: exif.latitude, lon: exif.longitude, tags: { 'source': 'EXIF GPS' }, name: 'EXIF GPS-Position' }].concat(data.nodes || []),
ways: data.ways || [],
relations: data.relations || [],
total: 1 + data.total,
};
OverpassLayer.render(combined);
} else if (!hasExifGps) {
OverpassLayer.render(data);
}
if (searchResult) {
var text = data.total + ' Orte gefunden (' + elapsed + 's)';
var parts = [];
if (hasExifGps) parts.push('EXIF GPS-Marker');
parts.push(data.total + ' OSM-Orte');
var text = parts.join(' + ') + ' (' + elapsed + 's)';
if (data.cached) text += ' [Cache]';
if (data.truncated) text += ' [Limit erreicht]';
if (data.truncated) text += ' [Limit]';
searchResult.textContent = text;
searchResult.style.color = 'var(--accent)';
}
var countEl = document.getElementById('count-vlm');
if (countEl) countEl.textContent = data.total;
if (countEl) countEl.textContent = (hasExifGps ? 1 : 0) + data.total;
})
.catch(function(e) {
if (searchResult) {
searchResult.textContent = 'Fehler: ' + e.message;
searchResult.style.color = '#ff5252';
var prefix = hasExifGps ? 'EXIF GPS-Marker gesetzt | ' : '';
searchResult.textContent = prefix + 'Overpass-Fehler: ' + e.message;
searchResult.style.color = hasExifGps ? '#ff9800' : '#ff5252';
}
})
.finally(function() {