1 Commits

Author SHA1 Message Date
vcoppe
41b55157f5 New translations en.json (Spanish) 2025-12-11 14:52:24 +01:00
9 changed files with 39 additions and 145 deletions

View File

@@ -1375,7 +1375,10 @@ export class TrackPoint {
: undefined; : undefined;
} }
setExtension(key: string, value: string) { setExtensions(extensions: Record<string, string>) {
if (Object.keys(extensions).length === 0) {
return;
}
if (!this.extensions) { if (!this.extensions) {
this.extensions = {}; this.extensions = {};
} }
@@ -1385,12 +1388,8 @@ export class TrackPoint {
if (!this.extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions']) { if (!this.extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions']) {
this.extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions'] = {}; this.extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions'] = {};
} }
this.extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions'][key] = value;
}
setExtensions(extensions: Record<string, string>) {
Object.entries(extensions).forEach(([key, value]) => { Object.entries(extensions).forEach(([key, value]) => {
this.setExtension(key, value); this.extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions'][key] = value;
}); });
} }

View File

@@ -21,7 +21,7 @@
SquareArrowUpLeft, SquareArrowUpLeft,
SquareArrowOutDownRight, SquareArrowOutDownRight,
} from '@lucide/svelte'; } from '@lucide/svelte';
import { routingProfiles } from '$lib/components/toolbar/tools/routing/routing'; import { brouterProfiles } from '$lib/components/toolbar/tools/routing/routing';
import { i18n } from '$lib/i18n.svelte'; import { i18n } from '$lib/i18n.svelte';
import { slide } from 'svelte/transition'; import { slide } from 'svelte/transition';
import { import {
@@ -167,7 +167,7 @@
{i18n._(`toolbar.routing.activities.${$routingProfile}`)} {i18n._(`toolbar.routing.activities.${$routingProfile}`)}
</Select.Trigger> </Select.Trigger>
<Select.Content> <Select.Content>
{#each Object.keys(routingProfiles) as profile} {#each Object.keys(brouterProfiles) as profile}
<Select.Item value={profile} <Select.Item value={profile}
>{i18n._( >{i18n._(
`toolbar.routing.activities.${profile}` `toolbar.routing.activities.${profile}`

View File

@@ -6,141 +6,35 @@ import { get } from 'svelte/store';
const { routing, routingProfile, privateRoads } = settings; const { routing, routingProfile, privateRoads } = settings;
export type RoutingProfile = { export const brouterProfiles: { [key: string]: string } = {
engine: 'graphhopper' | 'brouter'; bike: 'Trekking-dry',
profile: string; racing_bike: 'fastbike',
}; gravel_bike: 'gravel',
mountain_bike: 'MTB',
export const routingProfiles: { [key: string]: RoutingProfile } = { foot: 'Hiking-Alpine-SAC6',
bike: { engine: 'graphhopper', profile: 'bike' }, motorcycle: 'Car-FastEco',
racing_bike: { engine: 'graphhopper', profile: 'racingbike' }, water: 'river',
gravel_bike: { engine: 'brouter', profile: 'gravel' }, railway: 'rail',
mountain_bike: { engine: 'graphhopper', profile: 'mtb' },
foot: { engine: 'graphhopper', profile: 'foot' },
motorcycle: { engine: 'graphhopper', profile: 'motorcycle' },
water: { engine: 'brouter', profile: 'river' },
railway: { engine: 'brouter', profile: 'rail' },
}; };
export function route(points: Coordinates[]): Promise<TrackPoint[]> { export function route(points: Coordinates[]): Promise<TrackPoint[]> {
if (get(routing)) { if (get(routing)) {
const profile = routingProfiles[get(routingProfile)]; return getRoute(points, brouterProfiles[get(routingProfile)], get(privateRoads));
if (profile.engine === 'graphhopper') {
return getGraphHopperRoute(points, profile.profile, get(privateRoads));
} else {
return getBRouterRoute(points, profile.profile);
}
} else { } else {
return getIntermediatePoints(points); return getIntermediatePoints(points);
} }
} }
const graphhopperDetails = ['road_class', 'surface', 'hike_rating', 'mtb_rating']; async function getRoute(
const hikeRatingToSACScale: { [key: string]: string } = {
'1': 'hiking',
'2': 'mountain_hiking',
'3': 'demanding_mountain_hiking',
'4': 'alpine_hiking',
'5': 'demanding_alpine_hiking',
'6': 'difficult_alpine_hiking',
};
const mtbRatingToScale: { [key: string]: string } = {
'1': '0',
'2': '1',
'3': '2',
'4': '3',
'5': '4',
'6': '5',
'7': '6',
};
async function getGraphHopperRoute(
points: Coordinates[], points: Coordinates[],
graphHopperProfile: string, brouterProfile: string,
privateRoads: boolean privateRoads: boolean
): Promise<TrackPoint[]> { ): Promise<TrackPoint[]> {
let response = await fetch('https://graphhopper-a.gpx.studio/route', { let url = `https://brouter.gpx.studio?lonlats=${points.map((point) => `${point.lon.toFixed(8)},${point.lat.toFixed(8)}`).join('|')}&profile=${brouterProfile + (privateRoads ? '-private' : '')}&format=geojson&alternativeidx=0`;
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
points: points.map((point) => [point.lon, point.lat]),
profile: graphHopperProfile,
elevation: true,
points_encoded: false,
details: graphhopperDetails,
custom_model: privateRoads
? {}
: {
priority: [
{
if: 'road_access == PRIVATE',
multiply_by: '0.0',
},
],
},
}),
});
if (!response.ok) {
throw new Error(`${await response.text()}`);
}
let json = await response.json();
let route: TrackPoint[] = [];
let coordinates = json.paths[0].points.coordinates;
let details = json.paths[0].details;
for (let i = 0; i < coordinates.length; i++) {
route.push(
new TrackPoint({
attributes: {
lat: coordinates[i][1],
lon: coordinates[i][0],
},
ele: coordinates[i][2] ?? (i > 0 ? route[i - 1].ele : 0),
extensions: {},
})
);
}
for (let key of graphhopperDetails) {
let detail = details[key];
for (let i = 0; i < detail.length; i++) {
for (let j = detail[i][0]; j < detail[i][1] + (i == detail.length - 1); j++) {
if (detail[i][2] !== undefined && detail[i][2] !== 'missing') {
if (key === 'road_class') {
route[j].setExtension('highway', detail[i][2]);
} else if (key === 'hike_rating') {
const sacScale = hikeRatingToSACScale[detail[i][2]];
if (sacScale) {
route[j].setExtension('sac_scale', sacScale);
}
} else if (key === 'mtb_rating') {
const mtbScale = mtbRatingToScale[detail[i][2]];
if (mtbScale) {
route[j].setExtension('mtb_scale', mtbScale);
}
} else if (key === 'surface' && detail[i][2] !== 'other') {
route[j].setExtension('surface', detail[i][2]);
}
}
}
}
}
return route;
}
async function getBRouterRoute(
points: Coordinates[],
brouterProfile: string
): Promise<TrackPoint[]> {
let url = `https://brouter.de/brouter?lonlats=${points.map((point) => `${point.lon.toFixed(8)},${point.lat.toFixed(8)}`).join('|')}&profile=${brouterProfile}&format=geojson&alternativeidx=0`;
let response = await fetch(url); let response = await fetch(url);
// Check if the response is ok
if (!response.ok) { if (!response.ok) {
throw new Error(`${await response.text()}`); throw new Error(`${await response.text()}`);
} }
@@ -158,13 +52,14 @@ async function getBRouterRoute(
let tags = messageIdx < messages.length ? getTags(messages[messageIdx][tagIdx]) : {}; let tags = messageIdx < messages.length ? getTags(messages[messageIdx][tagIdx]) : {};
for (let i = 0; i < coordinates.length; i++) { for (let i = 0; i < coordinates.length; i++) {
let coord = coordinates[i];
route.push( route.push(
new TrackPoint({ new TrackPoint({
attributes: { attributes: {
lat: coordinates[i][1], lat: coord[1],
lon: coordinates[i][0], lon: coord[0],
}, },
ele: coordinates[i][2] ?? (i > 0 ? route[i - 1].ele : 0), ele: coord[2] ?? (i > 0 ? route[i - 1].ele : 0),
}) })
); );

View File

@@ -29,13 +29,13 @@ Beste era batez, fitxategiak zuzenean arrastatu eta jaregin ditzakezu zure fitxa
Sortu hautatutako fitxategien kopia bat. Sortu hautatutako fitxategien kopia bat.
### <FileX size="16" class="inline-block" style="margin-bottom: 2px" /> Ezabatu ### <FileX size="16" class="inline-block" style="margin-bottom: 2px" /> Delete
Ezabatu hautatutako fitxategiak. Delete the currently selected files.
### <FileX size="16" class="inline-block" style="margin-bottom: 2px" /> Ezabatu guztiak ### <FileX size="16" class="inline-block" style="margin-bottom: 2px" /> Delete all
Ezabatu fitxategi guztiak. Delete all files.
### <Download size="16" class="inline-block" style="margin-bottom: 2px" /> Esportatu... ### <Download size="16" class="inline-block" style="margin-bottom: 2px" /> Esportatu...

View File

@@ -14,7 +14,7 @@ Deze handleiding zal je door alle componenten en gereedschappen van de interface
<DocsImage src="getting-started/interface" alt="De gpx.studio interface." /> <DocsImage src="getting-started/interface" alt="De gpx.studio interface." />
Zoals weergegeven in bovenstaande scherm, is de interface verdeeld in vier hoofddelen rond de kaart. Zoals weergegeven in bovenstaande scherm, is de interface verdeeld in vier hoofddelen rond de kaart.
Voordat we in de details van elke sectie duiken, eerst een snel overzicht van de interface. Voordat we in de details van elke sectie duiken, hebben we een snel overzicht van de interface.
## Menu ## Menu

View File

@@ -83,7 +83,7 @@ Deze actie is alleen beschikbaar wanneer de verticale indeling van de bestandsli
### <ClipboardPaste size="16" class="inline-block" style="margin-bottom: 2px" /> Plakken ### <ClipboardPaste size="16" class="inline-block" style="margin-bottom: 2px" /> Plakken
Plak de bestandsitems van het klembord naar het huidige hiërarchieniveau indien compatibel. Plak de bestandsitems van het klembord naar het huidige hiërarchie niveau indien compatibel.
<DocsNote> <DocsNote>

View File

@@ -33,9 +33,9 @@ title: 文件
Delete the currently selected files. Delete the currently selected files.
### <FileX size="16" class="inline-block" style="margin-bottom: 2px" /> 删除全部 ### <FileX size="16" class="inline-block" style="margin-bottom: 2px" /> Delete all
删除全部文件。 Delete all files.
### <Download size="16" class="inline-block" style="margin-bottom: 2px" /> 导出... ### <Download size="16" class="inline-block" style="margin-bottom: 2px" /> 导出...

View File

@@ -28,7 +28,7 @@
"undo": "Desegin", "undo": "Desegin",
"redo": "Berregin", "redo": "Berregin",
"delete": "Ezabatu", "delete": "Ezabatu",
"delete_all": "Ezabatu guztiak", "delete_all": "Delete all",
"select_all": "Hautatu dena", "select_all": "Hautatu dena",
"view": "Ikusi", "view": "Ikusi",
"elevation_profile": "Altuera profila", "elevation_profile": "Altuera profila",
@@ -80,7 +80,7 @@
"center": "Erdiratu", "center": "Erdiratu",
"open_in": "Ireki hemen", "open_in": "Ireki hemen",
"copy_coordinates": "Kopiatu koordenatuak", "copy_coordinates": "Kopiatu koordenatuak",
"edit_osm": "Editatu OpenStreeMapen" "edit_osm": "Edit in OpenStreetMap"
}, },
"toolbar": { "toolbar": {
"routing": { "routing": {
@@ -353,7 +353,7 @@
"water": "Ura", "water": "Ura",
"shower": "Dutxa", "shower": "Dutxa",
"shelter": "Babeslekua", "shelter": "Babeslekua",
"cemetery": "Hilerria", "cemetery": "Cemetery",
"motorized": "Kotxeak eta motorrak", "motorized": "Kotxeak eta motorrak",
"fuel-station": "Gasolindegia", "fuel-station": "Gasolindegia",
"parking": "Aparkalekua", "parking": "Aparkalekua",

View File

@@ -28,7 +28,7 @@
"undo": "撤销", "undo": "撤销",
"redo": "恢复", "redo": "恢复",
"delete": "删除", "delete": "删除",
"delete_all": "全部删除", "delete_all": "",
"select_all": "全选", "select_all": "全选",
"view": "显示", "view": "显示",
"elevation_profile": "海拔剖面图", "elevation_profile": "海拔剖面图",
@@ -80,7 +80,7 @@
"center": "居中", "center": "居中",
"open_in": "打开于", "open_in": "打开于",
"copy_coordinates": "复制坐标", "copy_coordinates": "复制坐标",
"edit_osm": " OpenStreetMap 中编辑" "edit_osm": "Edit in OpenStreetMap"
}, },
"toolbar": { "toolbar": {
"routing": { "routing": {
@@ -353,7 +353,7 @@
"water": "饮用水", "water": "饮用水",
"shower": "淋浴", "shower": "淋浴",
"shelter": "庇护所", "shelter": "庇护所",
"cemetery": "墓地", "cemetery": "Cemetery",
"motorized": "汽车和摩托车", "motorized": "汽车和摩托车",
"fuel-station": "加油站", "fuel-station": "加油站",
"parking": "停车场", "parking": "停车场",