mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-21 06:26:26 +00:00
feat(tours): compare a tour's plan with the track it was actually done with (ACT-02)
Each actual track in a tour's detail now stands beside the plan instead of
on its own: a table names the plan and the actual track as columns, each with
the line it is drawn as on the map, and sets distance, ascent, descent and the
time with breaks side by side. The difference is shown, signed and with an
arrow, only where both values are known and mean the same thing; a planned
total that leaves a stay out reads "at least" and is not subtracted from. A
value one side does not carry is named as missing ("Not in the plan", "Not in
the track", "No time stamps"), never estimated. Below the table, how far the
track left the planned line: its farthest point and the recorded stretches
more than 50 m away, or that there is no line to compare.
On the desktop plan map, "Compare on map" draws the actual track dotted in
the colour of done next to the plan, which stays picked in its own track
colour (and is put back should it be hidden on the map). The recording leaves
the map as a tour of its own meanwhile, so it is never drawn twice or in a
plan's colour. A frosted legend over the map names both lines and ends the
comparison; so do closing the detail, comparing another track, or the track
being unlinked. Comparing only reads: neither the plan nor the track changes.
The track is laid into the day's route lines the map already draws, so both
renderers show it without a layer of their own. distancesToLine in the shared
route corridor measures many points against one line laid flat once; a long
recording is measured in at most 1500 samples.
This commit is contained in:
@@ -1246,5 +1246,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'لا يمكن ربط هذا المسار بهذه الجولة',
|
||||
'tours.activity.refused.activity_tour_is_track': 'هذه الجولة هي نفسها المسار الفعلي لجولة أخرى',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'لم تعد الجولة في ذلك اليوم',
|
||||
'tours.activity.compare.title': 'المخطط والفعلي',
|
||||
'tours.activity.compare.plan': 'المخطط',
|
||||
'tours.activity.compare.difference': 'الفرق',
|
||||
'tours.activity.compare.time': 'الوقت مع الاستراحات',
|
||||
'tours.activity.compare.notInPlan': 'غير موجود في المخطط',
|
||||
'tours.activity.compare.notInTrack': 'غير موجود في المسار',
|
||||
'tours.activity.compare.farthest': 'أبعد نقطة عن المخطط',
|
||||
'tours.activity.compare.offPlan': 'خارج المخطط',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent}٪)',
|
||||
'tours.activity.compare.offPlanHint': 'المقاطع المسجلة التي تبعد أكثر من {distance} عن الخط المخطط',
|
||||
'tours.activity.compare.noLine': 'لا يوجد خط للمقارنة',
|
||||
'tours.activity.compare.show': 'قارن على الخريطة',
|
||||
'tours.activity.compare.showHint': 'يرسم المسار الفعلي منقطًا بجانب المخطط. لا يتغير شيء.',
|
||||
'tours.activity.compare.hide': 'إنهاء المقارنة',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1214,5 +1214,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Bu iz bu tura bağlana bilməz',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Bu tur özü başqa turun faktiki izidir',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Tur artıq o gündə deyil',
|
||||
'tours.activity.compare.title': 'Plan və faktiki',
|
||||
'tours.activity.compare.plan': 'Planlaşdırılan',
|
||||
'tours.activity.compare.difference': 'Fərq',
|
||||
'tours.activity.compare.time': 'Fasilələrlə vaxt',
|
||||
'tours.activity.compare.notInPlan': 'Planda yoxdur',
|
||||
'tours.activity.compare.notInTrack': 'İzdə yoxdur',
|
||||
'tours.activity.compare.farthest': 'Plandan ən uzaq məsafə',
|
||||
'tours.activity.compare.offPlan': 'Plandan kənar',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Planlaşdırılmış xətdən {distance} artıq uzaqda olan qeydə alınmış hissələr',
|
||||
'tours.activity.compare.noLine': 'Müqayisə üçün xətt yoxdur',
|
||||
'tours.activity.compare.show': 'Xəritədə müqayisə et',
|
||||
'tours.activity.compare.showHint': 'Faktiki izi planın yanında nöqtəli çəkir. Heç nə dəyişmir.',
|
||||
'tours.activity.compare.hide': 'Müqayisəni bitir',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1226,5 +1226,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Esta trilha não pode ser vinculada a este passeio',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Este passeio é a trilha real de outro passeio',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'O passeio não está mais nesse dia',
|
||||
'tours.activity.compare.title': 'Plano e real',
|
||||
'tours.activity.compare.plan': 'Plano',
|
||||
'tours.activity.compare.difference': 'Diferença',
|
||||
'tours.activity.compare.time': 'Tempo com pausas',
|
||||
'tours.activity.compare.notInPlan': 'Não está no plano',
|
||||
'tours.activity.compare.notInTrack': 'Não está na trilha',
|
||||
'tours.activity.compare.farthest': 'Maior distância do plano',
|
||||
'tours.activity.compare.offPlan': 'Fora do plano',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Trechos gravados a mais de {distance} da linha planejada',
|
||||
'tours.activity.compare.noLine': 'Nenhuma linha para comparar',
|
||||
'tours.activity.compare.show': 'Comparar no mapa',
|
||||
'tours.activity.compare.showHint': 'Desenha a trilha real pontilhada ao lado do plano. Nada muda.',
|
||||
'tours.activity.compare.hide': 'Encerrar comparação',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1233,5 +1233,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Aquest traç no es pot vincular a aquesta ruta',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Aquesta ruta és alhora el traç real d’una altra ruta',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'La ruta ja no és en aquell dia',
|
||||
'tours.activity.compare.title': 'Pla i real',
|
||||
'tours.activity.compare.plan': 'Pla',
|
||||
'tours.activity.compare.difference': 'Diferència',
|
||||
'tours.activity.compare.time': 'Temps amb pauses',
|
||||
'tours.activity.compare.notInPlan': 'No és al pla',
|
||||
'tours.activity.compare.notInTrack': 'No és al traç',
|
||||
'tours.activity.compare.farthest': 'Distància màxima al pla',
|
||||
'tours.activity.compare.offPlan': 'Fora del pla',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Trams enregistrats a més de {distance} de la línia planificada',
|
||||
'tours.activity.compare.noLine': 'No hi ha cap línia per comparar',
|
||||
'tours.activity.compare.show': 'Compara al mapa',
|
||||
'tours.activity.compare.showHint': 'Dibuixa el traç real puntejat al costat del pla. No canvia res.',
|
||||
'tours.activity.compare.hide': 'Acaba la comparació',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1212,5 +1212,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Tuto trasu nelze propojit s touto túrou',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Tato túra je sama skutečnou trasou jiné túry',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Túra už v tento den není',
|
||||
'tours.activity.compare.title': 'Plán a skutečnost',
|
||||
'tours.activity.compare.plan': 'Plán',
|
||||
'tours.activity.compare.difference': 'Rozdíl',
|
||||
'tours.activity.compare.time': 'Čas s přestávkami',
|
||||
'tours.activity.compare.notInPlan': 'Není v plánu',
|
||||
'tours.activity.compare.notInTrack': 'Není v trase',
|
||||
'tours.activity.compare.farthest': 'Největší odchylka od plánu',
|
||||
'tours.activity.compare.offPlan': 'Mimo plán',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Zaznamenané úseky vzdálené od plánované linie více než {distance}',
|
||||
'tours.activity.compare.noLine': 'Žádná linie k porovnání',
|
||||
'tours.activity.compare.show': 'Porovnat na mapě',
|
||||
'tours.activity.compare.showHint': 'Vykreslí skutečnou trasu tečkovaně vedle plánu. Nic se nemění.',
|
||||
'tours.activity.compare.hide': 'Ukončit porovnání',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1239,6 +1239,21 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Dieser Track kann nicht mit dieser Tour verknüpft werden',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Diese Tour ist selbst der Ist-Track einer anderen Tour',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Die Tour ist nicht mehr an diesem Tag',
|
||||
'tours.activity.compare.title': 'Planung und Ist',
|
||||
'tours.activity.compare.plan': 'Planung',
|
||||
'tours.activity.compare.difference': 'Unterschied',
|
||||
'tours.activity.compare.time': 'Zeit mit Pausen',
|
||||
'tours.activity.compare.notInPlan': 'Nicht in der Planung',
|
||||
'tours.activity.compare.notInTrack': 'Nicht im Track',
|
||||
'tours.activity.compare.farthest': 'Größter Abstand zur Planung',
|
||||
'tours.activity.compare.offPlan': 'Abseits der Planung',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint':
|
||||
'Aufgezeichnete Abschnitte, die mehr als {distance} von der geplanten Linie entfernt liegen',
|
||||
'tours.activity.compare.noLine': 'Keine Linie zum Vergleichen',
|
||||
'tours.activity.compare.show': 'Auf der Karte vergleichen',
|
||||
'tours.activity.compare.showHint': 'Zeichnet den Ist-Track gepunktet neben die Planung. Es ändert sich nichts.',
|
||||
'tours.activity.compare.hide': 'Vergleich beenden',
|
||||
};
|
||||
|
||||
export default tours;
|
||||
|
||||
@@ -1201,5 +1201,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'This track cannot be linked to this tour',
|
||||
'tours.activity.refused.activity_tour_is_track': 'This tour is itself the actual track of another tour',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'The tour is no longer on that day',
|
||||
'tours.activity.compare.title': 'Plan and actual',
|
||||
'tours.activity.compare.plan': 'Plan',
|
||||
'tours.activity.compare.difference': 'Difference',
|
||||
'tours.activity.compare.time': 'Time with breaks',
|
||||
'tours.activity.compare.notInPlan': 'Not in the plan',
|
||||
'tours.activity.compare.notInTrack': 'Not in the track',
|
||||
'tours.activity.compare.farthest': 'Farthest from the plan',
|
||||
'tours.activity.compare.offPlan': 'Off the plan',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Recorded stretches more than {distance} away from the planned line',
|
||||
'tours.activity.compare.noLine': 'No line to compare',
|
||||
'tours.activity.compare.show': 'Compare on map',
|
||||
'tours.activity.compare.showHint': 'Draws the actual track dotted beside the plan. Nothing changes.',
|
||||
'tours.activity.compare.hide': 'End comparison',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1226,5 +1226,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Este track no se puede vincular a esta ruta',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Esta ruta es a su vez el track real de otra ruta',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'La ruta ya no está en ese día',
|
||||
'tours.activity.compare.title': 'Previsto y real',
|
||||
'tours.activity.compare.plan': 'Previsto',
|
||||
'tours.activity.compare.difference': 'Diferencia',
|
||||
'tours.activity.compare.time': 'Tiempo con pausas',
|
||||
'tours.activity.compare.notInPlan': 'No está en el plan',
|
||||
'tours.activity.compare.notInTrack': 'No está en el track',
|
||||
'tours.activity.compare.farthest': 'Máxima distancia al plan',
|
||||
'tours.activity.compare.offPlan': 'Fuera del plan',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Tramos grabados a más de {distance} de la línea planificada',
|
||||
'tours.activity.compare.noLine': 'No hay línea para comparar',
|
||||
'tours.activity.compare.show': 'Comparar en el mapa',
|
||||
'tours.activity.compare.showHint': 'Dibuja el track real punteado junto al plan. No cambia nada.',
|
||||
'tours.activity.compare.hide': 'Terminar la comparación',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1210,5 +1210,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Seda rada ei saa selle matkaga siduda',
|
||||
'tours.activity.refused.activity_tour_is_track': 'See matk on ise teise matka tegelik rada',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Matk pole enam sellel päeval',
|
||||
'tours.activity.compare.title': 'Plaan ja tegelik',
|
||||
'tours.activity.compare.plan': 'Plaan',
|
||||
'tours.activity.compare.difference': 'Erinevus',
|
||||
'tours.activity.compare.time': 'Aeg koos pausidega',
|
||||
'tours.activity.compare.notInPlan': 'Plaanis puudub',
|
||||
'tours.activity.compare.notInTrack': 'Rajal puudub',
|
||||
'tours.activity.compare.farthest': 'Suurim kaugus plaanist',
|
||||
'tours.activity.compare.offPlan': 'Plaanist kõrval',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Salvestatud lõigud, mis on planeeritud joonest kaugemal kui {distance}',
|
||||
'tours.activity.compare.noLine': 'Võrdlemiseks pole joont',
|
||||
'tours.activity.compare.show': 'Võrdle kaardil',
|
||||
'tours.activity.compare.showHint': 'Joonistab tegeliku raja plaani kõrvale punktiirina. Midagi ei muutu.',
|
||||
'tours.activity.compare.hide': 'Lõpeta võrdlus',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1250,5 +1250,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Cette trace ne peut pas être liée à cette sortie',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Cette sortie est elle-même la trace réelle d’une autre sortie',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'La sortie n’est plus prévue ce jour-là',
|
||||
'tours.activity.compare.title': 'Prévu et réel',
|
||||
'tours.activity.compare.plan': 'Prévu',
|
||||
'tours.activity.compare.difference': 'Écart',
|
||||
'tours.activity.compare.time': 'Temps avec pauses',
|
||||
'tours.activity.compare.notInPlan': 'Absent du plan',
|
||||
'tours.activity.compare.notInTrack': 'Absent de la trace',
|
||||
'tours.activity.compare.farthest': 'Écart maximal au plan',
|
||||
'tours.activity.compare.offPlan': 'Hors du plan',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Portions enregistrées à plus de {distance} de la ligne prévue',
|
||||
'tours.activity.compare.noLine': 'Aucune ligne à comparer',
|
||||
'tours.activity.compare.show': 'Comparer sur la carte',
|
||||
'tours.activity.compare.showHint': 'Dessine la trace réelle en pointillés à côté du plan. Rien ne change.',
|
||||
'tours.activity.compare.hide': 'Terminer la comparaison',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1251,5 +1251,21 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Αυτή η διαδρομή δεν μπορεί να συνδεθεί με αυτή την περιήγηση',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Αυτή η εκδρομή είναι η ίδια πραγματική διαδρομή άλλης εκδρομής',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Η εκδρομή δεν είναι πια σε εκείνη την ημέρα',
|
||||
'tours.activity.compare.title': 'Σχέδιο και πραγματικό',
|
||||
'tours.activity.compare.plan': 'Σχέδιο',
|
||||
'tours.activity.compare.difference': 'Διαφορά',
|
||||
'tours.activity.compare.time': 'Χρόνος με διαλείμματα',
|
||||
'tours.activity.compare.notInPlan': 'Δεν υπάρχει στο σχέδιο',
|
||||
'tours.activity.compare.notInTrack': 'Δεν υπάρχει στη διαδρομή',
|
||||
'tours.activity.compare.farthest': 'Μέγιστη απόσταση από το σχέδιο',
|
||||
'tours.activity.compare.offPlan': 'Εκτός σχεδίου',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint':
|
||||
'Καταγεγραμμένα τμήματα σε απόσταση άνω των {distance} από τη σχεδιασμένη γραμμή',
|
||||
'tours.activity.compare.noLine': 'Δεν υπάρχει γραμμή για σύγκριση',
|
||||
'tours.activity.compare.show': 'Σύγκριση στον χάρτη',
|
||||
'tours.activity.compare.showHint':
|
||||
'Σχεδιάζει την πραγματική διαδρομή με τελείες δίπλα στο σχέδιο. Τίποτα δεν αλλάζει.',
|
||||
'tours.activity.compare.hide': 'Τέλος σύγκρισης',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1230,5 +1230,20 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Ez a nyomvonal nem kapcsolható ehhez a túrához',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Ez a túra maga is egy másik túra tényleges nyomvonala',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'A túra már nem szerepel azon a napon',
|
||||
'tours.activity.compare.title': 'Terv és tényleges',
|
||||
'tours.activity.compare.plan': 'Terv',
|
||||
'tours.activity.compare.difference': 'Eltérés',
|
||||
'tours.activity.compare.time': 'Idő szünetekkel',
|
||||
'tours.activity.compare.notInPlan': 'Nincs a tervben',
|
||||
'tours.activity.compare.notInTrack': 'Nincs a nyomvonalban',
|
||||
'tours.activity.compare.farthest': 'Legnagyobb távolság a tervtől',
|
||||
'tours.activity.compare.offPlan': 'Terven kívül',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint':
|
||||
'Rögzített szakaszok, amelyek {distance} távolságnál messzebb vannak a tervezett vonaltól',
|
||||
'tours.activity.compare.noLine': 'Nincs összehasonlítható vonal',
|
||||
'tours.activity.compare.show': 'Összehasonlítás a térképen',
|
||||
'tours.activity.compare.showHint': 'A tényleges nyomvonalat pontozva rajzolja a terv mellé. Semmi sem változik.',
|
||||
'tours.activity.compare.hide': 'Összehasonlítás befejezése',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1212,5 +1212,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Jejak ini tidak dapat ditautkan ke tur ini',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Tur ini sendiri adalah jejak aktual tur lain',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Tur ini sudah tidak ada di hari itu',
|
||||
'tours.activity.compare.title': 'Rencana dan aktual',
|
||||
'tours.activity.compare.plan': 'Rencana',
|
||||
'tours.activity.compare.difference': 'Selisih',
|
||||
'tours.activity.compare.time': 'Waktu dengan istirahat',
|
||||
'tours.activity.compare.notInPlan': 'Tidak ada di rencana',
|
||||
'tours.activity.compare.notInTrack': 'Tidak ada di jejak',
|
||||
'tours.activity.compare.farthest': 'Jarak terjauh dari rencana',
|
||||
'tours.activity.compare.offPlan': 'Di luar rencana',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Bagian terekam yang berjarak lebih dari {distance} dari garis rencana',
|
||||
'tours.activity.compare.noLine': 'Tidak ada garis untuk dibandingkan',
|
||||
'tours.activity.compare.show': 'Bandingkan di peta',
|
||||
'tours.activity.compare.showHint': 'Menggambar jejak aktual bertitik di samping rencana. Tidak ada yang berubah.',
|
||||
'tours.activity.compare.hide': 'Akhiri perbandingan',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1240,5 +1240,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Questa traccia non può essere collegata a questo tour',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Questo tour è a sua volta la traccia effettiva di un altro tour',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Il tour non è più in quel giorno',
|
||||
'tours.activity.compare.title': 'Piano ed effettivo',
|
||||
'tours.activity.compare.plan': 'Piano',
|
||||
'tours.activity.compare.difference': 'Differenza',
|
||||
'tours.activity.compare.time': 'Tempo con pause',
|
||||
'tours.activity.compare.notInPlan': 'Non nel piano',
|
||||
'tours.activity.compare.notInTrack': 'Non nella traccia',
|
||||
'tours.activity.compare.farthest': 'Distanza massima dal piano',
|
||||
'tours.activity.compare.offPlan': 'Fuori dal piano',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Tratti registrati a più di {distance} dalla linea pianificata',
|
||||
'tours.activity.compare.noLine': 'Nessuna linea da confrontare',
|
||||
'tours.activity.compare.show': 'Confronta sulla mappa',
|
||||
'tours.activity.compare.showHint': 'Disegna la traccia effettiva a puntini accanto al piano. Non cambia nulla.',
|
||||
'tours.activity.compare.hide': 'Termina il confronto',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1176,5 +1176,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'このトラックはこのツアーにリンクできません',
|
||||
'tours.activity.refused.activity_tour_is_track': 'このツアー自体が別のツアーの実際のトラックです',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'このツアーはもうその日にありません',
|
||||
'tours.activity.compare.title': '予定と実績',
|
||||
'tours.activity.compare.plan': '予定',
|
||||
'tours.activity.compare.difference': '差',
|
||||
'tours.activity.compare.time': '休憩込みの時間',
|
||||
'tours.activity.compare.notInPlan': '予定にありません',
|
||||
'tours.activity.compare.notInTrack': 'トラックにありません',
|
||||
'tours.activity.compare.farthest': '予定からの最大距離',
|
||||
'tours.activity.compare.offPlan': '予定外',
|
||||
'tours.activity.compare.offPlanValue': '{distance}({percent}%)',
|
||||
'tours.activity.compare.offPlanHint': '予定ルートから {distance} 以上離れた記録区間',
|
||||
'tours.activity.compare.noLine': '比較するルートがありません',
|
||||
'tours.activity.compare.show': '地図で比較',
|
||||
'tours.activity.compare.showHint': '実際のトラックを予定の横に点線で描きます。何も変更されません。',
|
||||
'tours.activity.compare.hide': '比較を終了',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1174,5 +1174,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': '이 트랙은 이 투어에 연결할 수 없습니다',
|
||||
'tours.activity.refused.activity_tour_is_track': '이 투어는 다른 투어의 실제 트랙입니다',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': '이 투어는 더 이상 그날에 없습니다',
|
||||
'tours.activity.compare.title': '계획과 실제',
|
||||
'tours.activity.compare.plan': '계획',
|
||||
'tours.activity.compare.difference': '차이',
|
||||
'tours.activity.compare.time': '휴식 포함 시간',
|
||||
'tours.activity.compare.notInPlan': '계획에 없음',
|
||||
'tours.activity.compare.notInTrack': '트랙에 없음',
|
||||
'tours.activity.compare.farthest': '계획에서 가장 먼 거리',
|
||||
'tours.activity.compare.offPlan': '계획 이탈',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent}%)',
|
||||
'tours.activity.compare.offPlanHint': '계획된 선에서 {distance} 이상 떨어진 기록 구간',
|
||||
'tours.activity.compare.noLine': '비교할 선이 없음',
|
||||
'tours.activity.compare.show': '지도에서 비교',
|
||||
'tours.activity.compare.showHint': '실제 트랙을 계획 옆에 점선으로 그립니다. 아무것도 바뀌지 않습니다.',
|
||||
'tours.activity.compare.hide': '비교 종료',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1233,5 +1233,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Deze track kan niet aan deze tocht worden gekoppeld',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Deze tocht is zelf de werkelijke track van een andere tocht',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'De tocht staat niet meer op die dag',
|
||||
'tours.activity.compare.title': 'Planning en werkelijk',
|
||||
'tours.activity.compare.plan': 'Planning',
|
||||
'tours.activity.compare.difference': 'Verschil',
|
||||
'tours.activity.compare.time': 'Tijd met pauzes',
|
||||
'tours.activity.compare.notInPlan': 'Niet in de planning',
|
||||
'tours.activity.compare.notInTrack': 'Niet in de track',
|
||||
'tours.activity.compare.farthest': 'Grootste afstand tot de planning',
|
||||
'tours.activity.compare.offPlan': 'Buiten de planning',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Opgenomen stukken die meer dan {distance} van de geplande lijn liggen',
|
||||
'tours.activity.compare.noLine': 'Geen lijn om te vergelijken',
|
||||
'tours.activity.compare.show': 'Vergelijken op de kaart',
|
||||
'tours.activity.compare.showHint': 'Tekent de werkelijke track gestippeld naast de planning. Er verandert niets.',
|
||||
'tours.activity.compare.hide': 'Vergelijking beëindigen',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1254,5 +1254,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Tej trasy nie można powiązać z tą wycieczką',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Ta wycieczka jest sama rzeczywistą trasą innej wycieczki',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Wycieczki nie ma już w tym dniu',
|
||||
'tours.activity.compare.title': 'Plan i rzeczywistość',
|
||||
'tours.activity.compare.plan': 'Planowane',
|
||||
'tours.activity.compare.difference': 'Różnica',
|
||||
'tours.activity.compare.time': 'Czas z przerwami',
|
||||
'tours.activity.compare.notInPlan': 'Brak w planie',
|
||||
'tours.activity.compare.notInTrack': 'Brak w trasie',
|
||||
'tours.activity.compare.farthest': 'Największa odległość od planu',
|
||||
'tours.activity.compare.offPlan': 'Poza planem',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Zarejestrowane odcinki oddalone o więcej niż {distance} od planowanej linii',
|
||||
'tours.activity.compare.noLine': 'Brak linii do porównania',
|
||||
'tours.activity.compare.show': 'Porównaj na mapie',
|
||||
'tours.activity.compare.showHint': 'Rysuje rzeczywistą trasę kropkami obok planu. Nic się nie zmienia.',
|
||||
'tours.activity.compare.hide': 'Zakończ porównanie',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1261,5 +1261,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Этот трек нельзя связать с этим маршрутом',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Этот маршрут сам является фактическим треком другого маршрута',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Маршрута больше нет в этот день',
|
||||
'tours.activity.compare.title': 'План и факт',
|
||||
'tours.activity.compare.plan': 'План',
|
||||
'tours.activity.compare.difference': 'Разница',
|
||||
'tours.activity.compare.time': 'Время с перерывами',
|
||||
'tours.activity.compare.notInPlan': 'Нет в плане',
|
||||
'tours.activity.compare.notInTrack': 'Нет в треке',
|
||||
'tours.activity.compare.farthest': 'Наибольшее удаление от плана',
|
||||
'tours.activity.compare.offPlan': 'Вне плана',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Записанные участки дальше {distance} от запланированной линии',
|
||||
'tours.activity.compare.noLine': 'Нет линии для сравнения',
|
||||
'tours.activity.compare.show': 'Сравнить на карте',
|
||||
'tours.activity.compare.showHint': 'Рисует фактический трек пунктиром рядом с планом. Ничего не меняется.',
|
||||
'tours.activity.compare.hide': 'Завершить сравнение',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1216,5 +1216,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Túto trasu nemožno prepojiť s touto túrou',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Táto túra je sama skutočnou trasou inej túry',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Túra už v tento deň nie je',
|
||||
'tours.activity.compare.title': 'Plán a skutočnosť',
|
||||
'tours.activity.compare.plan': 'Plán',
|
||||
'tours.activity.compare.difference': 'Rozdiel',
|
||||
'tours.activity.compare.time': 'Čas s prestávkami',
|
||||
'tours.activity.compare.notInPlan': 'Nie je v pláne',
|
||||
'tours.activity.compare.notInTrack': 'Nie je v trase',
|
||||
'tours.activity.compare.farthest': 'Najväčšia odchýlka od plánu',
|
||||
'tours.activity.compare.offPlan': 'Mimo plánu',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Zaznamenané úseky vzdialené od plánovanej línie viac ako {distance}',
|
||||
'tours.activity.compare.noLine': 'Žiadna línia na porovnanie',
|
||||
'tours.activity.compare.show': 'Porovnať na mape',
|
||||
'tours.activity.compare.showHint': 'Vykreslí skutočnú trasu bodkovane vedľa plánu. Nič sa nemení.',
|
||||
'tours.activity.compare.hide': 'Ukončiť porovnanie',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1205,5 +1205,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Det här spåret kan inte länkas till den här turen',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Den här turen är själv det faktiska spåret för en annan tur',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Turen ligger inte längre på den dagen',
|
||||
'tours.activity.compare.title': 'Planerat och faktiskt',
|
||||
'tours.activity.compare.plan': 'Planerat',
|
||||
'tours.activity.compare.difference': 'Skillnad',
|
||||
'tours.activity.compare.time': 'Tid med pauser',
|
||||
'tours.activity.compare.notInPlan': 'Saknas i planen',
|
||||
'tours.activity.compare.notInTrack': 'Saknas i spåret',
|
||||
'tours.activity.compare.farthest': 'Största avstånd från planen',
|
||||
'tours.activity.compare.offPlan': 'Utanför planen',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Inspelade sträckor mer än {distance} från den planerade linjen',
|
||||
'tours.activity.compare.noLine': 'Ingen linje att jämföra',
|
||||
'tours.activity.compare.show': 'Jämför på kartan',
|
||||
'tours.activity.compare.showHint': 'Ritar det faktiska spåret prickat bredvid planen. Inget ändras.',
|
||||
'tours.activity.compare.hide': 'Avsluta jämförelsen',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1157,5 +1157,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'ไม่สามารถเชื่อมเส้นทางนี้กับทัวร์นี้ได้',
|
||||
'tours.activity.refused.activity_tour_is_track': 'ทัวร์นี้เป็นเส้นทางจริงของทัวร์อื่น',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'ทัวร์ไม่ได้อยู่ในวันนั้นแล้ว',
|
||||
'tours.activity.compare.title': 'แผนและเส้นทางจริง',
|
||||
'tours.activity.compare.plan': 'แผน',
|
||||
'tours.activity.compare.difference': 'ส่วนต่าง',
|
||||
'tours.activity.compare.time': 'เวลารวมพัก',
|
||||
'tours.activity.compare.notInPlan': 'ไม่มีในแผน',
|
||||
'tours.activity.compare.notInTrack': 'ไม่มีในเส้นทาง',
|
||||
'tours.activity.compare.farthest': 'ระยะห่างจากแผนมากที่สุด',
|
||||
'tours.activity.compare.offPlan': 'นอกแผน',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent}%)',
|
||||
'tours.activity.compare.offPlanHint': 'ช่วงที่บันทึกไว้ซึ่งห่างจากเส้นที่วางแผนไว้เกิน {distance}',
|
||||
'tours.activity.compare.noLine': 'ไม่มีเส้นให้เปรียบเทียบ',
|
||||
'tours.activity.compare.show': 'เปรียบเทียบบนแผนที่',
|
||||
'tours.activity.compare.showHint': 'วาดเส้นทางจริงเป็นจุดข้างแผน ไม่มีอะไรเปลี่ยน',
|
||||
'tours.activity.compare.hide': 'จบการเปรียบเทียบ',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -20,7 +20,7 @@ const tokens = (value: string) => [...value.matchAll(/\{[^{}]+\}/g)].map((match)
|
||||
// placeholder spec; here only the general keys are.
|
||||
const groups = pluralGroups(Object.keys(english));
|
||||
const generalKeys = (keys: string[]) => keys.filter((key) => !pluralFormOf(key, groups));
|
||||
const GENERAL_KEY_COUNT = 1099;
|
||||
const GENERAL_KEY_COUNT = 1113;
|
||||
|
||||
function literalKeys(source: string): string[] {
|
||||
const tree = ts.createSourceFile('locale.ts', source, ts.ScriptTarget.Latest, true);
|
||||
|
||||
@@ -1212,5 +1212,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Bu iz bu tura bağlanamaz',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Bu tur zaten başka bir turun gerçek izi',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Tur artık o günde değil',
|
||||
'tours.activity.compare.title': 'Plan ve gerçek',
|
||||
'tours.activity.compare.plan': 'Planlanan',
|
||||
'tours.activity.compare.difference': 'Fark',
|
||||
'tours.activity.compare.time': 'Molalar dahil süre',
|
||||
'tours.activity.compare.notInPlan': 'Planda yok',
|
||||
'tours.activity.compare.notInTrack': 'İzde yok',
|
||||
'tours.activity.compare.farthest': 'Plandan en uzak mesafe',
|
||||
'tours.activity.compare.offPlan': 'Plan dışı',
|
||||
'tours.activity.compare.offPlanValue': '{distance} (%{percent})',
|
||||
'tours.activity.compare.offPlanHint': 'Planlanan çizgiden {distance} fazla uzakta kalan kayıtlı bölümler',
|
||||
'tours.activity.compare.noLine': 'Karşılaştırılacak çizgi yok',
|
||||
'tours.activity.compare.show': 'Haritada karşılaştır',
|
||||
'tours.activity.compare.showHint': 'Gerçek izi planın yanına noktalı çizer. Hiçbir şey değişmez.',
|
||||
'tours.activity.compare.hide': 'Karşılaştırmayı bitir',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1247,5 +1247,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Цей трек не можна пов’язати з цим маршрутом',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Цей маршрут сам є фактичним треком іншого маршруту',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Маршруту вже немає цього дня',
|
||||
'tours.activity.compare.title': 'План і факт',
|
||||
'tours.activity.compare.plan': 'План',
|
||||
'tours.activity.compare.difference': 'Різниця',
|
||||
'tours.activity.compare.time': 'Час із перервами',
|
||||
'tours.activity.compare.notInPlan': 'Немає в плані',
|
||||
'tours.activity.compare.notInTrack': 'Немає в треку',
|
||||
'tours.activity.compare.farthest': 'Найбільша відстань від плану',
|
||||
'tours.activity.compare.offPlan': 'Поза планом',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Записані ділянки далі ніж {distance} від запланованої лінії',
|
||||
'tours.activity.compare.noLine': 'Немає лінії для порівняння',
|
||||
'tours.activity.compare.show': 'Порівняти на карті',
|
||||
'tours.activity.compare.showHint': 'Малює фактичний трек пунктиром поруч із планом. Нічого не змінюється.',
|
||||
'tours.activity.compare.hide': 'Завершити порівняння',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1201,5 +1201,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': 'Không thể liên kết lộ trình này với chuyến đi này',
|
||||
'tours.activity.refused.activity_tour_is_track': 'Tour này chính là lộ trình thực tế của tour khác',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': 'Tour không còn ở ngày đó',
|
||||
'tours.activity.compare.title': 'Kế hoạch và thực tế',
|
||||
'tours.activity.compare.plan': 'Kế hoạch',
|
||||
'tours.activity.compare.difference': 'Chênh lệch',
|
||||
'tours.activity.compare.time': 'Thời gian kể cả nghỉ',
|
||||
'tours.activity.compare.notInPlan': 'Không có trong kế hoạch',
|
||||
'tours.activity.compare.notInTrack': 'Không có trong lộ trình',
|
||||
'tours.activity.compare.farthest': 'Xa kế hoạch nhất',
|
||||
'tours.activity.compare.offPlan': 'Ngoài kế hoạch',
|
||||
'tours.activity.compare.offPlanValue': '{distance} ({percent} %)',
|
||||
'tours.activity.compare.offPlanHint': 'Các đoạn đã ghi cách đường dự kiến hơn {distance}',
|
||||
'tours.activity.compare.noLine': 'Không có đường để so sánh',
|
||||
'tours.activity.compare.show': 'So sánh trên bản đồ',
|
||||
'tours.activity.compare.showHint': 'Vẽ lộ trình thực tế bằng nét chấm cạnh kế hoạch. Không có gì thay đổi.',
|
||||
'tours.activity.compare.hide': 'Kết thúc so sánh',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1117,5 +1117,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': '此軌跡無法連結到此路線',
|
||||
'tours.activity.refused.activity_tour_is_track': '此路線本身是另一條路線的實際軌跡',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': '此路線已不在那一天',
|
||||
'tours.activity.compare.title': '計畫與實際',
|
||||
'tours.activity.compare.plan': '計畫',
|
||||
'tours.activity.compare.difference': '差異',
|
||||
'tours.activity.compare.time': '含休息時間',
|
||||
'tours.activity.compare.notInPlan': '計畫中沒有',
|
||||
'tours.activity.compare.notInTrack': '軌跡中沒有',
|
||||
'tours.activity.compare.farthest': '距計畫最遠',
|
||||
'tours.activity.compare.offPlan': '偏離計畫',
|
||||
'tours.activity.compare.offPlanValue': '{distance}({percent}%)',
|
||||
'tours.activity.compare.offPlanHint': '距計畫路線超過 {distance} 的已記錄路段',
|
||||
'tours.activity.compare.noLine': '沒有可比較的路線',
|
||||
'tours.activity.compare.show': '在地圖上比較',
|
||||
'tours.activity.compare.showHint': '將實際軌跡以點線畫在計畫旁。不會變更任何內容。',
|
||||
'tours.activity.compare.hide': '結束比較',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1118,5 +1118,19 @@ const tours: TranslationStrings = {
|
||||
'tours.activity.refused.activity_track_is_tour': '该轨迹无法关联到此路线',
|
||||
'tours.activity.refused.activity_tour_is_track': '该路线本身是另一条路线的实际轨迹',
|
||||
'tours.activity.refused.activity_assignment_not_of_tour': '该路线已不在那一天',
|
||||
'tours.activity.compare.title': '计划与实际',
|
||||
'tours.activity.compare.plan': '计划',
|
||||
'tours.activity.compare.difference': '差值',
|
||||
'tours.activity.compare.time': '含休息时间',
|
||||
'tours.activity.compare.notInPlan': '计划中没有',
|
||||
'tours.activity.compare.notInTrack': '轨迹中没有',
|
||||
'tours.activity.compare.farthest': '距计划最远',
|
||||
'tours.activity.compare.offPlan': '偏离计划',
|
||||
'tours.activity.compare.offPlanValue': '{distance}({percent}%)',
|
||||
'tours.activity.compare.offPlanHint': '距计划线路超过 {distance} 的已记录路段',
|
||||
'tours.activity.compare.noLine': '没有可比较的线路',
|
||||
'tours.activity.compare.show': '在地图上比较',
|
||||
'tours.activity.compare.showHint': '将实际轨迹以点线画在计划旁。不会更改任何内容。',
|
||||
'tours.activity.compare.hide': '结束比较',
|
||||
};
|
||||
export default tours;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { nearnessToLine } from './route-corridor';
|
||||
import { distancesToLine, nearnessToLine } from './route-corridor';
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
@@ -41,3 +41,33 @@ describe('nearnessToLine', () => {
|
||||
).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('distancesToLine', () => {
|
||||
const line = [
|
||||
[47, 11],
|
||||
[47.01, 11],
|
||||
[47.02, 11],
|
||||
];
|
||||
|
||||
it('measures every point against the line, in their order, as nearnessToLine does one', () => {
|
||||
const points = [
|
||||
[47.015, 11.001],
|
||||
[47.005, 11],
|
||||
[46.99, 11, 900],
|
||||
];
|
||||
const distances = distancesToLine(points, line);
|
||||
expect(distances).toHaveLength(3);
|
||||
points.forEach((point, index) => {
|
||||
expect(distances?.[index]).toBeCloseTo(
|
||||
nearnessToLine({ lat: Number(point[0]), lng: Number(point[1]) }, line)?.distanceM ?? -1,
|
||||
6,
|
||||
);
|
||||
});
|
||||
expect(distances?.[1]).toBe(0);
|
||||
});
|
||||
|
||||
it('answers nothing for a line too short, and nothing to measure for no points', () => {
|
||||
expect(distancesToLine([[47, 11]], [[47, 11]])).toBeNull();
|
||||
expect(distancesToLine([], line)).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,14 +27,15 @@ function flatten(line: readonly Coordinate[]) {
|
||||
return (lat: number, lng: number): [number, number] => [lng * kx, lat * ky];
|
||||
}
|
||||
|
||||
/** How near the point is to a line of `[lat, lng]` points; null for a line of fewer than two. */
|
||||
export function nearnessToLine(point: { lat: number; lng: number }, line: readonly Coordinate[]): RouteNearness | null {
|
||||
if (line.length < 2) return null;
|
||||
/** The line laid flat once, so many points can be measured against it without laying it again. */
|
||||
function flatLine(line: readonly Coordinate[]) {
|
||||
const flat = flatten(line);
|
||||
const [px, py] = flat(point.lat, point.lng);
|
||||
let best: RouteNearness | null = null;
|
||||
return { flat, points: line.map((p) => flat(Number(p[0]), Number(p[1]))) };
|
||||
}
|
||||
|
||||
function nearestOnFlat(points: readonly [number, number][], px: number, py: number): RouteNearness {
|
||||
let best: RouteNearness = { distanceM: Number.POSITIVE_INFINITY, alongM: 0 };
|
||||
let walked = 0;
|
||||
const points = line.map((p) => flat(Number(p[0]), Number(p[1])));
|
||||
for (let i = 1; i < points.length; i += 1) {
|
||||
const [ax, ay] = points[i - 1] as [number, number];
|
||||
const [bx, by] = points[i] as [number, number];
|
||||
@@ -43,8 +44,31 @@ export function nearnessToLine(point: { lat: number; lng: number }, line: readon
|
||||
const length2 = dx * dx + dy * dy;
|
||||
const t = length2 === 0 ? 0 : Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / length2));
|
||||
const distanceM = Math.hypot(px - (ax + t * dx), py - (ay + t * dy));
|
||||
if (!best || distanceM < best.distanceM) best = { distanceM, alongM: walked + t * Math.sqrt(length2) };
|
||||
if (distanceM < best.distanceM) best = { distanceM, alongM: walked + t * Math.sqrt(length2) };
|
||||
walked += Math.sqrt(length2);
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
/** How near the point is to a line of `[lat, lng]` points; null for a line of fewer than two. */
|
||||
export function nearnessToLine(point: { lat: number; lng: number }, line: readonly Coordinate[]): RouteNearness | null {
|
||||
if (line.length < 2) return null;
|
||||
const { flat, points } = flatLine(line);
|
||||
const [px, py] = flat(point.lat, point.lng);
|
||||
return nearestOnFlat(points, px, py);
|
||||
}
|
||||
|
||||
/**
|
||||
* How far each of `points` lies from the line, in metres and in their order;
|
||||
* null for a line of fewer than two. The line is laid flat once for all of
|
||||
* them, so a recorded track of thousands of points is measured against a plan
|
||||
* of thousands (ACT-02) without laying the plan again for every point.
|
||||
*/
|
||||
export function distancesToLine(points: readonly Coordinate[], line: readonly Coordinate[]): number[] | null {
|
||||
if (line.length < 2) return null;
|
||||
const { flat, points: flatPoints } = flatLine(line);
|
||||
return points.map((p) => {
|
||||
const [px, py] = flat(Number(p[0]), Number(p[1]));
|
||||
return nearestOnFlat(flatPoints, px, py).distanceM;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user