WME RTC Plus

RTC Management mit Kreisen, Perimeter-Sperrungen, GPX Import/Export

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         WME RTC Plus
// @namespace    http://tampermonkey.net/
// @version      2026.01.11
// @description  RTC Management mit Kreisen, Perimeter-Sperrungen, GPX Import/Export
// @namespace    https://greasyfork.org/de/users/863740-horst-wittlich
// @author       Hiwi234
// @match        https://*.waze.com/editor*
// @match        https://*.waze.com/*/editor*
// @match        https://beta.waze.com/editor*
// @match        https://beta.waze.com/*/editor*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=waze.com
// @grant        none
// @license      MIT
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    let uOpenLayers;
    let uWaze;
    let radiusLayer, infoLayer;
    let polygonControl, freehandControl, dragControl;
    let eventListeners = [];
    let modificationHistory = [];
    let presetCircleMode = false;
    let presetCircleCenter = null;
    const DEBUG = true;
    const EARTH_RADIUS = 6371000;

    // Translations
    const translations = {
        en: {
            tabTitle: 'RTC +',
            title: 'WME RTC Plus',
            enableCircle: 'Enable Circle Drawing',
            enableFreehand: 'Enable Free Hand Drawing',
            selectStreets: 'Select / Start',
            undoLastCircle: 'Undo',
            clearCircles: 'Clear Circles',
            displayOptions: 'Display Options:',
            showRadius: 'Show Radius',
            showDiameter: 'Show Diameter',
            showArea: 'Show Area',
            imperialUnits: 'Imperial Units (ft/mi)',
            filterOptions: 'Filter Options:',
            onlyDrivable: 'Only drivable segments',
            perimeterBlocking: 'Perimeter Blocking:',
            blockInbound: 'Block perimeter inbound only',
            blockInboundHint: '(hollow circle - exit allowed)',
            rtcSettings: 'RTC Settings:',
            rtcReason: 'Closure reason:',
            rtcDuration: 'Duration:',
            rtcHours: 'hrs',
            rtcMinutes: 'min',
            rtcDefaultReason: 'Perimeter closure',
            rtcModeDuration: 'Duration',
            rtcModeEndDate: 'End date',
            rtcEndDate: 'End',
            deleteRtcsInArea: 'Delete RTCs in area',
            deletingRtcs: 'Deleting RTCs...',
            rtcsDeleted: '✓ {0} RTCs deleted',
            noRtcsFound: 'No RTCs found in area',
            currentRadius: 'Current Radius',
            circlesCleared: 'Circles cleared',
            noCirclesToUndo: 'No circles to undo',
            removedCircle: 'Removed last circle',
            remaining: 'remaining',
            errorRemoving: 'Error removing circle',
            selectedSegments: 'Selected {0} segments',
            noSegmentsFound: 'No segments found in circles',
            appliedRestrictions: '✓ Applied RTC to {0} segments (inbound blocked)',
            noModification: '⚠ No segments needed modification ({0} processed)',
            presetCircle: 'Preset Circle:',
            presetRadius: 'Radius:',
            presetHint: 'Create Circle',
            clickForCenter: 'Click for center',
            circleCreated: 'Circle created ({0}m)',
            moveCircles: 'Move circles',
            moveHint: 'Drag circles to move them',
            createMapComment: 'Create Map Comment',
            mapCommentOptions: 'Map Comment Options:',
            commentTitle: 'Title:',
            commentDesc: 'Description:',
            expiresIn: 'Expires in:',
            days: 'days',
            createFromCircle: 'Create from last circle',
            noCircleToConvert: 'No circle to convert',
            mapCommentCreated: 'Map Comment created!',
            selectCircleFirst: 'Draw a circle first',
            brushMode: 'Segment Brush',
            brushModeHint: 'Paint to select segments',
            brushErase: 'Erase mode',
            brushModeActive: 'Segment brush active',
            exportRtcs: 'Export RTCs',
            importRtcs: 'Import RTCs',
            exportedRtcs: '✓ {0} RTCs exported',
            importedRtcs: '✓ {0} RTCs imported',
            noRtcsToExport: 'No RTCs to export',
            importExport: 'Import/Export:',
            exportTypeRtcs: 'RTCs',
            exportTypeCircles: 'Circles',
            exportedCircles: '✓ {0} circles exported',
            importedCircles: '✓ {0} circles imported',
            noCirclesToExport: 'No circles to export',
            exportTypeGpx: 'GPX',
            importedGpx: '✓ GPX imported: {0} segments matched',
            exportedGpx: '✓ GPX exported',
            gpxNoSegments: 'No segments matched from GPX'
        },
        de: {
            tabTitle: 'RTC +',
            title: 'WME RTC Plus',
            enableCircle: 'Kreis zeichnen aktivieren',
            enableFreehand: 'Freihand zeichnen aktivieren',
            selectStreets: 'Auswahl / Start',
            undoLastCircle: 'Zurück',
            clearCircles: 'Kreise löschen',
            displayOptions: 'Anzeigeoptionen:',
            showRadius: 'Radius anzeigen',
            showDiameter: 'Durchmesser anzeigen',
            showArea: 'Fläche anzeigen',
            imperialUnits: 'Imperiale Einheiten (ft/mi)',
            filterOptions: 'Filteroptionen:',
            onlyDrivable: 'Nur befahrbare Segmente',
            perimeterBlocking: 'Perimeter-Sperrung:',
            blockInbound: 'Nur eingehenden Verkehr sperren',
            blockInboundHint: '(hohler Kreis - Ausfahrt erlaubt)',
            rtcSettings: 'RTC Einstellungen:',
            rtcReason: 'Sperrgrund:',
            rtcDuration: 'Sperrdauer:',
            rtcHours: 'Std',
            rtcMinutes: 'Min',
            rtcDefaultReason: 'Perimeter-Sperrung',
            rtcModeDuration: 'Dauer',
            rtcModeEndDate: 'Enddatum',
            rtcEndDate: 'Ende',
            deleteRtcsInArea: 'RTCs im Bereich löschen',
            deletingRtcs: 'Lösche RTCs...',
            rtcsDeleted: '✓ {0} RTCs gelöscht',
            noRtcsFound: 'Keine RTCs im Bereich gefunden',
            currentRadius: 'Aktueller Radius',
            circlesCleared: 'Kreise gelöscht',
            noCirclesToUndo: 'Keine Kreise zum Rückgängigmachen',
            removedCircle: 'Letzten Kreis entfernt',
            remaining: 'übrig',
            errorRemoving: 'Fehler beim Entfernen',
            selectedSegments: '{0} Segmente ausgewählt',
            noSegmentsFound: 'Keine Segmente in Kreisen gefunden',
            appliedRestrictions: '✓ RTC auf {0} Segmente angewendet (Einfahrt gesperrt)',
            noModification: '⚠ Keine Segmente mussten geändert werden ({0} verarbeitet)',
            presetCircle: 'Vorbereiteter Kreis:',
            presetRadius: 'Radius:',
            presetHint: 'Kreis Erstellen',
            clickForCenter: 'Klicke für Mittelpunkt',
            circleCreated: 'Kreis erstellt ({0}m)',
            moveCircles: 'Kreise verschieben',
            moveHint: 'Kreise ziehen zum Verschieben',
            createMapComment: 'Map Comment erstellen',
            mapCommentOptions: 'Map Comment Optionen:',
            commentTitle: 'Titel:',
            commentDesc: 'Beschreibung:',
            expiresIn: 'Läuft ab in:',
            days: 'Tagen',
            createFromCircle: 'Aus letztem Kreis erstellen',
            noCircleToConvert: 'Kein Kreis vorhanden',
            mapCommentCreated: 'Map Comment erstellt!',
            selectCircleFirst: 'Erst einen Kreis zeichnen',
            brushMode: 'Segment-Pinsel',
            brushModeHint: 'Malen um Segmente auszuwählen',
            brushErase: 'Löschen-Modus',
            brushModeActive: 'Segment-Pinsel aktiv',
            exportRtcs: 'RTCs exportieren',
            importRtcs: 'RTCs importieren',
            exportedRtcs: '✓ {0} RTCs exportiert',
            importedRtcs: '✓ {0} RTCs importiert',
            noRtcsToExport: 'Keine RTCs zum Exportieren',
            importExport: 'Import/Export:',
            exportTypeRtcs: 'RTCs',
            exportTypeCircles: 'Kreise',
            exportedCircles: '✓ {0} Kreise exportiert',
            importedCircles: '✓ {0} Kreise importiert',
            noCirclesToExport: 'Keine Kreise zum Exportieren',
            exportTypeGpx: 'GPX',
            importedGpx: '✓ GPX importiert: {0} Segmente gematcht',
            exportedGpx: '✓ GPX exportiert',
            gpxNoSegments: 'Keine Segmente aus GPX gematcht'
        },
        fr: {
            tabTitle: 'RTC +',
            title: 'WME RTC Plus',
            enableCircle: 'Activer le dessin de cercle',
            enableFreehand: 'Activer le dessin à main levée',
            selectStreets: 'Sélection / Démarrer',
            undoLastCircle: 'Annuler',
            clearCircles: 'Effacer les cercles',
            displayOptions: "Options d'affichage:",
            showRadius: 'Afficher le rayon',
            showDiameter: 'Afficher le diamètre',
            showArea: 'Afficher la surface',
            imperialUnits: 'Unités impériales (ft/mi)',
            filterOptions: 'Options de filtre:',
            onlyDrivable: 'Segments praticables uniquement',
            perimeterBlocking: 'Blocage du périmètre:',
            blockInbound: 'Bloquer uniquement le trafic entrant',
            blockInboundHint: '(cercle creux - sortie autorisée)',
            currentRadius: 'Rayon actuel',
            circlesCleared: 'Cercles effacés',
            noCirclesToUndo: 'Aucun cercle à annuler',
            removedCircle: 'Dernier cercle supprimé',
            remaining: 'restant(s)',
            errorRemoving: 'Erreur lors de la suppression',
            selectedSegments: '{0} segments sélectionnés',
            noSegmentsFound: 'Aucun segment trouvé dans les cercles',
            appliedRestrictions: '✓ Restrictions de direction appliquées à {0} segments (sortie préservée)',
            noModification: '⚠ Aucun segment à modifier ({0} traités)',
            presetCircle: 'Cercle prédéfini:',
            presetRadius: 'Rayon:',
            presetHint: 'Créer Cercle',
            clickForCenter: 'Cliquez pour centre',
            circleCreated: 'Cercle créé ({0}m)',
            moveCircles: 'Déplacer les cercles',
            moveHint: 'Glisser pour déplacer',
            createMapComment: 'Créer Map Comment',
            mapCommentOptions: 'Options Map Comment:',
            commentTitle: 'Titre:',
            commentDesc: 'Description:',
            expiresIn: 'Expire dans:',
            days: 'jours',
            createFromCircle: 'Créer depuis dernier cercle',
            noCircleToConvert: 'Aucun cercle disponible',
            mapCommentCreated: 'Map Comment créé!',
            selectCircleFirst: 'Dessinez un cercle d\'abord',
            brushMode: 'Pinceau segments',
            brushModeHint: 'Peindre pour sélectionner',
            brushErase: 'Mode effacer',
            brushModeActive: 'Pinceau segments actif',
            exportRtcs: 'Exporter RTCs',
            importRtcs: 'Importer RTCs',
            exportedRtcs: '✓ {0} RTCs exportés',
            importedRtcs: '✓ {0} RTCs importés',
            noRtcsToExport: 'Aucun RTC à exporter',
            importExport: 'Import/Export:',
            exportTypeRtcs: 'RTCs',
            exportTypeCircles: 'Cercles',
            exportedCircles: '✓ {0} cercles exportés',
            importedCircles: '✓ {0} cercles importés',
            noCirclesToExport: 'Aucun cercle à exporter',
            exportTypeGpx: 'GPX',
            importedGpx: '✓ GPX importé: {0} segments matchés',
            exportedGpx: '✓ GPX exporté',
            gpxNoSegments: 'Aucun segment matché depuis GPX'
        },
        it: {
            tabTitle: 'RTC +',
            title: 'WME RTC Plus',
            enableCircle: 'Attiva disegno cerchio',
            enableFreehand: 'Attiva disegno a mano libera',
            selectStreets: 'Selezione / Avvia',
            undoLastCircle: 'Annulla',
            clearCircles: 'Cancella cerchi',
            displayOptions: 'Opzioni di visualizzazione:',
            showRadius: 'Mostra raggio',
            showDiameter: 'Mostra diametro',
            showArea: 'Mostra area',
            imperialUnits: 'Unità imperiali (ft/mi)',
            filterOptions: 'Opzioni filtro:',
            onlyDrivable: 'Solo segmenti percorribili',
            perimeterBlocking: 'Blocco perimetrale:',
            blockInbound: 'Blocca solo traffico in entrata',
            blockInboundHint: '(cerchio vuoto - uscita consentita)',
            currentRadius: 'Raggio attuale',
            circlesCleared: 'Cerchi cancellati',
            noCirclesToUndo: 'Nessun cerchio da annullare',
            removedCircle: 'Ultimo cerchio rimosso',
            remaining: 'rimanenti',
            errorRemoving: 'Errore nella rimozione',
            selectedSegments: '{0} segmenti selezionati',
            noSegmentsFound: 'Nessun segmento trovato nei cerchi',
            appliedRestrictions: '✓ Restrizioni di direzione applicate a {0} segmenti (uscita preservata)',
            noModification: '⚠ Nessun segmento da modificare ({0} elaborati)',
            presetCircle: 'Cerchio predefinito:',
            presetRadius: 'Raggio:',
            presetHint: 'Crea Cerchio',
            clickForCenter: 'Clicca per centro',
            circleCreated: 'Cerchio creato ({0}m)',
            moveCircles: 'Sposta i cerchi',
            moveHint: 'Trascina per spostare',
            createMapComment: 'Crea Map Comment',
            mapCommentOptions: 'Opzioni Map Comment:',
            commentTitle: 'Titolo:',
            commentDesc: 'Descrizione:',
            expiresIn: 'Scade tra:',
            days: 'giorni',
            createFromCircle: 'Crea dall\'ultimo cerchio',
            noCircleToConvert: 'Nessun cerchio disponibile',
            mapCommentCreated: 'Map Comment creato!',
            selectCircleFirst: 'Prima disegna un cerchio',
            brushMode: 'Pennello segmenti',
            brushModeHint: 'Dipingi per selezionare',
            brushErase: 'Modalità cancella',
            brushModeActive: 'Pennello segmenti attivo',
            exportRtcs: 'Esporta RTCs',
            importRtcs: 'Importa RTCs',
            exportedRtcs: '✓ {0} RTCs esportati',
            importedRtcs: '✓ {0} RTCs importati',
            noRtcsToExport: 'Nessun RTC da esportare',
            importExport: 'Import/Export:',
            exportTypeRtcs: 'RTCs',
            exportTypeCircles: 'Cerchi',
            exportedCircles: '✓ {0} cerchi esportati',
            importedCircles: '✓ {0} cerchi importati',
            noCirclesToExport: 'Nessun cerchio da esportare',
            exportTypeGpx: 'GPX',
            importedGpx: '✓ GPX importato: {0} segmenti matchati',
            exportedGpx: '✓ GPX esportato',
            gpxNoSegments: 'Nessun segmento matchato da GPX'
        },
        es: {
            tabTitle: 'RTC +',
            title: 'WME RTC Plus',
            enableCircle: 'Activar dibujo de círculo',
            enableFreehand: 'Activar dibujo a mano alzada',
            selectStreets: 'Selección / Iniciar',
            undoLastCircle: 'Deshacer',
            clearCircles: 'Borrar círculos',
            displayOptions: 'Opciones de visualización:',
            showRadius: 'Mostrar radio',
            showDiameter: 'Mostrar diámetro',
            showArea: 'Mostrar área',
            imperialUnits: 'Unidades imperiales (ft/mi)',
            filterOptions: 'Opciones de filtro:',
            onlyDrivable: 'Solo segmentos transitables',
            perimeterBlocking: 'Bloqueo de perímetro:',
            blockInbound: 'Bloquear solo tráfico entrante',
            blockInboundHint: '(círculo hueco - salida permitida)',
            currentRadius: 'Radio actual',
            circlesCleared: 'Círculos borrados',
            noCirclesToUndo: 'No hay círculos para deshacer',
            removedCircle: 'Último círculo eliminado',
            remaining: 'restantes',
            errorRemoving: 'Error al eliminar',
            selectedSegments: '{0} segmentos seleccionados',
            noSegmentsFound: 'No se encontraron segmentos en los círculos',
            appliedRestrictions: '✓ Restricciones de dirección aplicadas a {0} segmentos (salida preservada)',
            noModification: '⚠ Ningún segmento necesitó modificación ({0} procesados)',
            presetCircle: 'Círculo predefinido:',
            presetRadius: 'Radio:',
            presetHint: 'Crear Círculo',
            clickForCenter: 'Clic para centro',
            circleCreated: 'Círculo creado ({0}m)',
            moveCircles: 'Mover los círculos',
            moveHint: 'Arrastra para mover',
            createMapComment: 'Crear Map Comment',
            mapCommentOptions: 'Opciones Map Comment:',
            commentTitle: 'Título:',
            commentDesc: 'Descripción:',
            expiresIn: 'Expira en:',
            days: 'días',
            createFromCircle: 'Crear desde último círculo',
            noCircleToConvert: 'No hay círculo disponible',
            mapCommentCreated: '¡Map Comment creado!',
            selectCircleFirst: 'Primero dibuja un círculo',
            brushMode: 'Pincel segmentos',
            brushModeHint: 'Pintar para seleccionar',
            brushErase: 'Modo borrar',
            brushModeActive: 'Pincel segmentos activo',
            exportRtcs: 'Exportar RTCs',
            importRtcs: 'Importar RTCs',
            exportedRtcs: '✓ {0} RTCs exportados',
            importedRtcs: '✓ {0} RTCs importados',
            noRtcsToExport: 'No hay RTCs para exportar',
            importExport: 'Import/Export:',
            exportTypeRtcs: 'RTCs',
            exportTypeCircles: 'Círculos',
            exportedCircles: '✓ {0} círculos exportados',
            importedCircles: '✓ {0} círculos importados',
            noCirclesToExport: 'No hay círculos para exportar',
            exportTypeGpx: 'GPX',
            importedGpx: '✓ GPX importado: {0} segmentos matcheados',
            exportedGpx: '✓ GPX exportado',
            gpxNoSegments: 'Ningún segmento matcheado desde GPX'
        },
        nl: {
            tabTitle: 'RTC +',
            title: 'WME RTC Plus',
            enableCircle: 'Cirkel tekenen inschakelen',
            enableFreehand: 'Vrije hand tekenen inschakelen',
            selectStreets: 'Selectie / Start',
            undoLastCircle: 'Ongedaan',
            clearCircles: 'Cirkels wissen',
            displayOptions: 'Weergaveopties:',
            showRadius: 'Straal tonen',
            showDiameter: 'Diameter tonen',
            showArea: 'Oppervlakte tonen',
            imperialUnits: 'Imperiale eenheden (ft/mi)',
            filterOptions: 'Filteropties:',
            onlyDrivable: 'Alleen berijdbare segmenten',
            perimeterBlocking: 'Perimeterblokkering:',
            blockInbound: 'Alleen inkomend verkeer blokkeren',
            blockInboundHint: '(holle cirkel - uitgang toegestaan)',
            currentRadius: 'Huidige straal',
            circlesCleared: 'Cirkels gewist',
            noCirclesToUndo: 'Geen cirkels om ongedaan te maken',
            removedCircle: 'Laatste cirkel verwijderd',
            remaining: 'resterend',
            errorRemoving: 'Fout bij verwijderen',
            selectedSegments: '{0} segmenten geselecteerd',
            noSegmentsFound: 'Geen segmenten gevonden in cirkels',
            appliedRestrictions: '✓ Richtingsbeperkingen toegepast op {0} segmenten (uitgang behouden)',
            noModification: '⚠ Geen segmenten hoefden te worden gewijzigd ({0} verwerkt)',
            presetCircle: 'Vooraf ingestelde cirkel:',
            presetRadius: 'Straal:',
            presetHint: 'Cirkel Maken',
            clickForCenter: 'Klik voor middelpunt',
            circleCreated: 'Cirkel gemaakt ({0}m)',
            moveCircles: 'Cirkels verplaatsen',
            moveHint: 'Sleep om te verplaatsen',
            createMapComment: 'Map Comment maken',
            mapCommentOptions: 'Map Comment Opties:',
            commentTitle: 'Titel:',
            commentDesc: 'Beschrijving:',
            expiresIn: 'Verloopt over:',
            days: 'dagen',
            createFromCircle: 'Maken van laatste cirkel',
            noCircleToConvert: 'Geen cirkel beschikbaar',
            mapCommentCreated: 'Map Comment gemaakt!',
            selectCircleFirst: 'Teken eerst een cirkel',
            brushMode: 'Segment-penseel',
            brushModeHint: 'Schilderen om te selecteren',
            brushErase: 'Wis-modus',
            brushModeActive: 'Segment-penseel actief',
            exportRtcs: 'RTCs exporteren',
            importRtcs: 'RTCs importeren',
            exportedRtcs: '✓ {0} RTCs geëxporteerd',
            importedRtcs: '✓ {0} RTCs geïmporteerd',
            noRtcsToExport: 'Geen RTCs om te exporteren',
            importExport: 'Import/Export:',
            exportTypeRtcs: 'RTCs',
            exportTypeCircles: 'Cirkels',
            exportedCircles: '✓ {0} cirkels geëxporteerd',
            importedCircles: '✓ {0} cirkels geïmporteerd',
            noCirclesToExport: 'Geen cirkels om te exporteren',
            exportTypeGpx: 'GPX',
            importedGpx: '✓ GPX geïmporteerd: {0} segmenten gematcht',
            exportedGpx: '✓ GPX geëxporteerd',
            gpxNoSegments: 'Geen segmenten gematcht uit GPX'
        }
    };

    let currentLang = 'en';

    function detectLanguage() {
        try {
            // 1. WME I18n Sprache (Benutzereinstellung im Editor)
            if (window.I18n?.currentLocale) {
                const locale = window.I18n.currentLocale();
                const lang = locale.split('-')[0].toLowerCase();
                if (translations[lang]) return lang;
            }

            // 2. Fallback: Browser-Sprache
            const browserLang = navigator.language?.substring(0, 2) || 'en';
            if (translations[browserLang]) return browserLang;

            return 'en';
        } catch (e) {
            return 'en';
        }
    }

    function t(key, ...args) {
        let text = translations[currentLang]?.[key] || translations['en'][key] || key;
        args.forEach((arg, i) => {
            text = text.replace(`{${i}}`, arg);
        });
        return text;
    }

    function log(message, data = null) {
        if (DEBUG) {
            console.log(`[WME RTC Plus] ${message}`, data || '');
        }
    }

    function warn(message, data = null) {
        console.warn(`[WME RTC Plus] ${message}`, data || '');
    }

    // Befahrbare Segment-Typen (roadType Werte)
    // 1=Street, 2=Primary, 3=Freeway, 4=Ramp, 6=Major Highway, 7=Minor Highway, 21=Narrow Street
    const DRIVABLE_ROAD_TYPES = new Set([1, 2, 3, 4, 6, 7, 21]);

    function isDrivableSegment(segment) {
        const type = segment?.attributes?.roadType;
        return type && DRIVABLE_ROAD_TYPES.has(type);
    }

    // Settings Storage
    const STORAGE_KEY = 'wme-rtc-plus-settings';

    function loadSettings() {
        try {
            const saved = localStorage.getItem(STORAGE_KEY);
            return saved ? JSON.parse(saved) : {};
        } catch (e) { return {}; }
    }

    function saveSettings(settings) {
        try {
            const current = loadSettings();
            localStorage.setItem(STORAGE_KEY, JSON.stringify({ ...current, ...settings }));
        } catch (e) { warn('Settings save error:', e); }
    }

    function addEventListenerWithCleanup(element, event, handler) {
        if (!element) return;
        element.addEventListener(event, handler);
        eventListeners.push({ element, event, handler });
    }

    function cleanupEventListeners() {
        eventListeners.forEach(({ element, event, handler }) => {
            try {
                element.removeEventListener(event, handler);
            } catch (e) {
                warn('Error removing event listener:', e);
            }
        });
        eventListeners = [];
    }

    function initializeScript() {
        uWaze = window.W;
        uOpenLayers = window.OpenLayers;

        if (!uWaze || !uOpenLayers || !uWaze.map) {
            log('WME objects not ready, retrying...');
            setTimeout(initializeScript, 500);
            return;
        }

        currentLang = detectLanguage();
        log(`Initializing with language: ${currentLang}`);
        radiusInit();
    }

    function addSidePanel() {
        try {
            const { tabLabel, tabPane } = W.userscripts.registerSidebarTab("wme-rtc-plus");

            tabLabel.innerText = t('tabTitle');
            tabLabel.title = 'WME RTC Plus';

            setupSidebarContent(tabPane);
        } catch (error) {
            log('New API failed, using fallback:', error);
            addSidePanelFallback();
        }
    }

    function addSidePanelFallback() {
        let userTabs = document.getElementById('user-info');
        if (!userTabs) {
            setTimeout(addSidePanelFallback, 1000);
            return;
        }

        let navTabs = userTabs.getElementsByClassName('nav-tabs')[0];
        let tabContent = userTabs.getElementsByClassName('tab-content')[0];

        if (!navTabs || !tabContent) {
            setTimeout(addSidePanelFallback, 1000);
            return;
        }

        let tab = document.createElement('li');
        tab.innerHTML = `<a href="#sidepanel-wme-rtc-plus" data-toggle="tab">${t('tabTitle')}</a>`;
        navTabs.appendChild(tab);

        let tabPane = document.createElement('section');
        tabPane.id = "sidepanel-wme-rtc-plus";
        tabPane.className = "tab-pane";
        tabContent.appendChild(tabPane);

        setupSidebarContent(tabPane);
    }

    function setupSidebarContent(tabPane) {
        tabPane.innerHTML = `
            <div style="padding:6px;font-size:12px;">
                <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px;">
                    <h4 style="margin:0;">${t('title')}</h4>
                    <span style="font-size:9px;color:#999;">v2026.01.03.24</span>
                </div>
                <div id="circles-current-radius" style="font-size:10px;color:#666;margin-bottom:4px;"></div>

                <div style="margin-bottom:6px;">
                    <label style="display:flex;align-items:center;cursor:pointer;margin-bottom:2px;font-size:11px;">
                        <input type="checkbox" id="wme-circles-edit-mode" style="margin-right:4px;">${t('enableCircle')}
                    </label>
                    <label style="display:flex;align-items:center;cursor:pointer;margin-bottom:2px;font-size:11px;">
                        <input type="checkbox" id="wme-freehand-edit-mode" style="margin-right:4px;">${t('enableFreehand')}
                    </label>
                    <label style="display:flex;align-items:center;cursor:pointer;margin-bottom:2px;font-size:11px;">
                        <input type="checkbox" id="wme-circles-move-mode" style="margin-right:4px;">${t('moveCircles')}
                    </label>
                    <label style="display:flex;align-items:center;cursor:pointer;font-size:11px;">
                        <input type="checkbox" id="wme-brush-mode" style="margin-right:4px;">🖌️ ${t('brushMode')}
                    </label>
                    <label style="display:none;align-items:center;cursor:pointer;font-size:11px;margin-left:18px;" id="brush-erase-label">
                        <input type="checkbox" id="wme-brush-erase" style="margin-right:4px;">🧹 ${t('brushErase')}
                    </label>
                    <div id="brush-mode-hint" style="display:none;font-size:9px;color:#666;margin-left:18px;">${t('brushModeHint')}</div>
                </div>

                <div style="padding:4px;background:#e3f2fd;border-radius:3px;margin-bottom:6px;">
                    <div style="display:flex;align-items:center;gap:4px;">
                        <span style="font-size:10px;">📐</span>
                        <span style="font-size:10px;">${t('presetRadius')}</span>
                        <input type="number" id="wme-preset-radius" min="5" max="5000" value="500" style="width:60px;padding:2px 4px;border:1px solid #ccc;border-radius:3px;font-size:11px;">
                        <span style="font-size:11px;">m</span>
                        <button id="wme-preset-circle-btn" style="flex:1;padding:4px;background:#2196F3;color:white;border:none;border-radius:3px;cursor:pointer;font-size:11px;">📍</button>
                    </div>
                    <button id="wme-preset-cancel-btn" style="width:100%;padding:4px;background:#f44336;color:white;border:none;border-radius:3px;cursor:pointer;margin-top:4px;display:none;font-size:11px;">❌</button>
                </div>

                <div style="display:grid;grid-template-columns:1fr 1fr;gap:3px;margin-bottom:6px;">
                    <button id="wme-circles-select" style="padding:4px;background:#4CAF50;color:white;border:none;border-radius:3px;cursor:pointer;font-size:10px;">${t('selectStreets')}</button>
                    <button id="wme-circles-undo" style="padding:4px;background:#2196F3;color:white;border:none;border-radius:3px;cursor:pointer;font-size:10px;">↩️ ${t('undoLastCircle')}</button>
                    <button id="wme-circles-clear" style="padding:4px;background:#f44336;color:white;border:none;border-radius:3px;cursor:pointer;font-size:10px;">🗑️ ${t('clearCircles')}</button>
                    <button id="wme-circles-delete-rtcs" style="padding:4px;background:#ff5722;color:white;border:none;border-radius:3px;cursor:pointer;font-size:10px;">🗑️ RTCs</button>
                </div>

                <details style="margin-bottom:6px;">
                    <summary style="cursor:pointer;padding:3px;background:#f5f5f5;border-radius:3px;font-size:10px;"><strong>${t('displayOptions')}</strong></summary>
                    <div style="padding:4px;background:#f5f5f5;border-radius:0 0 3px 3px;">
                        <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px;">
                            <span style="font-size:10px;">${t('showRadius')}</span>
                            <label class="ts"><input type="checkbox" id="show-radius"><span class="sl"></span></label>
                        </div>
                        <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px;">
                            <span style="font-size:10px;">${t('showDiameter')}</span>
                            <label class="ts"><input type="checkbox" id="show-diameter"><span class="sl"></span></label>
                        </div>
                        <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px;">
                            <span style="font-size:10px;">${t('showArea')}</span>
                            <label class="ts"><input type="checkbox" id="show-area"><span class="sl"></span></label>
                        </div>
                        <div style="display:flex;justify-content:space-between;align-items:center;">
                            <span style="font-size:10px;">${t('imperialUnits')}</span>
                            <label class="ts"><input type="checkbox" id="use-imperial"><span class="sl"></span></label>
                        </div>
                    </div>
                </details>

                <div style="display:flex;justify-content:space-between;align-items:center;padding:4px;background:#f5f5f5;border-radius:3px;margin-bottom:6px;">
                    <span style="font-size:10px;">${t('onlyDrivable')}</span>
                    <label class="ts"><input type="checkbox" id="filter-drivable-only"><span class="sl"></span></label>
                </div>

                <details style="margin-bottom:6px;">
                    <summary style="cursor:pointer;padding:3px;background:#e8f5e8;border-radius:3px;font-size:10px;"><strong>${t('perimeterBlocking')}</strong></summary>
                    <div style="padding:4px;background:#e8f5e8;border-radius:0 0 3px 3px;">
                        <div style="display:flex;justify-content:space-between;align-items:center;">
                            <div>
                                <div style="font-size:10px;">${t('blockInbound')}</div>
                                <div style="font-size:8px;color:#666;">${t('blockInboundHint')}</div>
                            </div>
                            <label class="ts"><input type="checkbox" id="block-inbound-only"><span class="sl"></span></label>
                        </div>
                        <div id="rtc-duration-settings" style="margin-top:6px;padding-top:6px;border-top:1px solid #c8e6c9;display:none;">
                            <div style="margin-bottom:4px;">
                                <label style="font-size:9px;margin-right:6px;"><input type="radio" name="rtc-mode" id="rtc-mode-duration" checked> ${t('rtcModeDuration')}</label>
                                <label style="font-size:9px;"><input type="radio" name="rtc-mode" id="rtc-mode-enddate"> ${t('rtcModeEndDate')}</label>
                            </div>
                            <div id="rtc-duration-inputs" style="display:flex;align-items:center;gap:3px;flex-wrap:wrap;">
                                <input type="number" id="rtc-duration-days" min="0" max="365" value="0" style="width:35px;padding:2px;border:1px solid #ccc;border-radius:3px;font-size:9px;">
                                <span style="font-size:9px;">${t('days')}</span>
                                <input type="number" id="rtc-duration-hours" min="0" max="23" value="24" style="width:35px;padding:2px;border:1px solid #ccc;border-radius:3px;font-size:9px;">
                                <span style="font-size:9px;">${t('rtcHours')}</span>
                                <input type="number" id="rtc-duration-minutes" min="0" max="59" value="0" style="width:35px;padding:2px;border:1px solid #ccc;border-radius:3px;font-size:9px;">
                                <span style="font-size:9px;">${t('rtcMinutes')}</span>
                            </div>
                            <div id="rtc-enddate-inputs" style="display:none;">
                                <div style="display:flex;align-items:center;gap:3px;">
                                    <input type="date" id="rtc-end-date" style="padding:2px;border:1px solid #ccc;border-radius:3px;font-size:9px;flex:1;">
                                    <input type="time" id="rtc-end-time" value="23:59" style="width:60px;padding:2px;border:1px solid #ccc;border-radius:3px;font-size:9px;">
                                </div>
                            </div>
                        </div>
                    </div>
                </details>

                <details style="margin-bottom:6px;">
                    <summary style="cursor:pointer;padding:3px;background:#fff3e0;border-radius:3px;font-size:10px;"><strong>💬 ${t('createMapComment')}</strong></summary>
                    <div style="padding:4px;background:#fff3e0;border-radius:0 0 3px 3px;">
                        <input type="text" id="wme-mc-title" maxlength="30" placeholder="${t('commentTitle')}" style="width:100%;padding:3px;border:1px solid #ccc;border-radius:3px;box-sizing:border-box;font-size:10px;margin-bottom:3px;">
                        <textarea id="wme-mc-desc" rows="1" placeholder="${t('commentDesc')}" style="width:100%;padding:3px;border:1px solid #ccc;border-radius:3px;box-sizing:border-box;resize:vertical;font-size:10px;margin-bottom:3px;"></textarea>
                        <div style="display:flex;align-items:center;gap:3px;margin-bottom:4px;">
                            <span style="font-size:9px;">${t('expiresIn')}</span>
                            <input type="number" id="wme-mc-days" min="1" max="365" value="30" style="width:40px;padding:2px;border:1px solid #ccc;border-radius:3px;font-size:9px;">
                            <span style="font-size:9px;">${t('days')}</span>
                        </div>
                        <button id="wme-create-mapcomment-btn" style="width:100%;padding:4px;background:#ff9800;color:white;border:none;border-radius:3px;cursor:pointer;font-size:10px;">💬 ${t('createFromCircle')}</button>
                    </div>
                </details>

                <div style="padding:4px;background:#e8eaf6;border-radius:3px;">
                    <div style="display:flex;align-items:center;gap:6px;margin-bottom:4px;flex-wrap:wrap;">
                        <label style="font-size:9px;"><input type="radio" name="export-type" id="export-type-rtcs" checked> ${t('exportTypeRtcs')}</label>
                        <label style="font-size:9px;"><input type="radio" name="export-type" id="export-type-circles"> ${t('exportTypeCircles')}</label>
                        <label style="font-size:9px;"><input type="radio" name="export-type" id="export-type-gpx"> ${t('exportTypeGpx')}</label>
                    </div>
                    <div style="display:flex;gap:3px;">
                        <button id="wme-export-rtcs-btn" style="flex:1;padding:3px;background:#3f51b5;color:white;border:none;border-radius:3px;cursor:pointer;font-size:10px;">Export</button>
                        <button id="wme-import-rtcs-btn" style="flex:1;padding:3px;background:#3f51b5;color:white;border:none;border-radius:3px;cursor:pointer;font-size:10px;">Import</button>
                    </div>
                    <input type="file" id="wme-import-rtcs-file" accept=".json,.gpx" style="display:none;">
                </div>

                <style>
                    .ts{position:relative;display:inline-block;width:32px;height:16px;}
                    .ts input{opacity:0;width:0;height:0;}
                    .sl{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background:#ccc;transition:.2s;border-radius:16px;}
                    .sl:before{position:absolute;content:"";height:12px;width:12px;left:2px;bottom:2px;background:white;transition:.2s;border-radius:50%;}
                    input:checked+.sl{background:#4CAF50;}
                    input:checked+.sl:before{transform:translateX(16px);}
                    details summary{list-style:none;}
                    details summary::-webkit-details-marker{display:none;}
                    details summary::before{content:'▶';font-size:8px;margin-right:4px;display:inline-block;transition:transform .2s;}
                    details[open] summary::before{transform:rotate(90deg);}
                </style>
            </div>
        `;

        const checkbox = tabPane.querySelector('#wme-circles-edit-mode');
        const freehandCheckbox = tabPane.querySelector('#wme-freehand-edit-mode');
        const moveCheckbox = tabPane.querySelector('#wme-circles-move-mode');
        const clearButton = tabPane.querySelector('#wme-circles-clear');
        const selectButton = tabPane.querySelector('#wme-circles-select');
        const undoButton = tabPane.querySelector('#wme-circles-undo');
        const showRadiusCheckbox = tabPane.querySelector('#show-radius');
        const showDiameterCheckbox = tabPane.querySelector('#show-diameter');
        const showAreaCheckbox = tabPane.querySelector('#show-area');
        const useImperialCheckbox = tabPane.querySelector('#use-imperial');
        const filterDrivableCheckbox = tabPane.querySelector('#filter-drivable-only');
        const blockInboundCheckbox = tabPane.querySelector('#block-inbound-only');
        const presetRadiusInput = tabPane.querySelector('#wme-preset-radius');
        const presetCircleBtn = tabPane.querySelector('#wme-preset-circle-btn');
        const presetCancelBtn = tabPane.querySelector('#wme-preset-cancel-btn');
        const mapCommentBtn = tabPane.querySelector('#wme-create-mapcomment-btn');
        const mcTitleInput = tabPane.querySelector('#wme-mc-title');
        const mcDescInput = tabPane.querySelector('#wme-mc-desc');
        const mcDaysInput = tabPane.querySelector('#wme-mc-days');

        // Details elements für Klappmenüs
        const detailsDisplay = tabPane.querySelector('details:nth-of-type(1)');
        const detailsPerimeter = tabPane.querySelector('details:nth-of-type(2)');
        const detailsMapComment = tabPane.querySelector('details:nth-of-type(3)');

        // Einstellungen laden und anwenden
        const settings = loadSettings();
        if (settings.showRadius) showRadiusCheckbox.checked = true;
        if (settings.showDiameter) showDiameterCheckbox.checked = true;
        if (settings.showArea) showAreaCheckbox.checked = true;
        if (settings.useImperial) useImperialCheckbox.checked = true;
        if (settings.filterDrivable) filterDrivableCheckbox.checked = true;
        if (settings.blockInbound) blockInboundCheckbox.checked = true;
        if (settings.presetRadius) presetRadiusInput.value = settings.presetRadius;
        if (settings.detailsDisplayOpen) detailsDisplay?.setAttribute('open', '');
        if (settings.detailsPerimeterOpen) detailsPerimeter?.setAttribute('open', '');
        if (settings.detailsMapCommentOpen) detailsMapComment?.setAttribute('open', '');
        if (settings.rtcDays) tabPane.querySelector('#rtc-duration-days').value = settings.rtcDays;
        if (settings.rtcHours) tabPane.querySelector('#rtc-duration-hours').value = settings.rtcHours;
        if (settings.rtcMinutes) tabPane.querySelector('#rtc-duration-minutes').value = settings.rtcMinutes;

        // Einstellungen bei Änderung speichern
        const saveAllSettings = () => {
            saveSettings({
                showRadius: showRadiusCheckbox.checked,
                showDiameter: showDiameterCheckbox.checked,
                showArea: showAreaCheckbox.checked,
                useImperial: useImperialCheckbox.checked,
                filterDrivable: filterDrivableCheckbox.checked,
                blockInbound: blockInboundCheckbox.checked,
                presetRadius: presetRadiusInput.value,
                detailsDisplayOpen: detailsDisplay?.hasAttribute('open'),
                detailsPerimeterOpen: detailsPerimeter?.hasAttribute('open'),
                detailsMapCommentOpen: detailsMapComment?.hasAttribute('open'),
                rtcDays: tabPane.querySelector('#rtc-duration-days')?.value,
                rtcHours: tabPane.querySelector('#rtc-duration-hours')?.value,
                rtcMinutes: tabPane.querySelector('#rtc-duration-minutes')?.value
            });
        };

        // Event Listener für Speicherung
        [showRadiusCheckbox, showDiameterCheckbox, showAreaCheckbox, useImperialCheckbox,
         filterDrivableCheckbox, blockInboundCheckbox].forEach(el => {
            el?.addEventListener('change', saveAllSettings);
        });
        presetRadiusInput?.addEventListener('change', saveAllSettings);
        detailsDisplay?.addEventListener('toggle', saveAllSettings);
        detailsPerimeter?.addEventListener('toggle', saveAllSettings);
        detailsMapComment?.addEventListener('toggle', saveAllSettings);
        tabPane.querySelector('#rtc-duration-days')?.addEventListener('change', saveAllSettings);
        tabPane.querySelector('#rtc-duration-hours')?.addEventListener('change', saveAllSettings);
        tabPane.querySelector('#rtc-duration-minutes')?.addEventListener('change', saveAllSettings);

        function formatLength(meters, useImperial = false) {
            if (useImperial) {
                let feet = meters * 3.28084;
                if (feet >= 5280) {
                    let miles = feet / 5280;
                    return `${Math.round(miles * 100) / 100} mi`;
                } else {
                    return `${Math.round(feet)} ft`;
                }
            } else {
                if (meters > 1000) {
                    return `${Math.round((meters / 1000) * 100) / 100} km`;
                } else {
                    return `${Math.round(meters)} m`;
                }
            }
        }

        function formatArea(squareMeters, useImperial = false) {
            if (useImperial) {
                let squareFeet = squareMeters * 10.7639;
                if (squareFeet >= 27878400) {
                    let squareMiles = squareFeet / 27878400;
                    return `${Math.round(squareMiles * 100) / 100} mi²`;
                } else if (squareFeet >= 43560) {
                    let acres = squareFeet / 43560;
                    return `${Math.round(acres * 100) / 100} ac`;
                } else {
                    return `${Math.round(squareFeet)} ft²`;
                }
            } else {
                if (squareMeters > 1000000) {
                    return `${Math.round((squareMeters / 1000000) * 100) / 100} km²`;
                } else {
                    return `${Math.round(squareMeters)} m²`;
                }
            }
        }

        let updateTimeout;
        function updateAllAnnotations() {
            clearTimeout(updateTimeout);
            updateTimeout = setTimeout(() => {
                if (!infoLayer || !radiusLayer) return;

                try {
                    infoLayer.destroyFeatures();

                    if (!radiusLayer.features || radiusLayer.features.length === 0) {
                        return;
                    }

                    radiusLayer.features.forEach(feature => {
                        if (!feature || !feature.geometry) return;

                        if (feature.geometry.CLASS_NAME === "OpenLayers.Geometry.Polygon") {
                            const components = feature.geometry.components?.[0]?.components;
                            if (components && components.length > 90) {
                                addCircleAnnotations(feature);
                            } else if (components) {
                                addFreehandAnnotations(feature);
                            }
                        }
                    });
                } catch (error) {
                    warn('Error updating annotations:', error);
                }
            }, 100);
        }

        function addCircleAnnotations(f) {
            try {
                let minX = f.geometry.bounds.left;
                let minY = f.geometry.bounds.bottom;
                let maxX = f.geometry.bounds.right;
                let maxY = f.geometry.bounds.top;

                let startX = (minX + maxX) / 2;
                let startY = (minY + maxY) / 2;

                let startPoint = new uOpenLayers.Geometry.Point(startX, startY);
                let endPoint = new uOpenLayers.Geometry.Point(maxX, startY);
                let radius = new uOpenLayers.Geometry.LineString([startPoint, endPoint]);
                let len = radius.getGeodesicLength(new uOpenLayers.Projection("EPSG:900913"));

                let area = Math.PI * len * len;

                let showRadius = showRadiusCheckbox?.checked;
                let showDiameter = showDiameterCheckbox?.checked;
                let showArea = showAreaCheckbox?.checked;
                let useImperial = useImperialCheckbox?.checked;

                let centerStyle = {
                    strokeColor: "#c40606",
                    strokeWidth: 2,
                    pointRadius: 5,
                    fillOpacity: 0.2
                };

                let labelText = [];

                if (showRadius) {
                    labelText.push('R: ' + formatLength(len, useImperial));
                }

                if (showDiameter) {
                    labelText.push('Ø: ' + formatLength(len * 2, useImperial));
                }

                if (showArea) {
                    labelText.push('A: ' + formatArea(area, useImperial));
                }

                let lineStyle = {
                    strokeColor: "#c40606",
                    strokeWidth: 3,
                    label: labelText.join(' | '),
                    labelAlign: "left",
                    labelXOffset: "20",
                    labelYOffset: "10",
                    labelOutlineColor: "white",
                    labelOutlineWidth: 3
                };

                let center = new uOpenLayers.Feature.Vector(startPoint, {}, centerStyle);
                if (labelText.length > 0) {
                    let radiusLine = new uOpenLayers.Feature.Vector(radius, { 'length': len }, lineStyle);
                    infoLayer.addFeatures([center, radiusLine]);
                } else {
                    infoLayer.addFeatures([center]);
                }
            } catch (error) {
                warn('Error adding circle annotations:', error);
            }
        }

        function addFreehandAnnotations(f) {
            try {
                let bounds = f.geometry.getBounds();
                let minX = bounds.left;
                let minY = bounds.bottom;
                let maxX = bounds.right;
                let maxY = bounds.top;

                let centerX = (minX + maxX) / 2;
                let centerY = (minY + maxY) / 2;
                let width = maxX - minX;
                let height = maxY - minY;
                let diameter = Math.max(width, height);

                let centerPoint = new uOpenLayers.Geometry.Point(centerX, centerY);
                let endPoint = new uOpenLayers.Geometry.Point(centerX + diameter/2, centerY);
                let diameterLine = new uOpenLayers.Geometry.LineString([centerPoint, endPoint]);
                let len = diameterLine.getGeodesicLength(new uOpenLayers.Projection("EPSG:900913"));

                let area = f.geometry.getArea();

                let showRadius = showRadiusCheckbox?.checked;
                let showDiameter = showDiameterCheckbox?.checked;
                let showArea = showAreaCheckbox?.checked;
                let useImperial = useImperialCheckbox?.checked;

                let centerStyle = {
                    strokeColor: "#c40606",
                    strokeWidth: 2,
                    pointRadius: 5,
                    fillOpacity: 0.2
                };

                let labelText = [];

                if (showRadius) {
                    labelText.push('R: ' + formatLength(len / 2, useImperial));
                }

                if (showDiameter) {
                    labelText.push('Ø: ' + formatLength(len, useImperial));
                }

                if (showArea) {
                    labelText.push('A: ' + formatArea(area, useImperial));
                }

                let lineStyle = {
                    strokeColor: "#c40606",
                    strokeWidth: 3,
                    label: labelText.join(' | '),
                    labelAlign: "left",
                    labelXOffset: "20",
                    labelYOffset: "10",
                    labelOutlineColor: "white",
                    labelOutlineWidth: 3
                };

                let center = new uOpenLayers.Feature.Vector(centerPoint, {}, centerStyle);
                if (labelText.length > 0) {
                    let diameterLineFeature = new uOpenLayers.Feature.Vector(diameterLine, { 'diameter': len }, lineStyle);
                    infoLayer.addFeatures([center, diameterLineFeature]);
                } else {
                    infoLayer.addFeatures([center]);
                }
            } catch (error) {
                warn('Error adding freehand annotations:', error);
            }
        }

        // Register global event listener for annotation updates (used by drag control)
        document.addEventListener('updateAnnotations', updateAllAnnotations);

        addEventListenerWithCleanup(showRadiusCheckbox, 'change', updateAllAnnotations);
        addEventListenerWithCleanup(showDiameterCheckbox, 'change', updateAllAnnotations);
        addEventListenerWithCleanup(showAreaCheckbox, 'change', updateAllAnnotations);
        addEventListenerWithCleanup(useImperialCheckbox, 'change', updateAllAnnotations);

        // Toggle RTC duration settings visibility
        const rtcDurationSettings = tabPane.querySelector('#rtc-duration-settings');
        const rtcDurationInputs = tabPane.querySelector('#rtc-duration-inputs');
        const rtcEnddateInputs = tabPane.querySelector('#rtc-enddate-inputs');
        const rtcModeDuration = tabPane.querySelector('#rtc-mode-duration');
        const rtcModeEnddate = tabPane.querySelector('#rtc-mode-enddate');
        const rtcEndDateInput = tabPane.querySelector('#rtc-end-date');

        // Initial state based on saved settings
        if (blockInboundCheckbox.checked && rtcDurationSettings) {
            rtcDurationSettings.style.display = 'block';
        }

        addEventListenerWithCleanup(blockInboundCheckbox, 'change', () => {
            if (rtcDurationSettings) {
                rtcDurationSettings.style.display = blockInboundCheckbox.checked ? 'block' : 'none';
                // Set default end date to tomorrow and min to today
                if (blockInboundCheckbox.checked && rtcEndDateInput) {
                    const today = new Date();
                    const tomorrow = new Date();
                    tomorrow.setDate(tomorrow.getDate() + 1);
                    rtcEndDateInput.min = today.toISOString().split('T')[0];
                    rtcEndDateInput.value = tomorrow.toISOString().split('T')[0];
                }
            }
        });

        // Toggle between duration and end date mode
        const updateRtcMode = () => {
            if (rtcModeDuration?.checked) {
                rtcDurationInputs.style.display = 'flex';
                rtcEnddateInputs.style.display = 'none';
            } else {
                rtcDurationInputs.style.display = 'none';
                rtcEnddateInputs.style.display = 'block';
            }
        };
        addEventListenerWithCleanup(rtcModeDuration, 'change', updateRtcMode);
        addEventListenerWithCleanup(rtcModeEnddate, 'change', updateRtcMode);

        addEventListenerWithCleanup(checkbox, 'click', (e) => {
            if (e.target.checked) {
                freehandCheckbox.checked = false;
                moveCheckbox.checked = false;
                freehandControl.deactivate();
                dragControl.deactivate();
                polygonControl.activate();
            } else {
                polygonControl.deactivate();
            }
        });

        addEventListenerWithCleanup(freehandCheckbox, 'click', (e) => {
            if (e.target.checked) {
                checkbox.checked = false;
                moveCheckbox.checked = false;
                polygonControl.deactivate();
                dragControl.deactivate();
                freehandControl.activate();
            } else {
                freehandControl.deactivate();
            }
        });

        // DragFeature Control - recreated on demand
        function createDragControl() {
            log('Creating new DragFeature control, layer has ' + (radiusLayer.features?.length || 0) + ' features');
            const ctrl = new uOpenLayers.Control.DragFeature(radiusLayer, {
                onStart: function(feature, pixel) {
                    log('Drag started');
                },
                onDrag: function(feature, pixel) {
                    if (!this._lastUpdate || Date.now() - this._lastUpdate > 100) {
                        this._lastUpdate = Date.now();
                        document.dispatchEvent(new CustomEvent('updateAnnotations'));
                    }
                },
                onComplete: function(feature, pixel) {
                    log('Drag completed');
                    document.dispatchEvent(new CustomEvent('updateAnnotations'));
                }
            });
            return ctrl;
        }

        dragControl = createDragControl();
        uWaze.map.addControl(dragControl);

        function activateDragMode() {
            log('activateDragMode called');

            // Remove old control completely
            if (dragControl) {
                try {
                    dragControl.deactivate();
                    uWaze.map.removeControl(dragControl);
                } catch(e) {}
            }

            // Create fresh control and add it
            dragControl = createDragControl();
            uWaze.map.addControl(dragControl);

            // Activate it
            dragControl.activate();

            log('Drag mode activated, control.active=' + dragControl.active);
        }

        addEventListenerWithCleanup(moveCheckbox, 'click', (e) => {
            if (e.target.checked) {
                checkbox.checked = false;
                freehandCheckbox.checked = false;
                polygonControl.deactivate();
                freehandControl.deactivate();
                activateDragMode();
                updateStatusMessage(t('moveHint'), '#2196F3');
            } else {
                if (dragControl) {
                    dragControl.deactivate();
                    log('Drag mode deactivated');
                }
                updateStatusMessage('', '#4CAF50');
            }
        });

        // Track pending reactivation
        let reactivateTimer = null;

        function scheduleReactivation() {
            if (!moveCheckbox || !moveCheckbox.checked) return;

            // Clear any pending timer
            if (reactivateTimer) clearTimeout(reactivateTimer);

            // Wait for WME and other scripts to finish, then reactivate
            reactivateTimer = setTimeout(() => {
                if (moveCheckbox && moveCheckbox.checked) {
                    activateDragMode();
                }
            }, 2000); // Wait 2 seconds for everything to settle
        }

        // On zoom: schedule reactivation after everything finishes
        uWaze.map.events.register('zoomend', null, function() {
            log('zoomend event fired');

            if (radiusLayer && radiusLayer.redraw) radiusLayer.redraw();
            if (infoLayer && infoLayer.redraw) infoLayer.redraw();

            scheduleReactivation();

            document.dispatchEvent(new CustomEvent('updateAnnotations'));
        });

        // Also reactivate after map move completes
        uWaze.map.events.register('moveend', null, function() {
            if (moveCheckbox && moveCheckbox.checked) {
                scheduleReactivation();
            }
        });

        addEventListenerWithCleanup(clearButton, 'click', (e) => {
            clearAllCircles();
            updateStatusMessage(t('circlesCleared'), '#4CAF50');
        });

        addEventListenerWithCleanup(undoButton, 'click', (e) => {
            undoLastCircle();
        });

        addEventListenerWithCleanup(selectButton, 'click', (e) => {
            selectSegmentsInCircles();
        });

        // Delete RTCs Button
        const deleteRtcsBtn = tabPane.querySelector('#wme-circles-delete-rtcs');
        addEventListenerWithCleanup(deleteRtcsBtn, 'click', (e) => {
            deleteRtcsInCircles();
        });

        // Brush Mode - basiert auf Freihand-Zeichnung mit breiter Linie
        const brushCheckbox = tabPane.querySelector('#wme-brush-mode');
        const brushHint = tabPane.querySelector('#brush-mode-hint');
        let brushModeActive = false;
        let brushControl = null;
        let brushLayer = null;
        let brushSelectedSegments = new Set(); // Speichert alle ausgewählten Segment-IDs
        let brushHistory = []; // History für Undo - speichert Snapshots der Auswahl

        // Erstelle separaten Layer für Brush mit breiter Linie
        brushLayer = new uOpenLayers.Layer.Vector("WME Brush Layer", {
            displayInLayerSwitcher: false,
            visibility: true,
            style: {
                strokeColor: "#2196F3",
                strokeOpacity: 0.6,
                strokeWidth: 20, // 20 Pixel breit
                strokeLinecap: "round"
            }
        });
        uWaze.map.addLayer(brushLayer);

        // Brush Control - wie Freihand aber für Selektion
        brushControl = new uOpenLayers.Control.DrawFeature(brushLayer, uOpenLayers.Handler.Path, {
            handlerOptions: {
                freehand: true,
                freehandToggle: null
            }
        });
        uWaze.map.addControl(brushControl);

        // Wenn Brush-Zeichnung fertig ist, finde geschnittene Segmente
        brushControl.events.on({
            'featureadded': function(e) {
                if (!brushModeActive) return;

                const brushGeom = e.feature.geometry;
                if (!brushGeom) return;

                // Prüfe ob Löschen-Modus aktiv
                const brushEraseCheckbox = tabPane.querySelector('#wme-brush-erase');
                const eraseMode = brushEraseCheckbox?.checked || false;

                log(`Brush Event: eraseMode=${eraseMode}, brushSelectedSegments.size=${brushSelectedSegments.size}`);

                // Speichere aktuellen Zustand für Undo BEVOR Änderungen
                brushHistory.push(new Set(brushSelectedSegments));
                if (brushHistory.length > 50) brushHistory.shift(); // Max 50 Schritte

                // Erstelle Buffer um die Linie
                const resolution = uWaze.map.getResolution();
                const bufferSize = eraseMode ? 10 * resolution : 20 * resolution;

                // Finde alle Segmente die die Brush-Linie schneiden
                const segments = uWaze.model.segments.getObjectArray();
                let changeCount = 0;
                let checkedCount = 0;

                for (const segment of segments) {
                    if (!segment.attributes?.roadType) continue;

                    // Filter: nur befahrbare
                    if (filterDrivableCheckbox?.checked) {
                        if (!isDrivableSegment(segment)) continue;
                    }

                    const segGeom = segment.getOLGeometry?.() || segment.geometry;
                    if (!segGeom) continue;

                    checkedCount++;

                    // Prüfe ob Segment die Brush-Linie schneidet oder nah dran ist
                    const distance = brushGeom.distanceTo(segGeom);

                    let threshold;
                    if (eraseMode) {
                        threshold = Math.min(5 * resolution, 3);
                    } else {
                        threshold = bufferSize;
                    }

                    if (distance < threshold) {
                        const segId = segment.getID();

                        if (eraseMode) {
                            // LÖSCHEN-MODUS: Entferne NUR dieses eine Segment
                            if (brushSelectedSegments.has(segId)) {
                                brushSelectedSegments.delete(segId);
                                if (window._gpxSegmentIds) {
                                    window._gpxSegmentIds.delete(segId);
                                }
                                changeCount++;
                                log(`Brush Erase: Segment ${segId} entfernt`);
                            }
                        } else {
                            // NORMAL-MODUS: Füge Segment zur Auswahl hinzu
                            if (!brushSelectedSegments.has(segId)) {
                                brushSelectedSegments.add(segId);
                                changeCount++;
                            }
                        }
                    }
                }

                log(`Brush: ${checkedCount} Segmente geprüft, ${changeCount} geändert, ${brushSelectedSegments.size} IDs gesamt`);

                // Lösche die Brush-Linie
                brushLayer.removeAllFeatures();

                // Aktualisiere WME Selektion
                const allSegments = Array.from(brushSelectedSegments)
                    .map(id => uWaze.model.segments.getObjectById(id))
                    .filter(Boolean);

                log(`Brush: ${allSegments.length} Segmente geladen von ${brushSelectedSegments.size} IDs`);

                if (allSegments.length > 0) {
                    uWaze.selectionManager.setSelectedModels(allSegments);
                    if (eraseMode) {
                        const notLoaded = brushSelectedSegments.size - allSegments.length;
                        const notLoadedText = notLoaded > 0 ? ` (+${notLoaded} nicht geladen)` : '';
                        updateStatusMessage(`🧹 ${allSegments.length} Segmente (-${changeCount} entfernt)${notLoadedText}`, '#ff9800');
                    } else {
                        updateStatusMessage(`🖌️ ${allSegments.length} Segmente (+${changeCount} neu)`, '#2196F3');
                    }
                } else if (brushSelectedSegments.size > 0) {
                    // IDs vorhanden aber nicht geladen - NICHT deselektieren!
                    if (eraseMode) {
                        updateStatusMessage(`🧹 ${changeCount} entfernt (${brushSelectedSegments.size} IDs gespeichert)`, '#ff9800');
                    } else {
                        updateStatusMessage(`🖌️ ${brushSelectedSegments.size} Segmente (nicht im Viewport)`, '#2196F3');
                    }
                } else {
                    uWaze.selectionManager.unselectAll();
                    window._gpxSegmentIds = null;
                    updateStatusMessage(`🧹 Alle Segmente entfernt`, '#ff9800');
                }
            }
        });

        // Brush Undo Funktion
        function undoBrushSelection() {
            if (brushHistory.length === 0) {
                return false; // Keine History
            }

            // Letzten Zustand wiederherstellen
            brushSelectedSegments = brushHistory.pop();

            // WME Selektion aktualisieren
            const allSegments = Array.from(brushSelectedSegments)
                .map(id => uWaze.model.segments.getObjectById(id))
                .filter(Boolean);

            if (allSegments.length > 0) {
                uWaze.selectionManager.setSelectedModels(allSegments);
            } else {
                uWaze.selectionManager.unselectAll();
            }

            updateStatusMessage(`↩️ ${allSegments.length} Segmente`, '#2196F3');
            return true;
        }
        addEventListenerWithCleanup(brushCheckbox, 'change', (e) => {
            brushModeActive = e.target.checked;
            brushHint.style.display = brushModeActive ? 'block' : 'none';

            // Zeige/verstecke Löschen-Checkbox
            const brushEraseLabel = tabPane.querySelector('#brush-erase-label');
            if (brushEraseLabel) {
                brushEraseLabel.style.display = brushModeActive ? 'flex' : 'none';
            }

            if (brushModeActive) {
                // Deaktiviere andere Modi
                checkbox.checked = false;
                freehandCheckbox.checked = false;
                moveCheckbox.checked = false;
                polygonControl.deactivate();
                freehandControl.deactivate();
                if (dragControl) dragControl.deactivate();

                // WICHTIG: Übernehme Segment-IDs
                brushSelectedSegments.clear();

                // 1. Zuerst: Global gespeicherte GPX-IDs übernehmen (falls vorhanden)
                if (window._gpxSegmentIds && window._gpxSegmentIds.size > 0) {
                    for (const id of window._gpxSegmentIds) {
                        brushSelectedSegments.add(id);
                    }
                    log(`Brush: ${brushSelectedSegments.size} GPX-Segment-IDs übernommen`);
                }

                // 2. Dann: Aktuelle WME-Selektion hinzufügen (falls zusätzliche Segmente)
                try {
                    const currentSelection = uWaze.selectionManager.getSelectedFeatures() || [];
                    let addedFromSelection = 0;
                    for (const feature of currentSelection) {
                        if (feature?.model?.type === 'segment') {
                            const segId = feature.model.attributes?.id || feature.model.getID?.();
                            if (segId && !brushSelectedSegments.has(segId)) {
                                brushSelectedSegments.add(segId);
                                addedFromSelection++;
                            }
                        }
                    }
                    if (addedFromSelection > 0) {
                        log(`Brush: +${addedFromSelection} Segmente aus aktueller Auswahl`);
                    }
                } catch (e) {
                    // Fallback: Keine Übernahme
                }

                // Aktiviere Brush
                brushControl.activate();
                updateStatusMessage(t('brushModeActive') + (brushSelectedSegments.size > 0 ? ` (${brushSelectedSegments.size})` : ''), '#2196F3');
                log('Brush-Modus aktiviert');
            } else {
                brushControl.deactivate();
                brushLayer.removeAllFeatures();
                // Löschen-Checkbox zurücksetzen
                const brushEraseCheckbox = tabPane.querySelector('#wme-brush-erase');
                if (brushEraseCheckbox) brushEraseCheckbox.checked = false;
                // Auswahl bleibt erhalten beim Deaktivieren
                updateStatusMessage('', '#4CAF50');
                log('Brush-Modus deaktiviert');
            }
        });

        // Import/Export Buttons
        const exportBtn = tabPane.querySelector('#wme-export-rtcs-btn');
        const importBtn = tabPane.querySelector('#wme-import-rtcs-btn');
        const importFile = tabPane.querySelector('#wme-import-rtcs-file');
        const exportTypeRtcs = tabPane.querySelector('#export-type-rtcs');
        const exportTypeCircles = tabPane.querySelector('#export-type-circles');
        const exportTypeGpx = tabPane.querySelector('#export-type-gpx');

        addEventListenerWithCleanup(exportBtn, 'click', (e) => {
            if (exportTypeGpx?.checked) {
                exportSelectedAsGpx();
            } else if (exportTypeCircles?.checked) {
                exportCirclesInArea();
            } else {
                exportRtcsInArea();
            }
        });

        addEventListenerWithCleanup(importBtn, 'click', (e) => {
            importFile.click();
        });

        addEventListenerWithCleanup(importFile, 'change', (e) => {
            if (e.target.files.length > 0) {
                const file = e.target.files[0];
                const fileName = file.name.toLowerCase();

                // GPX-Datei erkennen (unabhängig von Radio-Button)
                if (fileName.endsWith('.gpx')) {
                    importGpxFile(file);
                } else if (exportTypeCircles?.checked) {
                    importCirclesFromFile(file);
                } else {
                    importRtcsFromFile(file);
                }
                e.target.value = ''; // Reset für erneuten Import
            }
        });

        // Preset Circle Event Handlers
        addEventListenerWithCleanup(presetCircleBtn, 'click', (e) => {
            startPresetCircleMode();
        });

        addEventListenerWithCleanup(presetCancelBtn, 'click', (e) => {
            cancelPresetCircleMode();
        });

        // Map Comment Event Handler
        addEventListenerWithCleanup(mapCommentBtn, 'click', (e) => {
            createMapCommentFromCircle();
        });

        function createMapCommentFromCircle() {
            try {
                if (!radiusLayer || !radiusLayer.features || radiusLayer.features.length === 0) {
                    updateStatusMessage(t('selectCircleFirst'), '#ff9800');
                    return;
                }

                const lastFeature = radiusLayer.features[radiusLayer.features.length - 1];
                if (!lastFeature || !lastFeature.geometry) {
                    updateStatusMessage(t('noCircleToConvert'), '#ff9800');
                    return;
                }

                // Get SDK
                let sdk = null;
                try {
                    if (typeof getWmeSdk === 'function') {
                        sdk = getWmeSdk({ scriptId: 'wme-circles', scriptName: 'WME Circles' });
                    }
                } catch (e) {
                    warn('SDK not available:', e);
                }

                if (!sdk || !sdk.DataModel || !sdk.DataModel.MapComments) {
                    updateStatusMessage('SDK not available', '#f44336');
                    warn('WME SDK not available for Map Comments');
                    return;
                }

                // Convert OpenLayers geometry to GeoJSON
                const geometry = lastFeature.geometry;
                const coords = [];

                // Mercator to WGS84 conversion
                function mercatorToWgs84(x, y) {
                    const lon = (x / 20037508.34) * 180;
                    let lat = (y / 20037508.34) * 180;
                    lat = (180 / Math.PI) * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
                    return [lon, lat];
                }

                // Get polygon points
                if (geometry.CLASS_NAME === "OpenLayers.Geometry.Polygon") {
                    const ring = geometry.components[0];
                    if (ring && ring.components) {
                        for (const point of ring.components) {
                            const [lon, lat] = mercatorToWgs84(point.x, point.y);
                            coords.push([lon, lat]);
                        }
                    }
                }

                if (coords.length < 4) {
                    updateStatusMessage('Invalid geometry', '#f44336');
                    return;
                }

                // Build GeoJSON
                const geoJson = {
                    type: 'Polygon',
                    coordinates: [coords]
                };

                // Get form values
                const title = mcTitleInput?.value || '';
                const desc = mcDescInput?.value || '';
                const days = parseInt(mcDaysInput?.value) || 30;

                // Calculate end date
                const endDate = Date.now() + (days * 24 * 60 * 60 * 1000);

                log('Creating Map Comment with geometry:', geoJson);

                // Create Map Comment via SDK
                const result = sdk.DataModel.MapComments.addComment({
                    geometry: geoJson,
                    subject: String(title).substring(0, 30),
                    body: String(desc).substring(0, 2000),
                    endDate: endDate
                });

                if (result) {
                    updateStatusMessage('✅ ' + t('mapCommentCreated') + ' (ID: ' + result.id + ')', '#4CAF50');
                    log('Map Comment created:', result);

                    // Clear form
                    if (mcTitleInput) mcTitleInput.value = '';
                    if (mcDescInput) mcDescInput.value = '';
                } else {
                    updateStatusMessage('✅ ' + t('mapCommentCreated'), '#4CAF50');
                }

            } catch (error) {
                warn('Error creating Map Comment:', error);
                updateStatusMessage('Error: ' + error.message, '#f44336');
            }
        }

        function startPresetCircleMode() {
            presetCircleMode = true;
            presetCircleCenter = null;

            // Deactivate other drawing modes
            checkbox.checked = false;
            freehandCheckbox.checked = false;
            polygonControl.deactivate();
            freehandControl.deactivate();

            // Update UI
            presetCircleBtn.style.background = '#ff9800';
            presetCircleBtn.textContent = '⏳ ' + t('clickForCenter');
            presetCancelBtn.style.display = 'block';

            updateStatusMessage(t('clickForCenter'), '#2196F3');

            // Add map click handler
            uWaze.map.events.register('click', null, onPresetMapClick);
        }

        function cancelPresetCircleMode() {
            presetCircleMode = false;
            presetCircleCenter = null;

            // Reset UI
            presetCircleBtn.style.background = '#2196F3';
            presetCircleBtn.textContent = '📍 ' + t('presetHint');
            presetCancelBtn.style.display = 'none';

            updateStatusMessage('', '#4CAF50');

            // Remove map click handler
            uWaze.map.events.unregister('click', null, onPresetMapClick);
        }

        function onPresetMapClick(e) {
            if (!presetCircleMode) return;

            // Get click position - this returns WGS84 coordinates directly
            const lonlat = uWaze.map.getLonLatFromPixel(e.xy);
            if (!lonlat) {
                warn('Could not get coordinates from click');
                return;
            }

            const radius = parseInt(presetRadiusInput?.value) || 100;

            log(`Preset click at: ${lonlat.lon}, ${lonlat.lat}, radius: ${radius}m`);

            // lonlat.lon and lonlat.lat are already in WGS84
            createPresetCircle(lonlat.lon, lonlat.lat, radius);

            // Reset mode
            cancelPresetCircleMode();

            updateStatusMessage(t('circleCreated', radius), '#4CAF50');
        }

        function createPresetCircle(centerLon, centerLat, radiusMeters) {
            try {
                // centerLon, centerLat are already in WGS84
                log(`Creating circle at WGS84: ${centerLon}, ${centerLat}`);

                // WGS84 to Mercator conversion
                function wgs84ToMercator(lon, lat) {
                    const x = lon * 20037508.34 / 180;
                    let y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
                    y = y * 20037508.34 / 180;
                    return [x, y];
                }

                // Create circle points using geodesic calculation
                const points = [];
                const steps = 100;

                for (let i = 0; i <= steps; i++) {
                    const bearing = (i / steps) * 360;
                    const destPoint = destinationPoint(
                        [centerLon, centerLat],
                        radiusMeters,
                        bearing
                    );

                    // Convert to Mercator for OpenLayers
                    const [mx, my] = wgs84ToMercator(destPoint[0], destPoint[1]);
                    points.push(new uOpenLayers.Geometry.Point(mx, my));
                }

                // Create polygon
                const ring = new uOpenLayers.Geometry.LinearRing(points);
                const polygon = new uOpenLayers.Geometry.Polygon([ring]);
                const feature = new uOpenLayers.Feature.Vector(polygon);

                // Add to layer
                radiusLayer.addFeatures([feature]);

                // Force redraw
                if (radiusLayer.redraw) radiusLayer.redraw();

                // Update annotations
                setTimeout(() => {
                    const event = new CustomEvent('updateAnnotations');
                    document.dispatchEvent(event);
                }, 100);

                log(`Created preset circle: ${radiusMeters}m`);

            } catch (error) {
                warn('Error creating preset circle:', error);
                console.error(error);
            }
        }

        // Geodesic destination point calculation
        function destinationPoint(start, distanceMeters, bearingDegrees) {
            const toRadians = (deg) => deg * Math.PI / 180;
            const toDegrees = (rad) => rad * 180 / Math.PI;

            const startLon = Number(start[0]);
            const startLat = Number(start[1]);
            const dist = Number(distanceMeters);
            const bearing = Number(bearingDegrees);

            const lon1 = toRadians(startLon);
            const lat1 = toRadians(startLat);
            const bearingRad = toRadians(bearing);
            const angularDist = dist / EARTH_RADIUS;

            const lat2 = Math.asin(
                Math.sin(lat1) * Math.cos(angularDist) +
                Math.cos(lat1) * Math.sin(angularDist) * Math.cos(bearingRad)
            );
            const lon2 = lon1 + Math.atan2(
                Math.sin(bearingRad) * Math.sin(angularDist) * Math.cos(lat1),
                Math.cos(angularDist) - Math.sin(lat1) * Math.sin(lat2)
            );
            return [toDegrees(lon2), toDegrees(lat2)];
        }

        function updateStatusMessage(message, color = '#4CAF50') {
            const statusElement = document.getElementById('circles-current-radius');
            if (statusElement) {
                statusElement.innerHTML = message;
                statusElement.style.color = color;
                setTimeout(() => {
                    statusElement.innerHTML = '';
                    statusElement.style.color = '';
                }, 4000);
            }
        }

        function selectSegmentsInCircles() {
            const toSelect = [];
            const segments = uWaze.model.segments.getObjectArray();
            const blockInboundOnly = blockInboundCheckbox?.checked;

            if (!segments || segments.length === 0) {
                warn('No segments found');
                return;
            }

            if (blockInboundOnly) {
                log('Finding perimeter segments for hollow circle blocking...');

                for (const drawnFeature of radiusLayer.features) {
                    const circleGeometry = drawnFeature.geometry;
                    const bounds = circleGeometry.getBounds();
                    const circleCenter = {
                        x: (bounds.left + bounds.right) / 2,
                        y: (bounds.bottom + bounds.top) / 2
                    };

                    const radius = Math.abs(bounds.right - bounds.left) / 2;
                    // Toleranz für Segmente die den Kreis knapp berühren (5% des Radius)
                    const tolerance = radius * 0.05;

                    for (const segment of segments) {
                        if (!segment.attributes?.roadType) continue;

                        if (filterDrivableCheckbox.checked) {
                            if (!isDrivableSegment(segment)) continue;
                        }

                        const segGeom = segment.getOLGeometry ? segment.getOLGeometry() : segment.geometry;
                        if (!segGeom) continue;

                        const coords = segGeom.components || segGeom.getVertices?.();
                        if (!coords || coords.length < 2) continue;

                        // Prüfe Start- und Endpunkt
                        const startPoint = coords[0];
                        const endPoint = coords[coords.length - 1];

                        if (!startPoint?.x || !endPoint?.x) continue;

                        const startDist = Math.hypot(startPoint.x - circleCenter.x, startPoint.y - circleCenter.y);
                        const endDist = Math.hypot(endPoint.x - circleCenter.x, endPoint.y - circleCenter.y);

                        // Prüfe ob Punkte innen oder außen sind (mit Toleranz)
                        const startInside = startDist < (radius + tolerance);
                        const endInside = endDist < (radius + tolerance);
                        const startStrictInside = startDist < (radius - tolerance);
                        const endStrictInside = endDist < (radius - tolerance);

                        // Ein Segment ist ein Perimeter-Segment wenn:
                        // 1. Ein Punkt klar innen und einer klar außen
                        // 2. Mindestens ein Punkt berührt den Perimeter (innerhalb Toleranz)
                        // 3. Das Segment schneidet den Kreis geometrisch

                        let isPerimeterSegment = false;

                        // Fall 1: Ein Punkt innen, einer außen
                        if (startStrictInside !== endStrictInside) {
                            isPerimeterSegment = true;
                        }
                        // Fall 2: Mindestens ein Punkt liegt nah am Perimeter
                        else if (Math.abs(startDist - radius) <= tolerance || Math.abs(endDist - radius) <= tolerance) {
                            isPerimeterSegment = true;
                        }
                        // Fall 3: Segment kreuzt den Kreis (beide außen aber intersects)
                        else if (!startInside && !endInside && circleGeometry.intersects(segGeom)) {
                            isPerimeterSegment = true;
                        }
                        // Fall 4: Prüfe ob irgendein Zwischenpunkt den Kreis kreuzt
                        else if (coords.length > 2) {
                            for (let i = 1; i < coords.length - 1; i++) {
                                const midPoint = coords[i];
                                if (midPoint?.x) {
                                    const midDist = Math.hypot(midPoint.x - circleCenter.x, midPoint.y - circleCenter.y);
                                    if (Math.abs(midDist - radius) <= tolerance) {
                                        isPerimeterSegment = true;
                                        break;
                                    }
                                }
                            }
                        }

                        if (isPerimeterSegment) {
                            if (shouldBlockSegmentInbound(segment, segGeom, circleCenter, radius)) {
                                // Duplikate vermeiden
                                if (!toSelect.find(s => s.getID() === segment.getID())) {
                                    toSelect.push(segment);
                                    log(`✓ Perimeter-Segment gefunden: ${segment.getID()} (${segment.attributes.primaryStreetID ? 'Straße' : 'unbenannt'})`);
                                }
                            }
                        }
                    }
                }

                log(`=== Gefundene Perimeter-Segmente: ${toSelect.length} ===`);
                toSelect.forEach(s => log(`  - Segment ${s.getID()}`));
            } else {
                for (const segment of segments) {
                    if (!segment.attributes?.roadType) continue;

                    if (filterDrivableCheckbox.checked) {
                        if (!isDrivableSegment(segment)) continue;
                    }

                    const segGeom = segment.getOLGeometry ? segment.getOLGeometry() : segment.geometry;
                    if (!segGeom) continue;

                    let isInCircle = false;

                    for (const drawnFeature of radiusLayer.features) {
                        if (drawnFeature.geometry.intersects(segGeom)) {
                            isInCircle = true;
                            break;
                        }
                    }

                    if (isInCircle) {
                        toSelect.push(segment);
                    }
                }
            }

            log(`Selected ${toSelect.length} segments${blockInboundOnly ? ' (perimeter only)' : ''}`);

            if (toSelect.length > 0) {
                if (blockInboundOnly) {
                    applyDirectionRestrictions(toSelect);
                } else {
                    uWaze.selectionManager.setSelectedModels(toSelect);
                    updateStatusMessage(t('selectedSegments', toSelect.length), '#4CAF50');
                }
            } else {
                updateStatusMessage(t('noSegmentsFound'), '#ff9800');
            }

            checkbox.checked = false;
            freehandCheckbox.checked = false;
            polygonControl.deactivate();
            freehandControl.deactivate();
        }

        function exportRtcsInArea() {
            log('=== Export Button geklickt ===');

            if (!radiusLayer || !radiusLayer.features || radiusLayer.features.length === 0) {
                updateStatusMessage('Erst einen Kreis zeichnen', '#ff9800');
                log('Export abgebrochen: Kein Kreis vorhanden');
                return;
            }

            log(`radiusLayer hat ${radiusLayer.features.length} Features`);

            const segments = uWaze.model.segments.getObjectArray();
            log(`${segments.length} Segmente im Model`);

            const segmentsInCircle = [];

            // Finde alle Segmente im Kreis
            for (const segment of segments) {
                if (!segment.attributes?.roadType) continue;

                const segGeom = segment.getOLGeometry ? segment.getOLGeometry() : segment.geometry;
                if (!segGeom) continue;

                for (const drawnFeature of radiusLayer.features) {
                    if (drawnFeature.geometry.intersects(segGeom)) {
                        segmentsInCircle.push(segment);
                        break;
                    }
                }
            }

            log(`${segmentsInCircle.length} Segmente im Kreis gefunden`);

            if (segmentsInCircle.length === 0) {
                updateStatusMessage('Keine Segmente im Kreis gefunden', '#ff9800');
                return;
            }

            // Finde alle RTCs auf diesen Segmenten
            const rtcsToExport = [];
            const segmentIds = new Set(segmentsInCircle.map(s => s.getID()));

            log(`Prüfe roadClosures...`);
            log(`W.model.roadClosures existiert: ${!!W.model.roadClosures}`);

            if (W.model.roadClosures) {
                const allClosures = W.model.roadClosures.getObjectArray();
                log(`${allClosures.length} Closures im Model insgesamt`);

                for (const closure of allClosures) {
                    const attrs = closure.attributes;
                    if (!attrs) continue;

                    log(`Closure prüfen: segID=${attrs.segID}, in Set: ${segmentIds.has(attrs.segID)}`);

                    if (segmentIds.has(attrs.segID)) {
                        rtcsToExport.push({
                            segmentId: attrs.segID,
                            reason: attrs.reason || '',
                            direction: attrs.direction,
                            startDate: attrs.startDate,
                            endDate: attrs.endDate,
                            permanent: attrs.permanent || false
                        });
                        log(`  → RTC hinzugefügt für Segment ${attrs.segID}`);
                    }
                }
            } else {
                warn('W.model.roadClosures nicht verfügbar!');

                // Alternative: Prüfe ob Closures auf den Segmenten selbst gespeichert sind
                log('Versuche Closures direkt von Segmenten zu lesen...');
                for (const segment of segmentsInCircle) {
                    const closures = segment.attributes?.roadClosures || segment.attributes?.closures;
                    if (closures && closures.length > 0) {
                        log(`Segment ${segment.getID()} hat ${closures.length} Closures`);
                        for (const c of closures) {
                            rtcsToExport.push({
                                segmentId: segment.getID(),
                                reason: c.reason || '',
                                direction: c.direction,
                                startDate: c.startDate,
                                endDate: c.endDate,
                                permanent: c.permanent || false
                            });
                        }
                    }
                }
            }

            log(`${rtcsToExport.length} RTCs zum Export gefunden`);

            if (rtcsToExport.length === 0) {
                updateStatusMessage(t('noRtcsToExport') + ' (0 RTCs auf ' + segmentsInCircle.length + ' Segmenten)', '#ff9800');
                return;
            }

            // Export als JSON
            const exportData = {
                version: 1,
                exportDate: new Date().toISOString(),
                segmentCount: segmentsInCircle.length,
                rtcs: rtcsToExport
            };

            log('Erstelle Download...');

            try {
                const jsonStr = JSON.stringify(exportData, null, 2);
                log(`JSON erstellt: ${jsonStr.length} Zeichen`);

                const blob = new Blob([jsonStr], { type: 'application/json' });
                log(`Blob erstellt: ${blob.size} Bytes`);

                const url = URL.createObjectURL(blob);
                log(`URL erstellt: ${url}`);

                const a = document.createElement('a');
                a.href = url;
                a.download = `wme-rtcs-export-${new Date().toISOString().slice(0,10)}.json`;
                a.style.display = 'none';
                document.body.appendChild(a);

                log('Starte Download...');
                a.click();

                // Cleanup nach kurzer Verzögerung
                setTimeout(() => {
                    document.body.removeChild(a);
                    URL.revokeObjectURL(url);
                    log('Cleanup abgeschlossen');
                }, 100);

                updateStatusMessage(t('exportedRtcs', rtcsToExport.length), '#4CAF50');
                log(`✓ ${rtcsToExport.length} RTCs exportiert`);
            } catch (err) {
                warn('Export Fehler:', err);
                console.error('Export Fehler Details:', err);
                updateStatusMessage('Export Fehler: ' + err.message, '#f44336');
            }
        }

        function importRtcsFromFile(file) {
            const reader = new FileReader();

            reader.onload = function(e) {
                try {
                    const data = JSON.parse(e.target.result);

                    if (!data.rtcs || !Array.isArray(data.rtcs)) {
                        updateStatusMessage('Ungültiges Dateiformat', '#f44336');
                        return;
                    }

                    log(`Importiere ${data.rtcs.length} RTCs...`);
                    importRtcs(data.rtcs);

                } catch (err) {
                    warn('Import Fehler:', err);
                    updateStatusMessage('Fehler beim Lesen der Datei', '#f44336');
                }
            };

            reader.readAsText(file);
        }

        function importRtcs(rtcList) {
            if (rtcList.length === 0) {
                updateStatusMessage('Keine RTCs zum Importieren', '#ff9800');
                return;
            }

            const cab = require("Waze/Modules/Closures/Models/ClosureActionBuilder");
            const sc = require("Waze/Modules/Closures/Models/SharedClosure");

            let importedCount = 0;
            let errorCount = 0;
            let currentIndex = 0;

            const importNext = () => {
                if (currentIndex >= rtcList.length) {
                    updateStatusMessage(t('importedRtcs', importedCount) + (errorCount > 0 ? ` (${errorCount} Fehler)` : ''), '#4CAF50');
                    return;
                }

                const rtc = rtcList[currentIndex];
                currentIndex++;

                const segment = W.model.segments.getObjectById(rtc.segmentId);
                if (!segment) {
                    log(`Segment ${rtc.segmentId} nicht gefunden, überspringe...`);
                    errorCount++;
                    importNext();
                    return;
                }

                W.selectionManager.setSelectedModels([segment]);

                const closureDetails = {
                    closures: [],
                    attributions: [],
                    reason: (rtc.reason || 'Import') + String.fromCharCode(160),
                    direction: rtc.direction || 3,
                    startDate: rtc.startDate,
                    endDate: rtc.endDate,
                    location: "",
                    permanent: rtc.permanent || false,
                    segments: [segment],
                    closuresType: 'roadClosure',
                    reverseSegments: {}
                };

                const closure = new sc(closureDetails, {
                    dataModel: W.model,
                    segmentSelection: W.selectionManager.getSegmentSelection(),
                    isNewClosure: true,
                    closedNodesMap: {}
                });

                if (closure.closureNodes?.models) {
                    for (const n of closure.closureNodes.models) {
                        n.attributes.isClosed = false;
                    }
                }

                const action = cab.add(closure, W.loginManager.user, W.model);

                W.controller.save({ actions: [action] }).then(() => {
                    importedCount++;
                    updateStatusMessage(`Importiere... ${currentIndex}/${rtcList.length}`, '#2196F3');
                    importNext();
                }).catch((err) => {
                    errorCount++;
                    log(`Import Fehler für Segment ${rtc.segmentId}: ${err.errors?.[0]?.attributes?.details || err.message}`);
                    importNext();
                });
            };

            updateStatusMessage(`Importiere... 0/${rtcList.length}`, '#2196F3');
            importNext();
        }

        // Kreise Export/Import Funktionen
        function exportCirclesInArea() {
            log('=== Kreise Export ===');

            if (!radiusLayer || !radiusLayer.features || radiusLayer.features.length === 0) {
                updateStatusMessage(t('noCirclesToExport'), '#ff9800');
                return;
            }

            // Mercator zu WGS84 Konvertierung
            function mercatorToWgs84(x, y) {
                const lon = (x / 20037508.34) * 180;
                let lat = (y / 20037508.34) * 180;
                lat = (180 / Math.PI) * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
                return [lon, lat];
            }

            const circles = [];

            for (const feature of radiusLayer.features) {
                if (!feature.geometry) continue;

                const geom = feature.geometry;
                const coords = [];

                if (geom.CLASS_NAME === "OpenLayers.Geometry.Polygon") {
                    const ring = geom.components?.[0];
                    if (ring && ring.components) {
                        for (const point of ring.components) {
                            const [lon, lat] = mercatorToWgs84(point.x, point.y);
                            coords.push([lon, lat]);
                        }
                    }
                }

                if (coords.length > 0) {
                    // Berechne Mittelpunkt und Radius
                    const bounds = geom.getBounds();
                    const centerX = (bounds.left + bounds.right) / 2;
                    const centerY = (bounds.bottom + bounds.top) / 2;
                    const [centerLon, centerLat] = mercatorToWgs84(centerX, centerY);

                    // Radius in Metern berechnen
                    const startPoint = new uOpenLayers.Geometry.Point(centerX, centerY);
                    const endPoint = new uOpenLayers.Geometry.Point(bounds.right, centerY);
                    const radiusLine = new uOpenLayers.Geometry.LineString([startPoint, endPoint]);
                    const radiusMeters = radiusLine.getGeodesicLength(new uOpenLayers.Projection("EPSG:900913"));

                    circles.push({
                        type: 'circle',
                        center: [centerLon, centerLat],
                        radiusMeters: Math.round(radiusMeters),
                        coordinates: coords
                    });
                }
            }

            if (circles.length === 0) {
                updateStatusMessage(t('noCirclesToExport'), '#ff9800');
                return;
            }

            const exportData = {
                version: 1,
                type: 'circles',
                exportDate: new Date().toISOString(),
                circles: circles
            };

            try {
                const jsonStr = JSON.stringify(exportData, null, 2);
                const blob = new Blob([jsonStr], { type: 'application/json' });
                const url = URL.createObjectURL(blob);

                const a = document.createElement('a');
                a.href = url;
                a.download = `wme-circles-export-${new Date().toISOString().slice(0,10)}.json`;
                a.style.display = 'none';
                document.body.appendChild(a);
                a.click();

                setTimeout(() => {
                    document.body.removeChild(a);
                    URL.revokeObjectURL(url);
                }, 100);

                updateStatusMessage(t('exportedCircles', circles.length), '#4CAF50');
                log(`✓ ${circles.length} Kreise exportiert`);
            } catch (err) {
                warn('Export Fehler:', err);
                updateStatusMessage('Export Fehler: ' + err.message, '#f44336');
            }
        }

        function importCirclesFromFile(file) {
            const reader = new FileReader();

            reader.onload = function(e) {
                try {
                    const data = JSON.parse(e.target.result);

                    if (data.type === 'circles' && data.circles && Array.isArray(data.circles)) {
                        importCircles(data.circles);
                    } else {
                        updateStatusMessage('Ungültiges Dateiformat (keine Kreise)', '#f44336');
                    }
                } catch (err) {
                    warn('Import Fehler:', err);
                    updateStatusMessage('Fehler beim Lesen der Datei', '#f44336');
                }
            };

            reader.readAsText(file);
        }

        function importCircles(circleList) {
            if (circleList.length === 0) {
                updateStatusMessage('Keine Kreise zum Importieren', '#ff9800');
                return;
            }

            // WGS84 zu Mercator Konvertierung
            function wgs84ToMercator(lon, lat) {
                const x = lon * 20037508.34 / 180;
                let y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
                y = y * 20037508.34 / 180;
                return [x, y];
            }

            let importedCount = 0;

            for (const circle of circleList) {
                try {
                    let points = [];

                    if (circle.coordinates && circle.coordinates.length > 0) {
                        // Verwende gespeicherte Koordinaten
                        for (const coord of circle.coordinates) {
                            const [mx, my] = wgs84ToMercator(coord[0], coord[1]);
                            points.push(new uOpenLayers.Geometry.Point(mx, my));
                        }
                    } else if (circle.center && circle.radiusMeters) {
                        // Erstelle Kreis aus Mittelpunkt und Radius
                        const steps = 100;
                        for (let i = 0; i <= steps; i++) {
                            const bearing = (i / steps) * 360;
                            const destPoint = destinationPoint(circle.center, circle.radiusMeters, bearing);
                            const [mx, my] = wgs84ToMercator(destPoint[0], destPoint[1]);
                            points.push(new uOpenLayers.Geometry.Point(mx, my));
                        }
                    }

                    if (points.length > 2) {
                        const ring = new uOpenLayers.Geometry.LinearRing(points);
                        const polygon = new uOpenLayers.Geometry.Polygon([ring]);
                        const feature = new uOpenLayers.Feature.Vector(polygon);
                        radiusLayer.addFeatures([feature]);
                        importedCount++;
                    }
                } catch (err) {
                    warn('Fehler beim Importieren eines Kreises:', err);
                }
            }

            if (radiusLayer.redraw) radiusLayer.redraw();

            setTimeout(() => {
                document.dispatchEvent(new CustomEvent('updateAnnotations'));
            }, 100);

            updateStatusMessage(t('importedCircles', importedCount), '#4CAF50');
            log(`✓ ${importedCount} Kreise importiert`);
        }

        // GPX Import/Export Funktionen
        function exportSelectedAsGpx() {
            log('=== GPX Export ===');

            // Exportiere ausgewählte Segmente oder Segmente im Kreis
            const selectedSegments = uWaze.selectionManager?.getSelectedFeatures?.() || [];
            let segmentsToExport = [];

            if (selectedSegments.length > 0) {
                // Ausgewählte Segmente exportieren
                segmentsToExport = selectedSegments.filter(f => f?.model?.type === 'segment').map(f => f.model);
            } else if (radiusLayer?.features?.length > 0) {
                // Segmente im Kreis exportieren
                const allSegments = uWaze.model.segments.getObjectArray();
                for (const segment of allSegments) {
                    if (!segment?.attributes?.roadType) continue;
                    const segGeom = segment.getOLGeometry?.() || segment.geometry;
                    if (!segGeom) continue;

                    for (const drawnFeature of radiusLayer.features) {
                        if (drawnFeature.geometry.intersects(segGeom)) {
                            segmentsToExport.push(segment);
                            break;
                        }
                    }
                }
            }

            if (segmentsToExport.length === 0) {
                updateStatusMessage('Keine Segmente zum Exportieren', '#ff9800');
                return;
            }

            // GPX erstellen
            const gpxHeader = `<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.1" creator="WME Circles" xmlns="http://www.topografix.com/GPX/1/1">
  <metadata>
    <name>WME Segments Export</name>
    <time>${new Date().toISOString()}</time>
  </metadata>`;

            let gpxTracks = '';

            // Mercator zu WGS84
            const toWGS84 = (x, y) => {
                const lon = x * 180 / 20037508.34;
                let lat = y * 180 / 20037508.34;
                lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
                return { lon, lat };
            };

            for (const segment of segmentsToExport) {
                const streetName = getSegmentStreetName(segment) || 'Unbekannt';
                const segId = segment.attributes?.id || segment.getID?.();

                let coords = [];
                const geom = segment.getOLGeometry?.() || segment.geometry || segment.attributes?.geometry;

                if (geom?.components) {
                    coords = geom.components.map(c => toWGS84(c.x, c.y));
                } else if (geom?.coordinates) {
                    coords = geom.coordinates.map(c => ({ lon: c[0], lat: c[1] }));
                } else if (geom?.getVertices) {
                    coords = geom.getVertices().map(v => toWGS84(v.x, v.y));
                }

                if (coords.length > 0) {
                    gpxTracks += `
  <trk>
    <name>${streetName} (${segId})</name>
    <trkseg>`;
                    for (const c of coords) {
                        gpxTracks += `
      <trkpt lat="${c.lat.toFixed(7)}" lon="${c.lon.toFixed(7)}"/>`;
                    }
                    gpxTracks += `
    </trkseg>
  </trk>`;
                }
            }

            const gpxContent = gpxHeader + gpxTracks + '\n</gpx>';

            // Download
            const blob = new Blob([gpxContent], { type: 'application/gpx+xml' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `wme-segments-${new Date().toISOString().slice(0,10)}.gpx`;
            document.body.appendChild(a);
            a.click();
            setTimeout(() => {
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
            }, 100);

            updateStatusMessage(t('exportedGpx') + ` (${segmentsToExport.length})`, '#4CAF50');
        }

        function getSegmentStreetName(segment) {
            if (!segment?.attributes) return null;
            const primaryStreet = segment.attributes.primaryStreetID;
            if (primaryStreet && uWaze?.model?.streets) {
                const street = uWaze.model.streets.getObjectById(primaryStreet);
                if (street?.attributes?.name) return street.attributes.name;
            }
            return segment.attributes.streetName || null;
        }

        function importGpxFile(file) {
            const reader = new FileReader();

            reader.onload = function(e) {
                try {
                    const parser = new DOMParser();
                    const gpxDoc = parser.parseFromString(e.target.result, 'text/xml');

                    // Prüfe auf Parse-Fehler
                    const parseError = gpxDoc.querySelector('parsererror');
                    if (parseError) {
                        log('GPX Parse-Fehler: ' + parseError.textContent);
                        updateStatusMessage('GPX Parse-Fehler', '#f44336');
                        return;
                    }

                    // Extrahiere alle Track-Punkte und Route-Punkte
                    const points = [];

                    // Track Points (trkpt) - mit und ohne Namespace
                    let trkpts = gpxDoc.querySelectorAll('trkpt');
                    if (trkpts.length === 0) {
                        trkpts = gpxDoc.getElementsByTagNameNS('*', 'trkpt');
                    }
                    log(`GPX: ${trkpts.length} trkpt Elemente gefunden`);

                    for (const pt of trkpts) {
                        const lat = parseFloat(pt.getAttribute('lat'));
                        const lon = parseFloat(pt.getAttribute('lon'));
                        if (!isNaN(lat) && !isNaN(lon) && Math.abs(lat) <= 90 && Math.abs(lon) <= 180) {
                            points.push({ lat, lon });
                        }
                    }

                    // Route Points (rtept)
                    let rtepts = gpxDoc.querySelectorAll('rtept');
                    if (rtepts.length === 0) {
                        rtepts = gpxDoc.getElementsByTagNameNS('*', 'rtept');
                    }
                    log(`GPX: ${rtepts.length} rtept Elemente gefunden`);

                    for (const pt of rtepts) {
                        const lat = parseFloat(pt.getAttribute('lat'));
                        const lon = parseFloat(pt.getAttribute('lon'));
                        if (!isNaN(lat) && !isNaN(lon) && Math.abs(lat) <= 90 && Math.abs(lon) <= 180) {
                            points.push({ lat, lon });
                        }
                    }

                    // Waypoints (wpt)
                    let wpts = gpxDoc.querySelectorAll('wpt');
                    if (wpts.length === 0) {
                        wpts = gpxDoc.getElementsByTagNameNS('*', 'wpt');
                    }
                    log(`GPX: ${wpts.length} wpt Elemente gefunden`);

                    for (const pt of wpts) {
                        const lat = parseFloat(pt.getAttribute('lat'));
                        const lon = parseFloat(pt.getAttribute('lon'));
                        if (!isNaN(lat) && !isNaN(lon) && Math.abs(lat) <= 90 && Math.abs(lon) <= 180) {
                            points.push({ lat, lon });
                        }
                    }

                    if (points.length === 0) {
                        // Debug: Zeige XML-Struktur
                        log('GPX XML Root: ' + gpxDoc.documentElement?.tagName);
                        log('GPX XML Children: ' + Array.from(gpxDoc.documentElement?.children || []).map(c => c.tagName).join(', '));
                        updateStatusMessage('Keine Punkte in GPX gefunden', '#ff9800');
                        return;
                    }

                    // Debug: Erste 3 Punkte zeigen
                    log(`GPX: ${points.length} Punkte gefunden`);
                    if (points.length > 0) {
                        log(`GPX Erster Punkt: ${points[0].lat.toFixed(5)}, ${points[0].lon.toFixed(5)}`);
                    }

                    // Zur GPX-Position zoomen (Mittelpunkt der Punkte)
                    const avgLat = points.reduce((s, p) => s + p.lat, 0) / points.length;
                    const avgLon = points.reduce((s, p) => s + p.lon, 0) / points.length;

                    log(`GPX Zentrum: ${avgLat.toFixed(5)}, ${avgLon.toFixed(5)}`);

                    // Starte Auto-Scroll mit Kontrolle
                    startGpxAutoScroll(points);

                } catch (err) {
                    warn('GPX Import Fehler:', err);
                    updateStatusMessage('GPX Fehler: ' + err.message, '#f44336');
                }
            };

            reader.readAsText(file);
        }

        // GPX-Linie auf der Karte zeichnen
        function drawGpxLine(gpxPoints) {
            removeGpxLine(); // Alte Linie entfernen

            try {
                const OL = window.OpenLayers || window.OL;
                if (!OL || !uWaze?.map?.olMap) return;

                // Layer erstellen
                const layer = new OL.Layer.Vector('GPX Route', {
                    displayInLayerSwitcher: false,
                    uniqueName: 'rtcplus_gpx_route'
                });

                // Punkte in Mercator konvertieren
                const points = gpxPoints.map(p => {
                    const mercX = p.lon * 20037508.34 / 180;
                    const mercY = Math.log(Math.tan((90 + p.lat) * Math.PI / 360)) / (Math.PI / 180) * 20037508.34 / 180;
                    return new OL.Geometry.Point(mercX, mercY);
                });

                // Linie erstellen
                const line = new OL.Geometry.LineString(points);
                const feature = new OL.Feature.Vector(line, {}, {
                    strokeColor: '#FF00FF',
                    strokeWidth: 4,
                    strokeOpacity: 0.7,
                    strokeDashstyle: 'dash'
                });

                layer.addFeatures([feature]);
                uWaze.map.olMap.addLayer(layer);

                gpxAutoScroll.gpxLayer = layer;
                log('GPX-Linie gezeichnet');
            } catch (e) {
                warn('GPX-Linie zeichnen fehlgeschlagen:', e);
            }
        }

        function removeGpxLine() {
            if (gpxAutoScroll.gpxLayer) {
                try {
                    uWaze.map.olMap.removeLayer(gpxAutoScroll.gpxLayer);
                    gpxAutoScroll.gpxLayer.destroy();
                } catch (e) {}
                gpxAutoScroll.gpxLayer = null;
            }
        }

        // GPX Auto-Scroll mit Benutzer-Kontrolle
        let gpxAutoScroll = {
            active: false,
            paused: false,
            gpxPoints: [],
            scrollPositions: [],
            currentIndex: 0,
            collectedSegmentIds: new Set(),
            timeoutId: null,
            gpxLayer: null
        };

        function startGpxAutoScroll(gpxPoints) {
            // GPX-Linie auf der Karte zeichnen
            drawGpxLine(gpxPoints);

            // Scroll-Positionen berechnen
            const scrollPositions = [];
            let lastLat = null, lastLon = null;
            const MIN_DISTANCE = 300; // 300m Schritte

            for (const p of gpxPoints) {
                if (lastLat === null) {
                    scrollPositions.push({ lat: p.lat, lon: p.lon });
                    lastLat = p.lat;
                    lastLon = p.lon;
                } else {
                    const R = 6371000;
                    const dLat = (p.lat - lastLat) * Math.PI / 180;
                    const dLon = (p.lon - lastLon) * Math.PI / 180;
                    const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                              Math.cos(lastLat * Math.PI / 180) * Math.cos(p.lat * Math.PI / 180) *
                              Math.sin(dLon/2) * Math.sin(dLon/2);
                    const dist = R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

                    if (dist >= MIN_DISTANCE) {
                        scrollPositions.push({ lat: p.lat, lon: p.lon });
                        lastLat = p.lat;
                        lastLon = p.lon;
                    }
                }
            }

            // Letzten Punkt
            const lastPoint = gpxPoints[gpxPoints.length - 1];
            if (scrollPositions.length === 0 ||
                scrollPositions[scrollPositions.length-1].lat !== lastPoint.lat) {
                scrollPositions.push({ lat: lastPoint.lat, lon: lastPoint.lon });
            }

            gpxAutoScroll = {
                active: true,
                paused: false,
                gpxPoints: gpxPoints,
                scrollPositions: scrollPositions,
                currentIndex: 0,
                collectedSegmentIds: new Set(),
                timeoutId: null
            };

            log(`GPX Auto-Scroll: ${scrollPositions.length} Positionen`);

            // UI anzeigen
            showGpxAutoScrollUI();

            // Zoom setzen
            try {
                if (uWaze?.map?.olMap?.zoomTo) {
                    uWaze.map.olMap.zoomTo(17);
                }
            } catch (e) {}

            // Starten
            gpxScrollNext();
        }

        function gpxScrollNext() {
            if (!gpxAutoScroll.active) return;
            if (gpxAutoScroll.paused) return;

            const { scrollPositions, currentIndex, gpxPoints } = gpxAutoScroll;

            if (currentIndex >= scrollPositions.length) {
                // Fertig!
                finishGpxAutoScroll();
                return;
            }

            const pos = scrollPositions[currentIndex];

            // Zur Position scrollen
            try {
                const mercX = pos.lon * 20037508.34 / 180;
                const mercY = Math.log(Math.tan((90 + pos.lat) * Math.PI / 360)) / (Math.PI / 180) * 20037508.34 / 180;

                if (uWaze?.map?.setCenter) {
                    uWaze.map.setCenter({ lon: mercX, lat: mercY });
                }
            } catch (e) {}

            // UI aktualisieren
            updateGpxAutoScrollUI();

            // Segmente sammeln nach kurzer Wartezeit
            gpxAutoScroll.timeoutId = setTimeout(() => {
                // Segmente matchen
                const matches = matchGpxToSegmentsLocal(gpxPoints);
                const newSegments = [];

                for (const seg of matches) {
                    const segId = seg.attributes?.id || seg.getID?.();
                    if (segId && !gpxAutoScroll.collectedSegmentIds.has(segId)) {
                        gpxAutoScroll.collectedSegmentIds.add(segId);
                        newSegments.push(seg);
                    }
                }

                // INKREMENTELL zur Auswahl hinzufügen (nicht ersetzen!)
                if (newSegments.length > 0) {
                    try {
                        const currentSelection = uWaze.selectionManager.getSelectedFeatures() || [];
                        const currentSegments = currentSelection
                            .filter(f => f?.model?.type === 'segment')
                            .map(f => f.model);

                        // Neue Segmente zur bestehenden Auswahl hinzufügen
                        const combinedSelection = [...currentSegments, ...newSegments];
                        uWaze.selectionManager.setSelectedModels(combinedSelection);
                    } catch (e) {
                        // Fallback: Nur neue Segmente auswählen
                        try {
                            const current = uWaze.selectionManager.getSelectedDataModelObjects?.() || [];
                            uWaze.selectionManager.setSelectedModels([...current, ...newSegments]);
                        } catch (e2) {}
                    }
                }

                // UI aktualisieren
                updateGpxAutoScrollUI();

                // Nächste Position
                gpxAutoScroll.currentIndex++;
                gpxScrollNext();

            }, 800); // 800ms pro Position für zuverlässiges Laden
        }

        function showGpxAutoScrollUI() {
            let ui = document.getElementById('gpx-autoscroll-ui');
            if (ui) ui.remove();

            ui = document.createElement('div');
            ui.id = 'gpx-autoscroll-ui';
            ui.style.cssText = `
                position: fixed;
                top: 10px;
                left: 50%;
                transform: translateX(-50%);
                background: rgba(0,0,0,0.92);
                color: white;
                padding: 12px 16px;
                border-radius: 10px;
                z-index: 99999;
                font-family: Arial, sans-serif;
                box-shadow: 0 4px 20px rgba(0,0,0,0.5);
                min-width: 380px;
            `;

            document.body.appendChild(ui);
            updateGpxAutoScrollUI();
        }

        function updateGpxAutoScrollUI() {
            const ui = document.getElementById('gpx-autoscroll-ui');
            if (!ui) return;

            const { scrollPositions, currentIndex, collectedSegmentIds, paused } = gpxAutoScroll;
            const total = scrollPositions.length;
            const percent = total > 0 ? Math.round((currentIndex / total) * 100) : 0;

            // Zähle aktuell ausgewählte Segmente
            let selectedCount = 0;
            try {
                const selection = uWaze.selectionManager.getSelectedFeatures() || [];
                selectedCount = selection.filter(f => f?.model?.type === 'segment').length;
            } catch (e) {
                selectedCount = collectedSegmentIds.size;
            }

            ui.innerHTML = `
                <div style="display: flex; align-items: center; gap: 12px;">
                    <div style="flex: 1;">
                        <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px;">
                            <span style="font-size: 13px; font-weight: bold;">🗺️ GPX Import</span>
                            <span style="font-size: 12px; color: #aaa;">${currentIndex}/${total}</span>
                        </div>
                        <div style="background: #333; border-radius: 4px; height: 8px; overflow: hidden;">
                            <div style="background: #4CAF50; height: 100%; width: ${percent}%; transition: width 0.2s;"></div>
                        </div>
                    </div>
                    <div style="text-align: center; min-width: 70px;">
                        <div style="font-size: 18px; font-weight: bold; color: #4CAF50;">${selectedCount}</div>
                        <div style="font-size: 9px; color: #888;">ausgewählt</div>
                    </div>
                    <button id="gpx-pause-btn" style="background: ${paused ? '#4CAF50' : '#ff9800'}; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: pointer; font-size: 16px;" title="${paused ? 'Fortsetzen' : 'Pause'}">
                        ${paused ? '▶' : '⏸'}
                    </button>
                    <button id="gpx-stop-btn" style="background: #f44336; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: pointer; font-size: 14px;" title="Beenden & Auswählen">
                        ✓
                    </button>
                    <button id="gpx-cancel-btn" style="background: #666; color: white; border: none; padding: 8px 10px; border-radius: 5px; cursor: pointer; font-size: 12px;" title="Abbrechen">
                        ✕
                    </button>
                </div>
            `;

            // Event Listener
            document.getElementById('gpx-pause-btn')?.addEventListener('click', toggleGpxPause);
            document.getElementById('gpx-stop-btn')?.addEventListener('click', finishGpxAutoScroll);
            document.getElementById('gpx-cancel-btn')?.addEventListener('click', cancelGpxAutoScroll);
        }

        function toggleGpxPause() {
            gpxAutoScroll.paused = !gpxAutoScroll.paused;

            if (!gpxAutoScroll.paused) {
                // Fortsetzen
                gpxScrollNext();
            }

            updateGpxAutoScrollUI();
        }

        function finishGpxAutoScroll() {
            if (gpxAutoScroll.timeoutId) {
                clearTimeout(gpxAutoScroll.timeoutId);
            }

            const collectedIds = gpxAutoScroll.collectedSegmentIds;
            const gpxPoints = gpxAutoScroll.gpxPoints;

            log(`GPX Auto-Scroll Sammlung beendet: ${collectedIds.size} Segment-IDs`);

            if (collectedIds.size === 0) {
                const ui = document.getElementById('gpx-autoscroll-ui');
                if (ui) ui.remove();
                gpxAutoScroll.active = false;
                updateStatusMessage(t('gpxNoSegments'), '#ff9800');
                return;
            }

            // PRUNE: Finde den optimalen Pfad durch die gesammelten Segmente
            updateGpxAutoScrollUIText('Berechne optimale Route...');

            setTimeout(() => {
                const prunedIds = pruneSegmentIds(collectedIds, gpxPoints);
                log(`GPX Prune: ${prunedIds.length} Segmente auf optimalem Pfad`);

                // WICHTIG: Speichere IDs SOFORT global für Brush-Modus
                window._gpxSegmentIds = new Set(prunedIds);
                log(`GPX: ${window._gpxSegmentIds.size} Segment-IDs global gespeichert`);

                // Speichere für Auswahl-Durchgang
                gpxAutoScroll.prunedIds = prunedIds;
                gpxAutoScroll.currentIndex = 0;

                // Starte Auswahl-Durchgang
                updateGpxAutoScrollUIText('Wähle Segmente aus...');
                selectPrunedSegments();
            }, 100);
        }

        function updateGpxAutoScrollUIText(text) {
            const ui = document.getElementById('gpx-autoscroll-ui');
            if (ui) {
                const titleSpan = ui.querySelector('span');
                if (titleSpan) titleSpan.textContent = '🗺️ ' + text;
            }
        }

        // PRUNE: Bilde eine Kette entlang der GPX-Route, entferne tote Arme
        function pruneSegmentIds(collectedIds, gpxPoints) {
            const segments = uWaze.model.segments.getObjectArray();

            // Sammle Segment-Daten mit GPX-Position
            const segmentMap = new Map();
            for (const seg of segments) {
                const id = seg.attributes?.id || seg.getID?.();
                if (!id || !collectedIds.has(id)) continue;

                const coords = getSegmentCoordsWGS84(seg);
                if (!coords || coords.length < 2) continue;

                // Berechne GPX-Position (wo auf der GPX-Linie liegt dieses Segment)
                const midPt = { lat: coords[Math.floor(coords.length/2)][1], lon: coords[Math.floor(coords.length/2)][0] };
                const gpxPos = findGpxPosition(midPt, gpxPoints);

                segmentMap.set(id, {
                    id: id,
                    coords: coords,
                    fromNode: seg.attributes?.fromNodeID,
                    toNode: seg.attributes?.toNodeID,
                    gpxPos: gpxPos
                });
            }

            if (segmentMap.size === 0) return [...collectedIds];

            // Baue Node-zu-Segment Index
            const nodeToSegs = new Map();
            for (const [id, sd] of segmentMap) {
                if (sd.fromNode) {
                    if (!nodeToSegs.has(sd.fromNode)) nodeToSegs.set(sd.fromNode, []);
                    nodeToSegs.get(sd.fromNode).push(sd);
                }
                if (sd.toNode) {
                    if (!nodeToSegs.has(sd.toNode)) nodeToSegs.set(sd.toNode, []);
                    nodeToSegs.get(sd.toNode).push(sd);
                }
            }

            // Sortiere alle Segmente nach GPX-Position
            const sortedSegs = [...segmentMap.values()].sort((a, b) => a.gpxPos - b.gpxPos);

            // Finde Start-Segment (niedrigste GPX-Position)
            const startSeg = sortedSegs[0];
            if (!startSeg) return [...collectedIds];

            // Bestimme Start-Node (der Node der NICHT in GPX-Richtung zeigt)
            const startCoord = startSeg.coords[0];
            const endCoord = startSeg.coords[startSeg.coords.length - 1];
            const startGpxPos = findGpxPosition({ lat: startCoord[1], lon: startCoord[0] }, gpxPoints);
            const endGpxPos = findGpxPosition({ lat: endCoord[1], lon: endCoord[0] }, gpxPoints);

            // currentNode ist der Exit-Node (höhere GPX-Position)
            let currentNode = startGpxPos < endGpxPos ? startSeg.toNode : startSeg.fromNode;

            // Baue Kette
            const chain = [startSeg.id];
            const usedIds = new Set([startSeg.id]);
            let lastGpxPos = startSeg.gpxPos;

            for (let step = 0; step < 2000; step++) {
                // Finde nächstes Segment über currentNode
                const candidates = nodeToSegs.get(currentNode) || [];
                let bestNext = null;
                let bestScore = -Infinity;

                for (const cand of candidates) {
                    if (usedIds.has(cand.id)) continue;

                    // Score basiert auf:
                    // 1. GPX-Position muss vorwärts sein (höher als lastGpxPos)
                    // 2. Aber nicht zu weit springen
                    const posDiff = cand.gpxPos - lastGpxPos;

                    // Muss vorwärts sein (oder minimal rückwärts für Kurven)
                    if (posDiff < -50) continue; // Nicht mehr als 50m zurück

                    // Score: Vorwärts ist gut, aber nicht zu weit springen
                    let score = 100;
                    if (posDiff > 0 && posDiff < 500) {
                        score = 200 - posDiff * 0.1; // Nähere Segmente bevorzugen
                    } else if (posDiff >= 500) {
                        score = 50; // Weite Sprünge sind schlecht
                    }

                    if (score > bestScore) {
                        bestScore = score;
                        bestNext = cand;
                    }
                }

                if (!bestNext) {
                    // Keine direkte Verbindung - versuche Lücke zu überbrücken
                    // Suche das nächste Segment auf der GPX-Linie das noch nicht verwendet wurde
                    let nextOnGpx = null;
                    let minPosDiff = Infinity;

                    for (const sd of sortedSegs) {
                        if (usedIds.has(sd.id)) continue;
                        const posDiff = sd.gpxPos - lastGpxPos;
                        if (posDiff > 0 && posDiff < minPosDiff) {
                            minPosDiff = posDiff;
                            nextOnGpx = sd;
                        }
                    }

                    if (nextOnGpx && minPosDiff < 200) {
                        // Springe zum nächsten Segment (Lücke akzeptieren)
                        bestNext = nextOnGpx;
                        log(`GPX Prune: Lücke übersprungen (${Math.round(minPosDiff)}m)`);
                    } else {
                        break; // Keine Fortsetzung möglich
                    }
                }

                // Füge Segment hinzu
                chain.push(bestNext.id);
                usedIds.add(bestNext.id);
                lastGpxPos = bestNext.gpxPos;

                // Update currentNode
                if (bestNext.fromNode === currentNode) {
                    currentNode = bestNext.toNode;
                } else {
                    currentNode = bestNext.fromNode;
                }

                // Sind wir am Ende der GPX-Linie?
                const gpxTotalLen = gpxPoints.length > 1 ?
                    findGpxPosition(gpxPoints[gpxPoints.length-1], gpxPoints) : 0;
                if (lastGpxPos >= gpxTotalLen * 0.95) {
                    break;
                }
            }

            log(`GPX Prune: Kette mit ${chain.length} Segmenten (von ${segmentMap.size} geflooded)`);
            return chain;
        }

        // Finde Position auf GPX-Linie (kumulative Distanz in Metern)
        function findGpxPosition(pt, gpxPoints) {
            let cumDist = 0;
            let bestDist = Infinity;
            let bestPos = 0;

            for (let i = 0; i < gpxPoints.length - 1; i++) {
                const segLen = haversineDistance(
                    gpxPoints[i].lat, gpxPoints[i].lon,
                    gpxPoints[i+1].lat, gpxPoints[i+1].lon
                );

                // Projektion auf dieses Segment
                const proj = projectPointToSegment(
                    pt.lat, pt.lon,
                    gpxPoints[i].lat, gpxPoints[i].lon,
                    gpxPoints[i+1].lat, gpxPoints[i+1].lon
                );

                if (proj.dist < bestDist) {
                    bestDist = proj.dist;
                    bestPos = cumDist + proj.t * segLen;
                }

                cumDist += segLen;
            }

            return bestPos;
        }

        // Projiziere Punkt auf Liniensegment
        function projectPointToSegment(pLat, pLon, aLat, aLon, bLat, bLon) {
            const dLat = bLat - aLat;
            const dLon = bLon - aLon;
            const lenSq = dLat * dLat + dLon * dLon;

            let t = 0;
            if (lenSq > 0) {
                t = Math.max(0, Math.min(1, ((pLat - aLat) * dLat + (pLon - aLon) * dLon) / lenSq));
            }

            const projLat = aLat + t * dLat;
            const projLon = aLon + t * dLon;

            return {
                t: t,
                dist: haversineDistance(pLat, pLon, projLat, projLon)
            };
        }

        // Distanz von Punkt zu Segment (für Flood-Matching)
        function distToSegment(pt, coords) {
            let minD = Infinity;
            for (let i = 0; i < coords.length - 1; i++) {
                const d = pointToLineDist(pt.lat, pt.lon, coords[i][1], coords[i][0], coords[i+1][1], coords[i+1][0]);
                if (d < minD) minD = d;
            }
            return minD;
        }

        function pointToLineDist(pLat, pLon, aLat, aLon, bLat, bLon) {
            const dLat = bLat - aLat, dLon = bLon - aLon;
            const lenSq = dLat * dLat + dLon * dLon;
            const t = lenSq > 0 ? Math.max(0, Math.min(1, ((pLat - aLat) * dLat + (pLon - aLon) * dLon) / lenSq)) : 0;
            return haversineDistance(pLat, pLon, aLat + t * dLat, aLon + t * dLon);
        }

        function pointToSegmentDistanceSimple(point, coords) {
            let minDist = Infinity;
            for (let i = 0; i < coords.length - 1; i++) {
                const dist = pointToLineDistSimple(
                    point.lat, point.lon,
                    coords[i][1], coords[i][0],
                    coords[i+1][1], coords[i+1][0]
                );
                if (dist < minDist) minDist = dist;
            }
            return minDist;
        }

        function pointToLineDistSimple(pLat, pLon, aLat, aLon, bLat, bLon) {
            const dLat = bLat - aLat;
            const dLon = bLon - aLon;
            const lenSq = dLat * dLat + dLon * dLon;
            let t = lenSq > 0 ? Math.max(0, Math.min(1, ((pLat - aLat) * dLat + (pLon - aLon) * dLon) / lenSq)) : 0;
            const projLat = aLat + t * dLat;
            const projLon = aLon + t * dLon;
            return haversineDistance(pLat, pLon, projLat, projLon);
        }

        // Auswahl-Durchgang: Scrolle nochmal und wähle die geprunten Segmente aus
        function selectPrunedSegments() {
            const { scrollPositions, currentIndex, prunedIds } = gpxAutoScroll;

            if (currentIndex >= scrollPositions.length) {
                // Fertig!
                finishGpxSelection();
                return;
            }

            const pos = scrollPositions[currentIndex];

            // Scrollen
            try {
                const mercX = pos.lon * 20037508.34 / 180;
                const mercY = Math.log(Math.tan((90 + pos.lat) * Math.PI / 360)) / (Math.PI / 180) * 20037508.34 / 180;
                uWaze.map.setCenter({ lon: mercX, lat: mercY });
            } catch (e) {}

            // UI Update
            const ui = document.getElementById('gpx-autoscroll-ui');
            if (ui) {
                const total = scrollPositions.length;
                const percent = Math.round((currentIndex / total) * 100);
                const progressDiv = ui.querySelector('div > div > div:nth-child(2)');
                if (progressDiv) {
                    progressDiv.innerHTML = `<div style="background: #2196F3; height: 100%; width: ${percent}%;"></div>`;
                }
            }

            // Warte und wähle Segmente
            gpxAutoScroll.timeoutId = setTimeout(() => {
                // Finde und wähle Segmente
                const prunedSet = new Set(prunedIds);
                const segments = uWaze.model.segments.getObjectArray();
                const toAdd = [];

                for (const seg of segments) {
                    const id = seg.attributes?.id || seg.getID?.();
                    if (prunedSet.has(id)) {
                        toAdd.push(seg);
                    }
                }

                if (toAdd.length > 0) {
                    try {
                        const current = uWaze.selectionManager.getSelectedFeatures() || [];
                        const currentSegs = current.filter(f => f?.model?.type === 'segment').map(f => f.model);
                        const currentIds = new Set(currentSegs.map(s => s.attributes?.id));
                        const newSegs = toAdd.filter(s => !currentIds.has(s.attributes?.id));
                        if (newSegs.length > 0) {
                            uWaze.selectionManager.setSelectedModels([...currentSegs, ...newSegs]);
                        }
                    } catch (e) {}
                }

                gpxAutoScroll.currentIndex++;
                selectPrunedSegments();
            }, 500);
        }

        function finishGpxSelection() {
            const ui = document.getElementById('gpx-autoscroll-ui');
            if (ui) ui.remove();

            gpxAutoScroll.active = false;

            // Zähle ausgewählte Segmente
            let count = 0;
            try {
                const sel = uWaze.selectionManager.getSelectedFeatures() || [];
                count = sel.filter(f => f?.model?.type === 'segment').length;
            } catch (e) {}

            if (count > 0) {
                updateStatusMessage(t('importedGpx', count), '#4CAF50');
            } else {
                updateStatusMessage('Segmente konnten nicht ausgewählt werden', '#ff9800');
            }

            // GPX-Linie nach kurzer Zeit entfernen
            setTimeout(() => removeGpxLine(), 5000);
        }

        function showGpxFinishedUI(totalSegments) {
            let ui = document.getElementById('gpx-finished-ui');
            if (ui) ui.remove();

            ui = document.createElement('div');
            ui.id = 'gpx-finished-ui';
            ui.style.cssText = `
                position: fixed;
                top: 10px;
                left: 50%;
                transform: translateX(-50%);
                background: rgba(0,0,0,0.9);
                color: white;
                padding: 10px 14px;
                border-radius: 8px;
                z-index: 99999;
                font-family: Arial, sans-serif;
                box-shadow: 0 4px 15px rgba(0,0,0,0.4);
            `;

            ui.innerHTML = `
                <div style="display: flex; align-items: center; gap: 10px;">
                    <span style="font-size: 12px;">🗺️ GPX: ${totalSegments} Segmente</span>
                    <button id="gpx-reselect-btn" style="background: #4CAF50; color: white; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer; font-size: 11px;" title="Segmente im aktuellen Bereich auswählen">
                        Auswählen
                    </button>
                    <button id="gpx-clear-btn" style="background: #666; color: white; border: none; padding: 5px 8px; border-radius: 4px; cursor: pointer; font-size: 11px;" title="GPX-Linie entfernen">
                        ✕
                    </button>
                </div>
            `;

            document.body.appendChild(ui);

            document.getElementById('gpx-reselect-btn')?.addEventListener('click', () => {
                reselectGpxSegments();
            });

            document.getElementById('gpx-clear-btn')?.addEventListener('click', () => {
                removeGpxLine();
                ui.remove();
                window._gpxSegmentIds = null;
            });
        }

        function reselectGpxSegments() {
            const segmentIds = window._gpxSegmentIds;
            if (!segmentIds || segmentIds.size === 0) {
                updateStatusMessage('Keine GPX-Segmente gespeichert', '#ff9800');
                return;
            }

            const segments = uWaze.model.segments.getObjectArray();
            const toSelect = segments.filter(seg => {
                const segId = seg.attributes?.id || seg.getID?.();
                return segId && segmentIds.has(segId);
            });

            if (toSelect.length > 0) {
                // Zur bestehenden Auswahl hinzufügen
                try {
                    const currentSelection = uWaze.selectionManager.getSelectedFeatures() || [];
                    const currentSegments = currentSelection
                        .filter(f => f?.model?.type === 'segment')
                        .map(f => f.model);

                    const existingIds = new Set(currentSegments.map(s => s.attributes?.id || s.getID?.()));
                    const newSegments = toSelect.filter(s => {
                        const id = s.attributes?.id || s.getID?.();
                        return !existingIds.has(id);
                    });

                    uWaze.selectionManager.setSelectedModels([...currentSegments, ...newSegments]);
                    updateStatusMessage(`+${newSegments.length} Segmente ausgewählt`, '#4CAF50');
                } catch (e) {
                    uWaze.selectionManager.setSelectedModels(toSelect);
                    updateStatusMessage(`${toSelect.length} Segmente ausgewählt`, '#4CAF50');
                }
            } else {
                updateStatusMessage('Keine passenden Segmente im Bereich', '#ff9800');
            }
        }

        function cancelGpxAutoScroll() {
            if (gpxAutoScroll.timeoutId) {
                clearTimeout(gpxAutoScroll.timeoutId);
            }

            gpxAutoScroll.active = false;

            // GPX-Linie entfernen
            removeGpxLine();

            const ui = document.getElementById('gpx-autoscroll-ui');
            if (ui) ui.remove();

            updateStatusMessage('GPX Import abgebrochen', '#ff9800');
        }

        // Lokales Matching ohne UI-Update (für Auto-Scroll)
        // LÄNGENBASIERTER ANSATZ: Segment muss signifikante Strecke entlang GPX abdecken
        function matchGpxToSegmentsLocal(gpxPoints) {
            if (!uWaze?.model?.segments) return [];
            if (gpxPoints.length < 2) return [];

            const segments = uWaze.model.segments.getObjectArray();
            const MAX_DISTANCE = 15; // 15 Meter maximale Abweichung

            // Filtere gültige Segmente
            const validSegments = segments.filter(seg => {
                if (!seg?.attributes) return false;
                if (seg.isDeleted?.()) return false;
                const roadType = seg.attributes.roadType;
                return roadType && [1, 2, 3, 4, 6, 7, 17, 20, 21].includes(roadType);
            });

            if (validSegments.length === 0) return [];

            // Berechne GPX-Gesamtlänge und erstelle Lookup für schnelle Distanzprüfung
            let gpxTotalLength = 0;
            const gpxCumDist = [0];
            for (let i = 1; i < gpxPoints.length; i++) {
                const d = haversineDistance(
                    gpxPoints[i-1].lat, gpxPoints[i-1].lon,
                    gpxPoints[i].lat, gpxPoints[i].lon
                );
                gpxTotalLength += d;
                gpxCumDist.push(gpxTotalLength);
            }

            const matchedSegments = [];

            for (const seg of validSegments) {
                const segCoordsWGS = getSegmentCoordsWGS84(seg);
                if (!segCoordsWGS || segCoordsWGS.length < 2) continue;

                // Finde Start- und End-Position des Segments auf der GPX-Linie
                let minGpxPos = Infinity;
                let maxGpxPos = -Infinity;
                let allPointsClose = true;

                for (const segPt of segCoordsWGS) {
                    // Finde nächsten Punkt auf GPX-Linie und dessen Position
                    let bestDist = Infinity;
                    let bestGpxPos = -1;

                    for (let i = 0; i < gpxPoints.length - 1; i++) {
                        const result = pointToLineWithPosition(
                            segPt[1], segPt[0],
                            gpxPoints[i].lat, gpxPoints[i].lon,
                            gpxPoints[i+1].lat, gpxPoints[i+1].lon,
                            gpxCumDist[i], gpxCumDist[i+1]
                        );

                        if (result.dist < bestDist) {
                            bestDist = result.dist;
                            bestGpxPos = result.position;
                        }
                    }

                    if (bestDist > MAX_DISTANCE) {
                        allPointsClose = false;
                        break;
                    }

                    if (bestGpxPos < minGpxPos) minGpxPos = bestGpxPos;
                    if (bestGpxPos > maxGpxPos) maxGpxPos = bestGpxPos;
                }

                if (!allPointsClose) continue;

                // Berechne wie viel GPX-Strecke das Segment abdeckt
                const gpxCoverage = maxGpxPos - minGpxPos;

                // Berechne Segment-Länge
                let segLength = 0;
                for (let i = 1; i < segCoordsWGS.length; i++) {
                    segLength += haversineDistance(
                        segCoordsWGS[i-1][1], segCoordsWGS[i-1][0],
                        segCoordsWGS[i][1], segCoordsWGS[i][0]
                    );
                }

                // KRITISCH: Die GPX-Abdeckung muss mindestens 50% der Segment-Länge sein
                // Das filtert Segmente die quer zur Route liegen
                const coverageRatio = gpxCoverage / Math.max(segLength, 1);

                if (coverageRatio < 0.5) continue;

                // Zusätzlich: Segment muss mindestens 10m GPX-Strecke abdecken
                // (filtert sehr kurze Kreuzungssegmente)
                if (gpxCoverage < 10 && segLength > 20) continue;

                matchedSegments.push({
                    segment: seg,
                    gpxCoverage: gpxCoverage,
                    segLength: segLength,
                    coverageRatio: coverageRatio,
                    startPos: minGpxPos,
                    endPos: maxGpxPos
                });
            }

            // Sortiere nach GPX-Position (von Start nach Ende)
            matchedSegments.sort((a, b) => a.startPos - b.startPos);

            console.log(`[WME RTC Plus] GPX Length-Based: ${gpxPoints.length} Punkte → ${matchedSegments.length} Segmente`);

            return matchedSegments.map(m => m.segment);
        }

        // Punkt-zu-Linie mit Position auf der Linie
        function pointToLineWithPosition(pLat, pLon, aLat, aLon, bLat, bLon, aPos, bPos) {
            const dLat = bLat - aLat;
            const dLon = bLon - aLon;
            const lengthSq = dLat * dLat + dLon * dLon;

            let t = 0;
            if (lengthSq > 0) {
                t = Math.max(0, Math.min(1, ((pLat - aLat) * dLat + (pLon - aLon) * dLon) / lengthSq));
            }

            const projLat = aLat + t * dLat;
            const projLon = aLon + t * dLon;

            return {
                dist: haversineDistance(pLat, pLon, projLat, projLon),
                position: aPos + t * (bPos - aPos)
            };
        }

        // Finde ein Verbindungssegment zwischen zwei nicht direkt verbundenen Segmenten
        function findBridgeSegment(segA, segB, segmentsByNode, excludeIds) {
            const aFromNode = segA.attributes?.fromNodeID;
            const aToNode = segA.attributes?.toNodeID;
            const bFromNode = segB.attributes?.fromNodeID;
            const bToNode = segB.attributes?.toNodeID;

            // Suche Segmente die beide verbinden können
            const aNodes = [aFromNode, aToNode].filter(n => n);
            const bNodes = [bFromNode, bToNode].filter(n => n);

            for (const aNode of aNodes) {
                const connectedToA = segmentsByNode.get(aNode) || [];
                for (const bridge of connectedToA) {
                    const bridgeId = bridge.attributes?.id || bridge.getID?.();
                    if (excludeIds.has(bridgeId)) continue;

                    const bridgeFrom = bridge.attributes?.fromNodeID;
                    const bridgeTo = bridge.attributes?.toNodeID;

                    // Prüfe ob dieses Segment auch mit B verbunden ist
                    if (bNodes.includes(bridgeFrom) || bNodes.includes(bridgeTo)) {
                        return bridge;
                    }
                }
            }

            return null;
        }

        // Bestimme welcher Node der Exit-Node ist basierend auf GPX-Richtung
        function determineExitNode(segment, currentPoint, gpxPoints, currentIndex) {
            const fromNode = segment.attributes?.fromNodeID;
            const toNode = segment.attributes?.toNodeID;

            if (!fromNode || !toNode) return null;

            // Hole Segment-Koordinaten
            const segCoords = getSegmentCoordsWGS84(segment);
            if (!segCoords || segCoords.length < 2) return toNode;

            // Segment Start und Ende
            const segStart = segCoords[0];
            const segEnd = segCoords[segCoords.length - 1];

            // Finde nächsten GPX-Punkt (Richtung)
            let nextPoint = null;
            for (let i = currentIndex + 1; i < Math.min(currentIndex + 10, gpxPoints.length); i++) {
                const dist = haversineDistance(currentPoint.lat, currentPoint.lon, gpxPoints[i].lat, gpxPoints[i].lon);
                if (dist > 20) { // Mindestens 20m entfernt
                    nextPoint = gpxPoints[i];
                    break;
                }
            }

            if (!nextPoint) return toNode;

            // Welches Ende ist näher am nächsten GPX-Punkt?
            const distToStart = haversineDistance(nextPoint.lat, nextPoint.lon, segStart[1], segStart[0]);
            const distToEnd = haversineDistance(nextPoint.lat, nextPoint.lon, segEnd[1], segEnd[0]);

            // Der Exit-Node ist der, der näher am nächsten GPX-Punkt ist
            // Normalerweise: fromNode = Start, toNode = Ende
            return (distToEnd < distToStart) ? toNode : fromNode;
        }

        // Präzise Distanzberechnung wie im Hausnummern-Script mit OpenLayers
        function getDistanceToSegmentPrecise(point, segment) {
            try {
                // Versuche OpenLayers distanceTo für präzise Berechnung
                if (uOpenLayers?.Geometry?.Point && typeof segment.getOLGeometry === 'function') {
                    // GPX-Punkt zu Web Mercator konvertieren
                    const mercX = point.lon * 20037508.34 / 180;
                    const mercY = Math.log(Math.tan((90 + point.lat) * Math.PI / 360)) / (Math.PI / 180) * 20037508.34 / 180;

                    const olPoint = new uOpenLayers.Geometry.Point(mercX, mercY);
                    const segOLGeom = segment.getOLGeometry();

                    if (segOLGeom) {
                        const distResult = olPoint.distanceTo(segOLGeom, { details: true });
                        if (distResult && distResult.x1 !== undefined && distResult.y1 !== undefined) {
                            // Konvertiere zurück zu WGS84 für Haversine-Distanz
                            const closestLon = distResult.x1 * 180 / 20037508.34;
                            let closestLat = distResult.y1 * 180 / 20037508.34;
                            closestLat = 180 / Math.PI * (2 * Math.atan(Math.exp(closestLat * Math.PI / 180)) - Math.PI / 2);

                            return haversineDistance(point.lat, point.lon, closestLat, closestLon);
                        }
                    }
                }
            } catch (e) {
                // Fallback auf manuelle Berechnung
            }

            // Fallback: Manuelle WGS84 Distanzberechnung
            return getDistanceToSegmentFast(point, segment);
        }

        // Berechne Bearing zwischen zwei Punkten
        function calculateBearing(lat1, lon1, lat2, lon2) {
            const dLon = (lon2 - lon1) * Math.PI / 180;
            const lat1Rad = lat1 * Math.PI / 180;
            const lat2Rad = lat2 * Math.PI / 180;

            const y = Math.sin(dLon) * Math.cos(lat2Rad);
            const x = Math.cos(lat1Rad) * Math.sin(lat2Rad) - Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(dLon);

            let bearing = Math.atan2(y, x) * 180 / Math.PI;
            return (bearing + 360) % 360; // Normalisiere zu 0-360°
        }

        // Berechne Bearing eines Segments
        function getSegmentBearing(segment) {
            const segCoords = getSegmentCoordsWGS84(segment);
            if (!segCoords || segCoords.length < 2) return null;

            const start = segCoords[0];
            const end = segCoords[segCoords.length - 1];

            return calculateBearing(start[1], start[0], end[1], end[0]);
        }

        // Schnelle Distanzberechnung (Fallback)
        function getDistanceToSegmentFast(point, seg) {
            const segCoords = getSegmentCoordsWGS84(seg);
            if (!segCoords || segCoords.length < 2) return Infinity;

            let minDist = Infinity;
            for (let j = 0; j < segCoords.length - 1; j++) {
                const d = pointToSegmentHaversine(
                    point.lon, point.lat,
                    segCoords[j][0], segCoords[j][1],
                    segCoords[j+1][0], segCoords[j+1][1]
                );
                if (d < minDist) minDist = d;
            }
            return minDist;
        }

        // Haversine Distanz in Metern
        function haversineDistance(lat1, lon1, lat2, lon2) {
            const R = 6371000; // Erdradius in Metern
            const dLat = (lat2 - lat1) * Math.PI / 180;
            const dLon = (lon2 - lon1) * Math.PI / 180;
            const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                      Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
                      Math.sin(dLon/2) * Math.sin(dLon/2);
            return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
        }

        // Punkt-zu-Segment Distanz mit Haversine (wie im Hausnummern-Script)
        function pointToSegmentHaversine(px, py, ax, ay, bx, by) {
            const dx = bx - ax;
            const dy = by - ay;
            const lengthSq = dx * dx + dy * dy;

            let t = 0;
            if (lengthSq > 0) {
                t = Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / lengthSq));
            }

            const projX = ax + t * dx;
            const projY = ay + t * dy;

            return haversineDistance(py, px, projY, projX);
        }

        // Einfache Distanzberechnung: Punkt zu Liniensegment in Metern
        function distPointToSegment(px, py, x1, y1, x2, y2) {
            const dx = x2 - x1;
            const dy = y2 - y1;
            const lenSq = dx * dx + dy * dy;

            let t = 0;
            if (lenSq > 0) {
                t = ((px - x1) * dx + (py - y1) * dy) / lenSq;
                t = Math.max(0, Math.min(1, t));
            }

            const nearestX = x1 + t * dx;
            const nearestY = y1 + t * dy;

            // Haversine-ähnliche Distanz in Metern
            const dLon = (px - nearestX) * 111320 * Math.cos(py * Math.PI / 180);
            const dLat = (py - nearestY) * 110540;

            return Math.sqrt(dLon * dLon + dLat * dLat);
        }

        function matchGpxToSegments(gpxPoints) {
            if (!uWaze?.model?.segments) {
                updateStatusMessage('Keine Segmente verfügbar', '#f44336');
                return;
            }

            const segments = uWaze.model.segments.getObjectArray();
            log(`GPX Matching: ${gpxPoints.length} Punkte, ${segments.length} Segmente verfügbar`);

            if (segments.length === 0) {
                updateStatusMessage('Keine Segmente geladen - bitte näher zoomen', '#f44336');
                return;
            }

            // Verwende die verbesserte lokale Matching-Funktion
            const matchedSegments = matchGpxToSegmentsLocal(gpxPoints);

            log(`GPX: ${matchedSegments.length} Segmente gematcht`);

            if (matchedSegments.length === 0) {
                updateStatusMessage(t('gpxNoSegments') + ` (${gpxPoints.length} Punkte)`, '#ff9800');
                return;
            }

            const segmentArray = matchedSegments;
            uWaze.selectionManager.setSelectedModels(segmentArray);

            updateStatusMessage(t('importedGpx', matchedSegments.size), '#4CAF50');
        }

        // Winkel auf -180 bis 180 normalisieren
        function normalizeAngle(angle) {
            while (angle > 180) angle -= 360;
            while (angle < -180) angle += 360;
            return angle;
        }

        // Segment-Koordinaten in WGS84 extrahieren
        function getSegmentCoordsWGS84(segment) {
            const geom = segment.getOLGeometry?.() || segment.geometry || segment.attributes?.geometry;
            if (!geom) return null;

            const toWGS84 = (x, y) => {
                if (Math.abs(x) <= 180 && Math.abs(y) <= 90) return [x, y];
                const lon = x * 180 / 20037508.34;
                let lat = y * 180 / 20037508.34;
                lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
                return [lon, lat];
            };

            let coords = [];

            if (geom.components && geom.components.length > 0) {
                coords = geom.components.map(c => toWGS84(c.x, c.y));
            } else if (geom.getVertices) {
                coords = geom.getVertices().map(v => toWGS84(v.x, v.y));
            } else if (geom.coordinates && Array.isArray(geom.coordinates)) {
                if (Array.isArray(geom.coordinates[0])) {
                    coords = geom.coordinates.map(c => [c[0], c[1]]);
                }
            }

            return coords.length >= 2 ? coords : null;
        }

        // Robuste Distanz-Berechnung zu einem Segment
        function getDistanceToSegment(pointLon, pointLat, segment) {
            // Methode 1: OpenLayers distanceTo (präziseste Methode)
            try {
                // GPX-Punkt zu Web Mercator konvertieren
                const mercX = pointLon * 20037508.34 / 180;
                const mercY = Math.log(Math.tan((90 + pointLat) * Math.PI / 360)) / (Math.PI / 180) * 20037508.34 / 180;

                if (uOpenLayers?.Geometry?.Point) {
                    const olPoint = new uOpenLayers.Geometry.Point(mercX, mercY);
                    const segGeom = segment.getOLGeometry?.();

                    if (segGeom && olPoint.distanceTo) {
                        const distResult = olPoint.distanceTo(segGeom, { details: true });

                        if (distResult && distResult.x1 !== undefined) {
                            // Nächster Punkt auf Segment (Web Mercator)
                            const closestLon = distResult.x1 * 180 / 20037508.34;
                            let closestLat = distResult.y1 * 180 / 20037508.34;
                            closestLat = 180 / Math.PI * (2 * Math.atan(Math.exp(closestLat * Math.PI / 180)) - Math.PI / 2);

                            // Haversine Distanz
                            return haversineDistance(pointLat, pointLon, closestLat, closestLon);
                        }
                    }
                }
            } catch (e) {
                // Fallback verwenden
            }

            // Methode 2: Manuelle Berechnung
            return manualDistanceToSegment(pointLon, pointLat, segment);
        }

        // Manuelle Distanz-Berechnung als Fallback
        function manualDistanceToSegment(pointLon, pointLat, segment) {
            // Segment-Koordinaten extrahieren
            let coords = [];

            // Versuche verschiedene Wege die Geometrie zu bekommen
            const geom = segment.getOLGeometry?.() || segment.geometry || segment.attributes?.geometry;

            if (!geom) return Infinity;

            // Web Mercator zu WGS84
            const toWGS84 = (x, y) => {
                // Prüfe ob bereits WGS84 (kleine Zahlen)
                if (Math.abs(x) <= 180 && Math.abs(y) <= 90) {
                    return [x, y];
                }
                // Web Mercator konvertieren
                const lon = x * 180 / 20037508.34;
                let lat = y * 180 / 20037508.34;
                lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
                return [lon, lat];
            };

            // Koordinaten aus verschiedenen Formaten extrahieren
            if (geom.components && geom.components.length > 0) {
                // OpenLayers LineString
                coords = geom.components.map(c => toWGS84(c.x, c.y));
            } else if (geom.getVertices) {
                // OpenLayers mit getVertices
                const verts = geom.getVertices();
                coords = verts.map(v => toWGS84(v.x, v.y));
            } else if (geom.coordinates && Array.isArray(geom.coordinates)) {
                // GeoJSON Format
                if (Array.isArray(geom.coordinates[0])) {
                    // [[lon, lat], [lon, lat], ...]
                    coords = geom.coordinates.map(c => [c[0], c[1]]);
                }
            }

            if (coords.length < 2) return Infinity;

            // Minimale Distanz zu allen Liniensegmenten
            let minDist = Infinity;

            for (let i = 0; i < coords.length - 1; i++) {
                const dist = pointToLineDistance(
                    pointLon, pointLat,
                    coords[i][0], coords[i][1],
                    coords[i+1][0], coords[i+1][1]
                );
                if (dist < minDist) minDist = dist;
            }

            return minDist;
        }

        // Punkt-zu-Linie Distanz (WGS84 Koordinaten, Ergebnis in Metern)
        function pointToLineDistance(px, py, ax, ay, bx, by) {
            // Projektion des Punktes auf die Linie
            const dx = bx - ax;
            const dy = by - ay;
            const lengthSq = dx * dx + dy * dy;

            let t = 0;
            if (lengthSq > 0) {
                t = Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / lengthSq));
            }

            const projX = ax + t * dx;
            const projY = ay + t * dy;

            return haversineDistance(py, px, projY, projX);
        }

        // Haversine Distanz in Metern
        function haversineDistance(lat1, lon1, lat2, lon2) {
            const R = 6371000; // Erdradius in Metern
            const dLat = (lat2 - lat1) * Math.PI / 180;
            const dLon = (lon2 - lon1) * Math.PI / 180;
            const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                      Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
                      Math.sin(dLon/2) * Math.sin(dLon/2);
            return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
        }

        function deleteRtcsInCircles() {
            if (!radiusLayer || !radiusLayer.features || radiusLayer.features.length === 0) {
                updateStatusMessage('Erst einen Kreis zeichnen', '#ff9800');
                return;
            }

            updateStatusMessage(t('deletingRtcs'), '#2196F3');
            log('Suche RTCs im markierten Bereich...');

            const segments = uWaze.model.segments.getObjectArray();
            const segmentsInCircle = [];

            // Finde alle Segmente im Kreis
            for (const segment of segments) {
                if (!segment.attributes?.roadType) continue;

                const segGeom = segment.getOLGeometry ? segment.getOLGeometry() : segment.geometry;
                if (!segGeom) continue;

                for (const drawnFeature of radiusLayer.features) {
                    if (drawnFeature.geometry.intersects(segGeom)) {
                        segmentsInCircle.push(segment);
                        break;
                    }
                }
            }

            if (segmentsInCircle.length === 0) {
                updateStatusMessage(t('noRtcsFound'), '#ff9800');
                return;
            }

            log(`${segmentsInCircle.length} Segmente im Bereich gefunden`);

            // Finde alle RTCs auf diesen Segmenten
            const closuresToDelete = [];
            const segmentIds = new Set(segmentsInCircle.map(s => s.getID()));
            const now = Date.now();

            // Hole alle Closures aus dem Model
            if (W.model.roadClosures) {
                const allClosures = W.model.roadClosures.getObjectArray();
                log(`Prüfe ${allClosures.length} Closures insgesamt...`);

                for (const closure of allClosures) {
                    if (closure.attributes && segmentIds.has(closure.attributes.segID)) {
                        // Debug: Zeige Closure-Daten
                        const attrs = closure.attributes;
                        log(`Closure auf Segment ${attrs.segID}: Start=${attrs.startDate}, Ende=${attrs.endDate}`);

                        // Nur aktive/zukünftige RTCs (nicht abgelaufene)
                        // endDate kann ein String oder Timestamp sein
                        let endTime;
                        if (attrs.endDate) {
                            endTime = typeof attrs.endDate === 'number' ? attrs.endDate : new Date(attrs.endDate).getTime();
                        }

                        if (!endTime || endTime > now) {
                            closuresToDelete.push(closure);
                            log(`  → Wird gelöscht (aktiv/zukünftig)`);
                        } else {
                            log(`  → Übersprungen (abgelaufen, Ende war ${new Date(endTime).toLocaleString()})`);
                        }
                    }
                }
            }

            if (closuresToDelete.length === 0) {
                updateStatusMessage(t('noRtcsFound'), '#ff9800');
                return;
            }

            log(`${closuresToDelete.length} RTCs zum Löschen gefunden`);

            // Prüfe ob WMEAC verfügbar ist
            if (typeof WMEAC !== 'undefined' && WMEAC.removeClosure) {
                log('Using WMEAC.removeClosure...');
                WMEAC.removeClosure(closuresToDelete,
                    () => {
                        log(`✓ ${closuresToDelete.length} RTCs gelöscht`);
                        updateStatusMessage(t('rtcsDeleted', closuresToDelete.length), '#4CAF50');
                    },
                    (err) => {
                        warn('WMEAC Lösch-Fehler:', err);
                        updateStatusMessage('Fehler beim Löschen', '#f44336');
                    }
                );
                return;
            }

            // Fallback: RTCs einzeln löschen um Fehler bei abgelaufenen zu umgehen
            try {
                const cab = require("Waze/Modules/Closures/Models/ClosureActionBuilder");
                const sc = require("Waze/Modules/Closures/Models/SharedClosure");

                let deletedCount = 0;
                let errorCount = 0;
                let currentIndex = 0;

                const deleteNext = () => {
                    if (currentIndex >= closuresToDelete.length) {
                        // Fertig
                        if (deletedCount > 0) {
                            updateStatusMessage(t('rtcsDeleted', deletedCount) + (errorCount > 0 ? ` (${errorCount} Fehler)` : ''), deletedCount > 0 ? '#4CAF50' : '#ff9800');
                        } else {
                            updateStatusMessage('Keine RTCs gelöscht (alle abgelaufen?)', '#ff9800');
                        }
                        return;
                    }

                    const closure = closuresToDelete[currentIndex];
                    currentIndex++;

                    const seg = W.model.segments.getObjectById(closure.attributes.segID);
                    if (!seg) {
                        errorCount++;
                        deleteNext();
                        return;
                    }

                    W.selectionManager.setSelectedModels([seg]);

                    const sclo = new sc(
                        {
                            segments: [seg],
                            closures: [closure],
                            reverseSegments: {}
                        },
                        {
                            dataModel: W.model,
                            segmentSelection: W.selectionManager.getSegmentSelection(),
                            isNew: true
                        }
                    );

                    const action = cab.delete(W.model, sclo);

                    W.controller.save({ actions: [action] }).then(() => {
                        deletedCount++;
                        log(`✓ RTC ${currentIndex}/${closuresToDelete.length} gelöscht`);
                        updateStatusMessage(`Lösche RTCs... ${currentIndex}/${closuresToDelete.length}`, '#2196F3');
                        deleteNext();
                    }).catch((err) => {
                        // Bei Fehler (z.B. abgelaufen) weitermachen
                        errorCount++;
                        log(`✗ RTC ${currentIndex} Fehler: ${err.errors?.[0]?.attributes?.details || err.message}`);
                        deleteNext();
                    });
                };

                // Starte das Löschen
                updateStatusMessage(`Lösche RTCs... 0/${closuresToDelete.length}`, '#2196F3');
                deleteNext();

            } catch (e) {
                warn('Fehler beim RTC-Löschen:', e);
                updateStatusMessage('Fehler: ' + e.message, '#f44336');
            }
        }

        function shouldBlockSegmentInbound(segment, segGeom, circleCenter, radius) {
            try {
                const coords = segGeom.components || segGeom.getVertices?.();

                if (!coords?.length || coords.length < 2) {
                    warn(`Invalid coordinates for segment ${segment.getID()}`);
                    return false;
                }

                // Punkt A (Start) und Punkt B (Ende) des Segments
                const startPoint = coords[0];
                const endPoint = coords[coords.length - 1];

                if (!startPoint?.x || !endPoint?.x || !circleCenter?.x) {
                    warn(`Invalid point data for segment ${segment.getID()}`);
                    return false;
                }

                // Distanz von A und B zum Kreismittelpunkt berechnen
                const startDist = Math.hypot(
                    startPoint.x - circleCenter.x,
                    startPoint.y - circleCenter.y
                );
                const endDist = Math.hypot(
                    endPoint.x - circleCenter.x,
                    endPoint.y - circleCenter.y
                );

                // Toleranz für Randberührung (5% des Radius)
                const tolerance = radius * 0.05;

                // Prüfe ob Punkte innen oder außen sind
                const startInside = startDist < (radius - tolerance);
                const endInside = endDist < (radius - tolerance);
                const startOnEdge = Math.abs(startDist - radius) <= tolerance;
                const endOnEdge = Math.abs(endDist - radius) <= tolerance;

                let blockDirection;

                if (startInside && !endInside) {
                    // A ist innen, B ist außen → Einfahrt ist B→A, also B→A sperren
                    blockDirection = 'B→A';
                } else if (!startInside && endInside) {
                    // A ist außen, B ist innen → Einfahrt ist A→B, also A→B sperren
                    blockDirection = 'A→B';
                } else if (startOnEdge || endOnEdge) {
                    // Mindestens ein Punkt liegt auf dem Rand
                    // Der Punkt der weiter vom Zentrum entfernt ist, ist die "Außenseite"
                    if (startDist > endDist) {
                        // A ist weiter außen → Einfahrt von A-Seite → A→B sperren
                        blockDirection = 'A→B';
                    } else {
                        // B ist weiter außen → Einfahrt von B-Seite → B→A sperren
                        blockDirection = 'B→A';
                    }
                } else if (!startInside && !endInside) {
                    // Beide außen aber Segment kreuzt den Kreis
                    // Der Punkt der näher am Zentrum ist, ist die "Einfahrtsseite"
                    if (startDist < endDist) {
                        // A ist näher am Zentrum → Einfahrt von A-Seite → B→A sperren
                        blockDirection = 'B→A';
                    } else {
                        // B ist näher am Zentrum → Einfahrt von B-Seite → A→B sperren
                        blockDirection = 'A→B';
                    }
                } else {
                    // Beide klar innen - sollte nicht als Perimeter-Segment erkannt werden
                    // Aber wir behandeln es trotzdem: der weiter außen liegende Punkt bestimmt die Richtung
                    if (startDist > endDist) {
                        blockDirection = 'A→B';
                    } else {
                        blockDirection = 'B→A';
                    }
                    log(`Segment ${segment.getID()}: Beide Punkte nah am Rand, verwende Distanz-Logik → ${blockDirection}`);
                }

                // Richtungsinfo speichern für spätere Verwendung
                segment._circleDirectionInfo = {
                    startPoint, endPoint, startDist, endDist, circleCenter,
                    blockDirection: blockDirection
                };

                log(`Segment ${segment.getID()}: A-Dist=${Math.round(startDist)}m, B-Dist=${Math.round(endDist)}m → Sperre ${blockDirection}`);

                return true;
            } catch (error) {
                warn(`Error in shouldBlockSegmentInbound for segment ${segment.getID()}:`, error);
                return false;
            }
        }

        function applyDirectionRestrictions(segments) {
            log(`=== Perimeter-Sperrung: ${segments.length} Segmente ===`);

            // Segmente selektieren
            uWaze.selectionManager.setSelectedModels(segments);

            // Modus prüfen: Dauer oder Enddatum
            const useDuration = document.querySelector('#rtc-mode-duration')?.checked !== false;

            const now = new Date();
            let end;

            if (useDuration) {
                // Dauer aus UI lesen
                const durationDays = parseInt(document.querySelector('#rtc-duration-days')?.value) || 0;
                const durationHours = parseInt(document.querySelector('#rtc-duration-hours')?.value) || 24;
                const durationMinutes = parseInt(document.querySelector('#rtc-duration-minutes')?.value) || 0;
                const totalMinutes = (durationDays * 24 * 60) + (durationHours * 60) + durationMinutes;

                if (totalMinutes <= 0) {
                    updateStatusMessage('Bitte Dauer eingeben', '#ff9800');
                    return;
                }

                end = new Date(now.getTime() + totalMinutes * 60 * 1000);
                log(`RTC Dauer: ${durationDays}d ${durationHours}h ${durationMinutes}m`);
            } else {
                // Enddatum aus UI lesen
                const endDateStr = document.querySelector('#rtc-end-date')?.value;
                const endTimeStr = document.querySelector('#rtc-end-time')?.value || '23:59';

                if (!endDateStr) {
                    updateStatusMessage('Bitte Enddatum eingeben', '#ff9800');
                    return;
                }

                end = new Date(`${endDateStr}T${endTimeStr}`);

                if (end <= now) {
                    updateStatusMessage('Enddatum muss in der Zukunft liegen', '#ff9800');
                    return;
                }

                log(`RTC Enddatum: ${endDateStr} ${endTimeStr}`);
            }

            const formatDate = (d) => {
                const pad = (n) => ('0' + n).slice(-2);
                return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
            };
            const startStr = formatDate(now);
            const endStr = formatDate(end);

            log(`Start: ${startStr}, Ende: ${endStr}`);

            // Segmente nach Richtung gruppieren
            const segmentsAtoB = [];
            const segmentsBtoA = [];

            for (const segment of segments) {
                try {
                    const dirInfo = segment._circleDirectionInfo;
                    if (!dirInfo) {
                        warn(`Segment ${segment.getID()}: Keine Richtungsinfo`);
                        continue;
                    }

                    if (dirInfo.blockDirection === 'A→B') {
                        // A→B sperren (direction = A_TO_B = 1)
                        segmentsAtoB.push(segment);
                        log(`✓ Segment ${segment.getID()}: RTC sperrt A→B`);
                    } else {
                        // B→A sperren (direction = B_TO_A = 2)
                        segmentsBtoA.push(segment);
                        log(`✓ Segment ${segment.getID()}: RTC sperrt B→A`);
                    }

                    delete segment._circleDirectionInfo;

                } catch (error) {
                    warn('Error:', error);
                }
            }

            // Closures über WME Action System erstellen
            try {
                // Prüfe ob WMEAC (Advanced Closures) verfügbar ist
                if (typeof WMEAC !== 'undefined' && WMEAC.addClosure) {
                    log('Using WMEAC.addClosure...');

                    const allSegs = [...segmentsAtoB, ...segmentsBtoA];
                    W.selectionManager.setSelectedModels(allSegs);

                    let successCount = 0;
                    let errorCount = 0;
                    const totalExpected = (segmentsAtoB.length > 0 ? 1 : 0) + (segmentsBtoA.length > 0 ? 1 : 0);

                    const checkDone = () => {
                        if (successCount + errorCount >= totalExpected) {
                            if (successCount > 0) {
                                updateStatusMessage(`✓ RTCs erstellt`, '#4CAF50');
                            } else {
                                updateStatusMessage(`Fehler beim Erstellen`, '#f44336');
                            }
                        }
                    };

                    if (segmentsAtoB.length > 0) {
                        W.selectionManager.setSelectedModels(segmentsAtoB);
                        WMEAC.addClosure({
                            segments: segmentsAtoB,
                            reason: "Perimeter-Sperrung",
                            direction: 1,
                            startDate: startStr,
                            endDate: endStr,
                            location: "",
                            permanent: false
                        }, () => { successCount++; checkDone(); }, (err) => { warn('A→B Error:', err); errorCount++; checkDone(); });
                    }

                    if (segmentsBtoA.length > 0) {
                        setTimeout(() => {
                            W.selectionManager.setSelectedModels(segmentsBtoA);
                            WMEAC.addClosure({
                                segments: segmentsBtoA,
                                reason: "Perimeter-Sperrung",
                                direction: 2,
                                startDate: startStr,
                                endDate: endStr,
                                location: "",
                                permanent: false
                            }, () => { successCount++; checkDone(); }, (err) => { warn('B→A Error:', err); errorCount++; checkDone(); });
                        }, 1000);
                    }

                    return;
                }

                // Fallback: Eigene Implementation
                log('WMEAC not available, using internal implementation...');

                const cab = require("Waze/Modules/Closures/Models/ClosureActionBuilder");
                const sc = require("Waze/Modules/Closures/Models/SharedClosure");

                if (segmentsAtoB.length === 0 && segmentsBtoA.length === 0) {
                    updateStatusMessage('Keine RTCs erstellt', '#ff9800');
                    return;
                }

                const createClosureForSegments = (segs, direction) => {
                    if (segs.length === 0) return null;

                    log(`Creating closure for ${segs.length} segments, direction=${direction}`);
                    log(`Segment IDs: ${segs.map(s => s.getID()).join(', ')}`);

                    // Segmente für diese Richtung selektieren
                    W.selectionManager.setSelectedModels(segs);

                    const closureDetails = {
                        closures: [],
                        attributions: [],
                        reason: "Perimeter-Sperrung" + String.fromCharCode(160),
                        direction: direction,
                        startDate: startStr,
                        endDate: endStr,
                        location: "",
                        permanent: false,
                        segments: segs,
                        closuresType: 'roadClosure',
                        reverseSegments: {}
                    };

                    log(`Closure details:`, JSON.stringify({
                        reason: closureDetails.reason,
                        direction: closureDetails.direction,
                        startDate: closureDetails.startDate,
                        endDate: closureDetails.endDate,
                        segmentCount: closureDetails.segments.length
                    }));

                    const closure = new sc(closureDetails, {
                        dataModel: W.model,
                        segmentSelection: W.selectionManager.getSegmentSelection(),
                        isNewClosure: true,
                        closedNodesMap: {}
                    });

                    log(`Closure created, closureNodes: ${closure.closureNodes?.models?.length || 0}`);

                    // ClosureNodes setzen (wie in Advanced Closures)
                    if (closure.closureNodes?.models) {
                        for (const n of closure.closureNodes.models) {
                            n.attributes.isClosed = false;
                        }
                    }

                    return cab.add(closure, W.loginManager.user, W.model);
                };

                // Sequentiell speichern um Konflikte zu vermeiden
                const saveWithCallback = (segs, direction, dirName, onSuccess, onError) => {
                    if (segs.length === 0) {
                        onSuccess(0);
                        return;
                    }

                    const action = createClosureForSegments(segs, direction);
                    if (!action) {
                        onSuccess(0);
                        return;
                    }

                    const t = { actions: [action] };

                    W.controller.save(t).then(function() {
                        log(`✓ ${segs.length} ${dirName} RTCs gespeichert`);
                        onSuccess(segs.length);
                    }).catch(function(err) {
                        warn(`${dirName} Save Error:`, err);
                        let errorDetails = '';
                        if (err.errors) {
                            err.errors.forEach(e => {
                                warn(`Error details:`, JSON.stringify(e.attributes || e));
                                if (e.attributes?.details) {
                                    errorDetails = e.attributes.details;
                                }
                            });
                        }

                        // Spezifische Fehlermeldung für überlappende RTCs
                        if (errorDetails.includes('overlapped')) {
                            err.userMessage = 'RTC existiert bereits für diesen Zeitraum! Bitte erst bestehende RTCs löschen.';
                        }

                        onError(err);
                    });
                };

                // Erst A→B, dann B→A
                saveWithCallback(segmentsAtoB, 1, 'A→B',
                    function(countA) {
                        // A→B erfolgreich, jetzt B→A
                        saveWithCallback(segmentsBtoA, 2, 'B→A',
                            function(countB) {
                                const total = countA + countB;
                                if (total > 0) {
                                    updateStatusMessage(`✓ ${total} RTCs erstellt`, '#4CAF50');
                                } else {
                                    updateStatusMessage('Keine RTCs erstellt', '#ff9800');
                                }
                            },
                            function(err) {
                                // B→A fehlgeschlagen, aber A→B war erfolgreich
                                if (countA > 0) {
                                    updateStatusMessage(`⚠ ${countA} RTCs erstellt, B→A fehlgeschlagen`, '#ff9800');
                                } else {
                                    let details = '';
                                    if (err.errors) {
                                        err.errors.forEach(e => {
                                            if (e.attributes?.details) details += e.attributes.details + ' ';
                                        });
                                    }
                                    updateStatusMessage(`Fehler: ${details || err.message || 'Unbekannt'}`, '#f44336');
                                }
                            }
                        );
                    },
                    function(err) {
                        // A→B fehlgeschlagen
                        let details = err.userMessage || '';
                        if (!details && err.errors) {
                            err.errors.forEach(e => {
                                if (e.attributes?.details) details += e.attributes.details + ' ';
                            });
                        }
                        updateStatusMessage(`Fehler: ${details || err.message || 'Unbekannt'}`, '#f44336');
                    }
                );

            } catch (e) {
                warn('Action System Fehler:', e);
                updateStatusMessage('Action System nicht verfügbar', '#f44336');
            }
        }

        function undoLastCircle() {
            try {
                // 1. Prüfe ob Brush-Modus aktiv und History vorhanden
                if (brushModeActive && brushHistory && brushHistory.length > 0) {
                    if (undoBrushSelection()) {
                        return;
                    }
                }

                // 2. Prüfe ob es Kreise zum Entfernen gibt
                if (radiusLayer && radiusLayer.features && radiusLayer.features.length > 0) {
                    const lastFeature = radiusLayer.features[radiusLayer.features.length - 1];

                    if (lastFeature) {
                        radiusLayer.removeFeatures([lastFeature]);

                        if (radiusLayer.redraw) radiusLayer.redraw();

                        updateAllAnnotations();

                        const remaining = radiusLayer.features.length;
                        updateStatusMessage(`✓ ${t('removedCircle')} (${remaining} ${t('remaining')})`, '#2196F3');
                        return;
                    }
                }

                // 3. Keine Kreise - versuche WME Undo
                if (W.controller && W.controller.undo) {
                    W.controller.undo();
                    updateStatusMessage('↩️ WME', '#2196F3');
                } else if (W.model && W.model.actionManager) {
                    W.model.actionManager.undo();
                    updateStatusMessage('↩️ WME', '#2196F3');
                } else {
                    updateStatusMessage(t('noCirclesToUndo'), '#ff9800');
                }
            } catch (error) {
                warn('Error undoing:', error);
                updateStatusMessage(t('errorRemoving'), '#f44336');
            }
        }

        function clearAllCircles() {
            try {
                // Deactivate controls first
                if (polygonControl) polygonControl.deactivate();
                if (freehandControl) freehandControl.deactivate();
                if (dragControl) dragControl.deactivate();

                // Clear checkboxes
                if (checkbox) checkbox.checked = false;
                if (freehandCheckbox) freehandCheckbox.checked = false;
                if (moveCheckbox) moveCheckbox.checked = false;

                // Remove features one by one (more reliable than destroyFeatures)
                if (infoLayer && infoLayer.features) {
                    const infoFeatures = [...infoLayer.features];
                    infoFeatures.forEach(f => {
                        try {
                            infoLayer.removeFeatures([f]);
                        } catch (e) {
                            log('Error removing info feature');
                        }
                    });
                }

                if (radiusLayer && radiusLayer.features) {
                    const radiusFeatures = [...radiusLayer.features];
                    radiusFeatures.forEach(f => {
                        try {
                            radiusLayer.removeFeatures([f]);
                        } catch (e) {
                            log('Error removing radius feature');
                        }
                    });
                }

                // Force redraw
                if (infoLayer && infoLayer.redraw) infoLayer.redraw();
                if (radiusLayer && radiusLayer.redraw) radiusLayer.redraw();

            } catch (error) {
                warn('Error clearing circles:', error);
            }
        }
    }

    function radiusInit() {
        radiusLayer = new uOpenLayers.Layer.Vector("WME Circle Control Layer", {
            displayInLayerSwitcher: true,
            uniqueName: "__CircleControlLayer",
            visibility: true,
            style: {
                "fillColor": "#c40606",
                "fillOpacity": 0.2,
                "strokeColor": "#c40606",
                "strokeOpacity": 1,
                "strokeWidth": 1,
                "strokeLinecap": "round",
                "strokeDashstyle": "solid",
                "pointRadius": 6,
                "pointerEvents": "visiblePainted",
                "labelAlign": "cm",
                "labelOutlineColor": "white",
                "labelOutlineWidth": 3
            }
        });

        infoLayer = new uOpenLayers.Layer.Vector("WME Circle Visual Layer", {
            displayInLayerSwitcher: true,
            uniqueName: "__DrawCircleDisplayLayer",
            visibility: true
        });

        let polygonHandler = uOpenLayers.Handler.RegularPolygon;
        polygonControl = new uOpenLayers.Control.DrawFeature(radiusLayer, polygonHandler, {
            handlerOptions: {
                sides: 100
            }
        });

        let polygonHandlerFreehand = uOpenLayers.Handler.Polygon;
        freehandControl = new uOpenLayers.Control.DrawFeature(radiusLayer, polygonHandlerFreehand, {
            handlerOptions: {
                freehand: true,
                freehandToggle: null
            }
        });

        // Drag control is created in setupSidebarContent via setupDragControl()

        uWaze.map.addLayer(radiusLayer);
        uWaze.map.addLayer(infoLayer);
        uWaze.map.addControl(polygonControl);
        uWaze.map.addControl(freehandControl);
        // dragControl is added via setupDragControl() in setupSidebarContent

        addSidePanel();

        polygonControl.handler.callbacks.move = function (e) {
            let linearRing = new uOpenLayers.Geometry.LinearRing(e.components[0].components);
            let geometry = new uOpenLayers.Geometry.Polygon([linearRing]);
            let polygonFeature = new uOpenLayers.Feature.Vector(geometry, null);
            let polybounds = polygonFeature.geometry.getBounds();
            let minX = polybounds.left;
            let minY = polybounds.bottom;
            let maxX = polybounds.right;
            let maxY = polybounds.top;
            let startX = (minX + maxX) / 2;
            let startY = (minY + maxY) / 2;
            let startPoint = new uOpenLayers.Geometry.Point(startX, startY);
            let endPoint = new uOpenLayers.Geometry.Point(maxX, startY);
            let radius = new uOpenLayers.Geometry.LineString([startPoint, endPoint]);
            let len = radius.getGeodesicLength(new uOpenLayers.Projection("EPSG:900913"));

            let unit = 'm';
            if (len > 1000) {
                len = Math.round((len / 1000) * 100) / 100;
                unit = "km";
            } else {
                len = Math.round(len);
            }

            let rad = document.getElementById('circles-current-radius');
            if (rad) {
                rad.innerHTML = 'Current Radius: ' + len + ' ' + unit;
            }

            infoLayer.destroyFeatures();

            let centerStyle = {
                strokeColor: "#ff9800",
                strokeWidth: 2,
                pointRadius: 3,
                fillOpacity: 0.3
            };

            let lineStyle = {
                strokeColor: "#ff9800",
                strokeWidth: 2,
                label: len + ' ' + unit,
                labelAlign: "left",
                labelXOffset: "15",
                labelYOffset: "5",
                labelOutlineColor: "white",
                labelOutlineWidth: 2,
                strokeDashstyle: "dash"
            };

            let center = new uOpenLayers.Feature.Vector(startPoint, {}, centerStyle);
            let radiusLine = new uOpenLayers.Feature.Vector(radius, {}, lineStyle);

            infoLayer.addFeatures([center, radiusLine]);
        }

        polygonControl.events.on({
            'featureadded': function (e) {
                let rad = document.getElementById('circles-current-radius');
                if (rad) {
                    rad.innerHTML = '';
                }
                setTimeout(() => {
                    const event = new CustomEvent('updateAnnotations');
                    document.dispatchEvent(event);
                }, 100);
            }
        });

        freehandControl.events.on({
            'featureadded': function (e) {
                let rad = document.getElementById('circles-current-radius');
                if (rad) {
                    rad.innerHTML = '';
                }
                setTimeout(() => {
                    const event = new CustomEvent('updateAnnotations');
                    document.dispatchEvent(event);
                }, 100);
            }
        });
    }

    if (W?.userscripts?.state?.isReady) {
        log('WME already ready, initializing...');
        initializeScript();
    } else {
        log('Waiting for WME ready event...');
        document.addEventListener("wme-ready", initializeScript, { once: true });
    }

})();