diff --git a/static/js/ui/vlm.js b/static/js/ui/vlm.js index 1cdad69..6d0e610 100644 --- a/static/js/ui/vlm.js +++ b/static/js/ui/vlm.js @@ -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,42 +296,90 @@ 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; - var bboxCb = document.getElementById('vlm-use-bbox'); - if (bboxCb && bboxCb.checked && Globe.viewer) { - var rect = Globe.viewer.camera.computeViewRectangle(); - if (rect) { - bbox = [ - Cesium.Math.toDegrees(rect.south), - Cesium.Math.toDegrees(rect.west), - Cesium.Math.toDegrees(rect.north), - Cesium.Math.toDegrees(rect.east), - ]; + 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(); + if (rect) { + bbox = [ + Cesium.Math.toDegrees(rect.south), + Cesium.Math.toDegrees(rect.west), + Cesium.Math.toDegrees(rect.north), + Cesium.Math.toDegrees(rect.east), + ]; + } } + // 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); - OverpassLayer.render(data); + // 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() {