mirror of
				https://github.com/gpxstudio/gpx.studio.git
				synced 2025-11-04 05:21:09 +00:00 
			
		
		
		
	add elevation tool
This commit is contained in:
		@@ -372,14 +372,14 @@ export class GPXFile extends GPXTreeNode<Track>{
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    addElevation(callback: (Coordinates) => number, trackIndices?: number[], segmentIndices?: number[], waypointIndices?: number[]) {
 | 
			
		||||
        let og = getOriginal(this); // Read as much as possible from the original object because it is faster
 | 
			
		||||
    addElevation(elevations: number[], trackIndices?: number[], segmentIndices?: number[], waypointIndices?: number[]) {
 | 
			
		||||
        let index = 0;
 | 
			
		||||
        this.trk.forEach((track, trackIndex) => {
 | 
			
		||||
            if (trackIndices === undefined || trackIndices.includes(trackIndex)) {
 | 
			
		||||
                track.trkseg.forEach((segment, segmentIndex) => {
 | 
			
		||||
                    if (segmentIndices === undefined || segmentIndices.includes(segmentIndex)) {
 | 
			
		||||
                        segment.trkpt.forEach((point, pointIndex) => {
 | 
			
		||||
                            point.ele = callback(og.trk[trackIndex].trkseg[segmentIndex].trkpt[pointIndex].attributes);
 | 
			
		||||
                        segment.trkpt.forEach((point) => {
 | 
			
		||||
                            point.ele = elevations[index++];
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
@@ -387,7 +387,7 @@ export class GPXFile extends GPXTreeNode<Track>{
 | 
			
		||||
        });
 | 
			
		||||
        this.wpt.forEach((waypoint, waypointIndex) => {
 | 
			
		||||
            if (waypointIndices === undefined || waypointIndices.includes(waypointIndex)) {
 | 
			
		||||
                waypoint.ele = callback(og.wpt[waypointIndex].attributes);
 | 
			
		||||
                waypoint.ele = elevations[index++];
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1260
									
								
								website/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1260
									
								
								website/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -21,8 +21,10 @@
 | 
			
		||||
        "@types/eslint": "^8.56.10",
 | 
			
		||||
        "@types/events": "^3.0.3",
 | 
			
		||||
        "@types/mapbox__mapbox-gl-geocoder": "^5.0.0",
 | 
			
		||||
        "@types/mapbox__tilebelt": "^1.0.4",
 | 
			
		||||
        "@types/mapbox-gl": "^3.1.0",
 | 
			
		||||
        "@types/node": "^20.14.6",
 | 
			
		||||
        "@types/png.js": "^0.2.3",
 | 
			
		||||
        "@types/sanitize-html": "^2.11.0",
 | 
			
		||||
        "@types/sortablejs": "^1.15.8",
 | 
			
		||||
        "@typescript-eslint/eslint-plugin": "^7.13.1",
 | 
			
		||||
@@ -43,13 +45,15 @@
 | 
			
		||||
        "tslib": "^2.6.3",
 | 
			
		||||
        "tsx": "^4.15.7",
 | 
			
		||||
        "typescript": "^5.4.5",
 | 
			
		||||
        "vite": "^5.3.1"
 | 
			
		||||
        "vite": "^5.3.1",
 | 
			
		||||
        "vite-plugin-node-polyfills": "^0.22.0"
 | 
			
		||||
    },
 | 
			
		||||
    "type": "module",
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@internationalized/date": "^3.5.4",
 | 
			
		||||
        "@mapbox/mapbox-gl-geocoder": "^5.0.2",
 | 
			
		||||
        "@mapbox/sphericalmercator": "^1.2.0",
 | 
			
		||||
        "@mapbox/tilebelt": "^1.0.2",
 | 
			
		||||
        "@types/mapbox__sphericalmercator": "^1.2.3",
 | 
			
		||||
        "bits-ui": "^0.21.12",
 | 
			
		||||
        "chart.js": "^4.4.3",
 | 
			
		||||
@@ -63,6 +67,7 @@
 | 
			
		||||
        "mapbox-gl": "^3.4.0",
 | 
			
		||||
        "mapillary-js": "^4.1.2",
 | 
			
		||||
        "mode-watcher": "^0.3.1",
 | 
			
		||||
        "png.js": "^0.2.1",
 | 
			
		||||
        "sanitize-html": "^2.13.0",
 | 
			
		||||
        "sortablejs": "^1.15.2",
 | 
			
		||||
        "svelte-i18n": "^4.0.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
import { File, FilePen, View, type Icon, Settings, Pencil, MapPin, Scissors, CalendarClock, Group, Ungroup, Filter, SquareDashedMousePointer } from "lucide-svelte";
 | 
			
		||||
import { File, FilePen, View, type Icon, Settings, Pencil, MapPin, Scissors, CalendarClock, Group, Ungroup, Filter, SquareDashedMousePointer, MountainSnow } from "lucide-svelte";
 | 
			
		||||
import type { ComponentType } from "svelte";
 | 
			
		||||
 | 
			
		||||
export const guides: Record<string, string[]> = {
 | 
			
		||||
    'getting-started': [],
 | 
			
		||||
    menu: ['file', 'edit', 'view', 'settings'],
 | 
			
		||||
    'files-and-stats': [],
 | 
			
		||||
    toolbar: ['routing', 'poi', 'scissors', 'time', 'merge', 'extract', 'minify', 'clean'],
 | 
			
		||||
    toolbar: ['routing', 'poi', 'scissors', 'time', 'merge', 'extract', 'elevation', 'minify', 'clean'],
 | 
			
		||||
    'map-controls': [],
 | 
			
		||||
    'gpx': [],
 | 
			
		||||
    'integration': [],
 | 
			
		||||
@@ -27,6 +27,7 @@ export const guideIcons: Record<string, string | ComponentType<Icon>> = {
 | 
			
		||||
    "time": CalendarClock,
 | 
			
		||||
    "merge": Group,
 | 
			
		||||
    "extract": Ungroup,
 | 
			
		||||
    "elevation": MountainSnow,
 | 
			
		||||
    "minify": Filter,
 | 
			
		||||
    "clean": SquareDashedMousePointer,
 | 
			
		||||
    "map-controls": "🗺",
 | 
			
		||||
 
 | 
			
		||||
@@ -261,14 +261,16 @@ export class GPXLayer {
 | 
			
		||||
                    marker.on('dragend', (e) => {
 | 
			
		||||
                        resetCursor();
 | 
			
		||||
                        marker.getElement().style.cursor = '';
 | 
			
		||||
                        dbUtils.applyToFile(this.fileId, (file) => {
 | 
			
		||||
                            let latLng = marker.getLngLat();
 | 
			
		||||
                            let wpt = file.wpt[marker._waypoint._data.index];
 | 
			
		||||
                            wpt.setCoordinates({
 | 
			
		||||
                                lat: latLng.lat,
 | 
			
		||||
                                lon: latLng.lng
 | 
			
		||||
                        getElevation([marker._waypoint]).then((ele) => {
 | 
			
		||||
                            dbUtils.applyToFile(this.fileId, (file) => {
 | 
			
		||||
                                let latLng = marker.getLngLat();
 | 
			
		||||
                                let wpt = file.wpt[marker._waypoint._data.index];
 | 
			
		||||
                                wpt.setCoordinates({
 | 
			
		||||
                                    lat: latLng.lat,
 | 
			
		||||
                                    lon: latLng.lng
 | 
			
		||||
                                });
 | 
			
		||||
                                wpt.ele = ele[0];
 | 
			
		||||
                            });
 | 
			
		||||
                            wpt.ele = getElevation(this.map, wpt.getCoordinates());
 | 
			
		||||
                        });
 | 
			
		||||
                        dragEndTimestamp = Date.now()
 | 
			
		||||
                    });
 | 
			
		||||
 
 | 
			
		||||
@@ -125,13 +125,11 @@ function getIntermediatePoints(points: Coordinates[]): Promise<TrackPoint[]> {
 | 
			
		||||
        }
 | 
			
		||||
    }));
 | 
			
		||||
 | 
			
		||||
    let m = get(map);
 | 
			
		||||
    route.forEach((point) => {
 | 
			
		||||
        point.setSurface("unknown");
 | 
			
		||||
        if (m) {
 | 
			
		||||
            point.ele = getElevation(m, point.getCoordinates());
 | 
			
		||||
        }
 | 
			
		||||
    return getElevation(route).then((elevations) => {
 | 
			
		||||
        route.forEach((point, i) => {
 | 
			
		||||
            point.setSurface("unknown");
 | 
			
		||||
            point.ele = elevations[i];
 | 
			
		||||
        });
 | 
			
		||||
        return route;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return new Promise((resolve) => resolve(route));
 | 
			
		||||
}
 | 
			
		||||
@@ -10,7 +10,7 @@ import { dbUtils, type GPXFileWithStatistics } from "$lib/db";
 | 
			
		||||
import { getOrderedSelection, selection } from "$lib/components/file-list/Selection";
 | 
			
		||||
import { ListFileItem, ListTrackItem, ListTrackSegmentItem } from "$lib/components/file-list/FileList";
 | 
			
		||||
import { currentTool, streetViewEnabled, Tool } from "$lib/stores";
 | 
			
		||||
import { getClosestLinePoint, getElevation, resetCursor, setGrabbingCursor } from "$lib/utils";
 | 
			
		||||
import { getClosestLinePoint, resetCursor, setGrabbingCursor } from "$lib/utils";
 | 
			
		||||
 | 
			
		||||
export const canChangeStart = writable(false);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ import { applyToOrderedItemsFromFile, applyToOrderedSelectedItemsFromFile, selec
 | 
			
		||||
import { ListFileItem, ListItem, ListTrackItem, ListLevel, ListTrackSegmentItem, ListWaypointItem, ListRootItem } from '$lib/components/file-list/FileList';
 | 
			
		||||
import { updateAnchorPoints } from '$lib/components/toolbar/tools/routing/Simplify';
 | 
			
		||||
import { SplitType } from '$lib/components/toolbar/tools/scissors/Scissors.svelte';
 | 
			
		||||
import { getClosestLinePoint, getElevation, getPreciseElevations } from '$lib/utils';
 | 
			
		||||
import { getClosestLinePoint, getElevation } from '$lib/utils';
 | 
			
		||||
import { browser } from '$app/environment';
 | 
			
		||||
import type mapboxgl from 'mapbox-gl';
 | 
			
		||||
 | 
			
		||||
@@ -911,29 +911,30 @@ export const dbUtils = {
 | 
			
		||||
        if (m === null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        let ele = getElevation(m, waypoint.attributes);
 | 
			
		||||
        if (item) {
 | 
			
		||||
            dbUtils.applyToFile(item.getFileId(), (file) => {
 | 
			
		||||
                let wpt = file.wpt[item.getWaypointIndex()];
 | 
			
		||||
                wpt.name = waypoint.name;
 | 
			
		||||
                wpt.desc = waypoint.desc;
 | 
			
		||||
                wpt.cmt = waypoint.cmt;
 | 
			
		||||
                wpt.sym = waypoint.sym;
 | 
			
		||||
                wpt.link = waypoint.link;
 | 
			
		||||
                wpt.setCoordinates(waypoint.attributes);
 | 
			
		||||
                wpt.ele = ele;
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            let fileIds = new Set<string>();
 | 
			
		||||
            get(selection).getSelected().forEach((item) => {
 | 
			
		||||
                fileIds.add(item.getFileId());
 | 
			
		||||
            });
 | 
			
		||||
            let wpt = new Waypoint(waypoint);
 | 
			
		||||
            wpt.ele = ele;
 | 
			
		||||
            dbUtils.applyToFiles(Array.from(fileIds), (file) =>
 | 
			
		||||
                file.replaceWaypoints(file.wpt.length, file.wpt.length, [wpt])
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        getElevation([waypoint.attributes]).then((elevation) => {
 | 
			
		||||
            if (item) {
 | 
			
		||||
                dbUtils.applyToFile(item.getFileId(), (file) => {
 | 
			
		||||
                    let wpt = file.wpt[item.getWaypointIndex()];
 | 
			
		||||
                    wpt.name = waypoint.name;
 | 
			
		||||
                    wpt.desc = waypoint.desc;
 | 
			
		||||
                    wpt.cmt = waypoint.cmt;
 | 
			
		||||
                    wpt.sym = waypoint.sym;
 | 
			
		||||
                    wpt.link = waypoint.link;
 | 
			
		||||
                    wpt.setCoordinates(waypoint.attributes);
 | 
			
		||||
                    wpt.ele = elevation[0];
 | 
			
		||||
                });
 | 
			
		||||
            } else {
 | 
			
		||||
                let fileIds = new Set<string>();
 | 
			
		||||
                get(selection).getSelected().forEach((item) => {
 | 
			
		||||
                    fileIds.add(item.getFileId());
 | 
			
		||||
                });
 | 
			
		||||
                let wpt = new Waypoint(waypoint);
 | 
			
		||||
                wpt.ele = elevation[0];
 | 
			
		||||
                dbUtils.applyToFiles(Array.from(fileIds), (file) =>
 | 
			
		||||
                    file.replaceWaypoints(file.wpt.length, file.wpt.length, [wpt])
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
    setStyleToSelection: (style: LineStyleExtension) => {
 | 
			
		||||
        if (get(selection).size === 0) {
 | 
			
		||||
@@ -1052,27 +1053,25 @@ export const dbUtils = {
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        getPreciseElevations(map, points).then((elevations) => {
 | 
			
		||||
 | 
			
		||||
            let callback = (coordinates: Coordinates) => elevations.get(`${coordinates.lat},${coordinates.lon}`) ?? 0;
 | 
			
		||||
        getElevation(points).then((elevations) => {
 | 
			
		||||
            applyGlobal((draft) => {
 | 
			
		||||
                applyToOrderedSelectedItemsFromFile((fileId, level, items) => {
 | 
			
		||||
                    let file = draft.get(fileId);
 | 
			
		||||
                    if (file) {
 | 
			
		||||
                        if (level === ListLevel.FILE) {
 | 
			
		||||
                            file.addElevation(callback);
 | 
			
		||||
                            file.addElevation(elevations);
 | 
			
		||||
                        } else if (level === ListLevel.TRACK) {
 | 
			
		||||
                            let trackIndices = items.map((item) => (item as ListTrackItem).getTrackIndex());
 | 
			
		||||
                            file.addElevation(callback, trackIndices, undefined, []);
 | 
			
		||||
                            file.addElevation(elevations, trackIndices, undefined, []);
 | 
			
		||||
                        } else if (level === ListLevel.SEGMENT) {
 | 
			
		||||
                            let trackIndices = [(items[0] as ListTrackSegmentItem).getTrackIndex()];
 | 
			
		||||
                            let segmentIndices = items.map((item) => (item as ListTrackSegmentItem).getSegmentIndex());
 | 
			
		||||
                            file.addElevation(callback, trackIndices, segmentIndices, []);
 | 
			
		||||
                            file.addElevation(elevations, trackIndices, segmentIndices, []);
 | 
			
		||||
                        } else if (level === ListLevel.WAYPOINTS) {
 | 
			
		||||
                            file.addElevation(callback, [], [], undefined);
 | 
			
		||||
                            file.addElevation(elevations, [], [], undefined);
 | 
			
		||||
                        } else if (level === ListLevel.WAYPOINT) {
 | 
			
		||||
                            let waypointIndices = items.map((item) => (item as ListWaypointItem).getWaypointIndex());
 | 
			
		||||
                            file.addElevation(callback, [], [], waypointIndices);
 | 
			
		||||
                            file.addElevation(elevations, [], [], waypointIndices);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 
 | 
			
		||||
@@ -31,9 +31,4 @@ Someone more experienced with OpenStreetMap will then review your note and make
 | 
			
		||||
 | 
			
		||||
More information on how to contribute to OpenStreetMap can be found <a href="https://wiki.openstreetmap.org/wiki/How_to_contribute" target="_blank">here</a>.
 | 
			
		||||
 | 
			
		||||
</DocsNote>
 | 
			
		||||
 | 
			
		||||
### Why is the elevation profile for my GPX file empty?
 | 
			
		||||
 | 
			
		||||
If the elevation profile for your GPX file is empty, it means that the GPX file does not contain elevation data.
 | 
			
		||||
You can add elevation data to your GPX file by using <a href="https://www.gpsvisualizer.com/elevation" target="_blank">GPS Visualizer</a>.
 | 
			
		||||
</DocsNote>
 | 
			
		||||
							
								
								
									
										20
									
								
								website/src/lib/docs/en/toolbar/elevation.mdx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								website/src/lib/docs/en/toolbar/elevation.mdx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
---
 | 
			
		||||
title: Elevation
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    import { MountainSnow } from 'lucide-svelte';
 | 
			
		||||
    import Elevation from '$lib/components/toolbar/tools/Elevation.svelte';
 | 
			
		||||
    import DocsNote from '$lib/components/docs/DocsNote.svelte';
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
# <MountainSnow size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
 | 
			
		||||
 | 
			
		||||
This tool allows you to add elevation data to traces and [points of interest](../gpx), or to replace the existing data.
 | 
			
		||||
 | 
			
		||||
<div class="flex flex-row justify-center">
 | 
			
		||||
    <Elevation class="text-foreground p-3 border rounded-md shadow-lg" />
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
Elevation data is provided by <a href="https://mapbox.com" target="_blank">Mapbox</a>.
 | 
			
		||||
You can learn more about its origin and accuracy in the <a href="https://docs.mapbox.com/data/tilesets/reference/mapbox-terrain-dem-v1/#elevation-data" target="_blank">documentation</a>.
 | 
			
		||||
@@ -7,8 +7,11 @@ import { map } from "./stores";
 | 
			
		||||
import { base } from "$app/paths";
 | 
			
		||||
import { languages } from "$lib/languages";
 | 
			
		||||
import { locale } from "svelte-i18n";
 | 
			
		||||
import type mapboxgl from "mapbox-gl";
 | 
			
		||||
import { type TrackPoint, type Waypoint, type Coordinates, crossarcDistance, distance } from "gpx";
 | 
			
		||||
import { TrackPoint, Waypoint, type Coordinates, crossarcDistance, distance } from "gpx";
 | 
			
		||||
import mapboxgl from "mapbox-gl";
 | 
			
		||||
import tilebelt from "@mapbox/tilebelt";
 | 
			
		||||
import { PUBLIC_MAPBOX_TOKEN } from "$env/static/public";
 | 
			
		||||
import PNGReader from "png.js";
 | 
			
		||||
 | 
			
		||||
export function cn(...inputs: ClassValue[]) {
 | 
			
		||||
    return twMerge(clsx(inputs));
 | 
			
		||||
@@ -90,32 +93,52 @@ export function getClosestLinePoint(points: TrackPoint[], point: TrackPoint | Co
 | 
			
		||||
    return closest;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getElevation(map: mapboxgl.Map, coordinates: Coordinates): number {
 | 
			
		||||
    let elevation = map.queryTerrainElevation(coordinates, { exaggerated: false });
 | 
			
		||||
    return elevation === null ? 0 : elevation;
 | 
			
		||||
}
 | 
			
		||||
export function getElevation(points: (TrackPoint | Waypoint | Coordinates)[], ELEVATION_ZOOM: number = 13, tileSize = 512): Promise<number[]> {
 | 
			
		||||
    let coordinates = points.map((point) => (point instanceof TrackPoint || point instanceof Waypoint) ? point.getCoordinates() : point);
 | 
			
		||||
    let bbox = new mapboxgl.LngLatBounds();
 | 
			
		||||
    coordinates.forEach((coord) => bbox.extend(coord));
 | 
			
		||||
 | 
			
		||||
export async function getPreciseElevation(map: mapboxgl.Map, coordinates: Coordinates | mapboxgl.LngLat): Promise<number> {
 | 
			
		||||
    if (!map.getBounds().contains(coordinates) || map.getZoom() < 14) {
 | 
			
		||||
        map.flyTo({ center: coordinates, zoom: 14 });
 | 
			
		||||
        await map.once('idle');
 | 
			
		||||
    }
 | 
			
		||||
    let elevation = map.queryTerrainElevation(coordinates, { exaggerated: false });
 | 
			
		||||
    return elevation === null ? 0 : elevation;
 | 
			
		||||
}
 | 
			
		||||
    let tiles = coordinates.map((coord) => tilebelt.pointToTile(coord.lon, coord.lat, ELEVATION_ZOOM));
 | 
			
		||||
    let uniqueTiles = Array.from(new Set(tiles.map((tile) => tile.join(',')))).map((tile) => tile.split(',').map((x) => parseInt(x)));
 | 
			
		||||
    let pngs = new Map<string, PNGReader>();
 | 
			
		||||
 | 
			
		||||
export async function getPreciseElevations(map: mapboxgl.Map, points: (TrackPoint | Waypoint)[]): Promise<Map<string, number>> {
 | 
			
		||||
    let elevations = new Map<string, number>();
 | 
			
		||||
    let promises = uniqueTiles.map((tile) => fetch(`https://api.mapbox.com/v4/mapbox.mapbox-terrain-dem-v1/${ELEVATION_ZOOM}/${tile[0]}/${tile[1]}@2x.pngraw?access_token=${PUBLIC_MAPBOX_TOKEN}`, { cache: 'force-cache' }).then((response) => response.arrayBuffer()).then((buffer) => new Promise((resolve, reject) => {
 | 
			
		||||
        let png = new PNGReader(new Uint8Array(buffer));
 | 
			
		||||
        png.parse((err, png) => {
 | 
			
		||||
            if (err) {
 | 
			
		||||
                reject(err);
 | 
			
		||||
            } else {
 | 
			
		||||
                resolve(png);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    })).then((png) => {
 | 
			
		||||
        pngs.set(tile.join(','), png);
 | 
			
		||||
    }));
 | 
			
		||||
 | 
			
		||||
    for (let point of points) {
 | 
			
		||||
        let key = `${point.getLatitude()},${point.getLongitude()}`;
 | 
			
		||||
        if (elevations.has(key)) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        elevations.set(key, await getPreciseElevation(map, point.getCoordinates()));
 | 
			
		||||
    }
 | 
			
		||||
    return Promise.all(promises).then(() => coordinates.map((coord, index) => {
 | 
			
		||||
        let tile = tiles[index];
 | 
			
		||||
        let tf = tilebelt.pointToTileFraction(coord.lon, coord.lat, ELEVATION_ZOOM);
 | 
			
		||||
        let x = tileSize * (tf[0] - tile[0]);
 | 
			
		||||
        let y = tileSize * (tf[1] - tile[1]);
 | 
			
		||||
        let _x = Math.floor(x);
 | 
			
		||||
        let _y = Math.floor(y);
 | 
			
		||||
        let dx = x - _x;
 | 
			
		||||
        let dy = y - _y;
 | 
			
		||||
 | 
			
		||||
    return elevations;
 | 
			
		||||
        // Get the four pixels surrounding the point
 | 
			
		||||
        let png = pngs.get(tile.join(','))!;
 | 
			
		||||
        const p00 = png.getPixel(_x, _y);
 | 
			
		||||
        const p01 = png.getPixel(_x, _y + (_y + 1 == tileSize ? 0 : 1));
 | 
			
		||||
        const p10 = png.getPixel(_x + (_x + 1 == tileSize ? 0 : 1), _y);
 | 
			
		||||
        const p11 = png.getPixel(_x + (_x + 1 == tileSize ? 0 : 1), _y + (_y + 1 == tileSize ? 0 : 1));
 | 
			
		||||
 | 
			
		||||
        let ele00 = -10000 + ((p00[0] * 256 * 256 + p00[1] * 256 + p00[2]) * 0.1);
 | 
			
		||||
        let ele01 = -10000 + ((p01[0] * 256 * 256 + p01[1] * 256 + p01[2]) * 0.1);
 | 
			
		||||
        let ele10 = -10000 + ((p10[0] * 256 * 256 + p10[1] * 256 + p10[2]) * 0.1);
 | 
			
		||||
        let ele11 = -10000 + ((p11[0] * 256 * 256 + p11[1] * 256 + p11[2]) * 0.1);
 | 
			
		||||
 | 
			
		||||
        return ele00 * (1 - dx) * (1 - dy) + ele01 * (1 - dx) * dy + ele10 * dx * (1 - dy) + ele11 * dx * dy;
 | 
			
		||||
    }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let previousCursors: string[] = [];
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,8 @@
 | 
			
		||||
import { sveltekit } from '@sveltejs/kit/vite';
 | 
			
		||||
import { enhancedImages } from '@sveltejs/enhanced-img';
 | 
			
		||||
import { defineConfig } from 'vite';
 | 
			
		||||
import { nodePolyfills } from 'vite-plugin-node-polyfills'
 | 
			
		||||
 | 
			
		||||
export default defineConfig({
 | 
			
		||||
    plugins: [enhancedImages(), sveltekit()]
 | 
			
		||||
    plugins: [nodePolyfills(), enhancedImages(), sveltekit()]
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user