mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-11-15 07:07:07 +00:00
cleaning
This commit is contained in:
1 parent
002fd259aa
commit
7474f892ce
20 files changed
+28
-221
No files matched your search
@@ -560,26 +560,6 @@ impl WaypointDetails {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
pub struct TrackpointDetails {
|
|
||||||
lng: f64,
|
|
||||||
lat: f64,
|
|
||||||
ele: f64,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
time: Option<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TrackpointDetails {
|
|
||||||
pub fn new(pt: &engine::Trackpoint) -> Self {
|
|
||||||
Self {
|
|
||||||
lng: pt.coordinates.lng,
|
|
||||||
lat: pt.coordinates.lat,
|
|
||||||
ele: pt.ele,
|
|
||||||
time: pt.time.map(|t| t as f64),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trackpoint of the selection: what the statistics buffers do not hold for each trackpoint.
|
/// A trackpoint of the selection: what the statistics buffers do not hold for each trackpoint.
|
||||||
/// Absent fields are unknown.
|
/// Absent fields are unknown.
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
|||||||
@@ -63,18 +63,6 @@ pub fn waypoint<H: History>(
|
|||||||
.map(WaypointDetails::new)
|
.map(WaypointDetails::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trackpoint of a segment of a file, `None` if it does not exist.
|
|
||||||
pub fn trackpoint<H: History>(
|
|
||||||
engine: &Engine<H>,
|
|
||||||
file_id: Uuid,
|
|
||||||
segment_id: Uuid,
|
|
||||||
index: usize,
|
|
||||||
) -> Option<TrackpointDetails> {
|
|
||||||
engine
|
|
||||||
.trackpoint(&FileId(file_id), &engine::TrackSegmentId(segment_id), index)
|
|
||||||
.map(TrackpointDetails::new)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A file as GPX (UTF-8 bytes), `None` if it does not exist. The options say which data of the
|
/// A file as GPX (UTF-8 bytes), `None` if it does not exist. The options say which data of the
|
||||||
/// trackpoints to keep.
|
/// trackpoints to keep.
|
||||||
pub fn export_file<H: History>(
|
pub fn export_file<H: History>(
|
||||||
|
|||||||
@@ -24,14 +24,6 @@ pub struct Statistics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Statistics {
|
impl Statistics {
|
||||||
pub fn total_speed(&self) -> Option<f64> {
|
|
||||||
self.global.total_speed()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn moving_speed(&self) -> Option<f64> {
|
|
||||||
self.global.moving_speed()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compute(trkseg: &TrackSegment) -> Self {
|
pub fn compute(trkseg: &TrackSegment) -> Self {
|
||||||
let mut stats = Self::default();
|
let mut stats = Self::default();
|
||||||
if trkseg.is_empty() {
|
if trkseg.is_empty() {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ impl StatisticsCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Statistics of the segments of the selection.
|
/// Statistics of the segments of the selection.
|
||||||
|
#[cfg(test)]
|
||||||
pub fn get<'a>(
|
pub fn get<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
state: Option<&'a Files>,
|
state: Option<&'a Files>,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ pub use outcome::*;
|
|||||||
pub use state::*;
|
pub use state::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ExportOptions, FileId, GlobalStatistics, Restored, Snapshot, TrackSegmentId, Trackpoint,
|
ExportOptions, FileId, GlobalStatistics, Restored, Snapshot, TrackSegmentId,
|
||||||
TrackpointCategories, Waypoint, WaypointId, reduction_distances, write,
|
TrackpointCategories, Waypoint, WaypointId, reduction_distances, write,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,22 +82,6 @@ impl<H: History> Engine<H> {
|
|||||||
.find(|wpt| wpt.id == *id)
|
.find(|wpt| wpt.id == *id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trackpoint of a segment (of a route or a track) of a file. `None` if it does not exist.
|
|
||||||
pub fn trackpoint(
|
|
||||||
&self,
|
|
||||||
file_id: &FileId,
|
|
||||||
segment_id: &TrackSegmentId,
|
|
||||||
index: usize,
|
|
||||||
) -> Option<&Trackpoint> {
|
|
||||||
let segment = self
|
|
||||||
.history
|
|
||||||
.current()?
|
|
||||||
.get(file_id)?
|
|
||||||
.segments()
|
|
||||||
.find(|seg| seg.id == *segment_id)?;
|
|
||||||
(index < segment.len()).then(|| &segment[index])
|
|
||||||
}
|
|
||||||
|
|
||||||
/// For each trackpoint of the selection (numbered as in the statistics), the tolerance up to
|
/// For each trackpoint of the selection (numbered as in the statistics), the tolerance up to
|
||||||
/// which `Reduce` keeps it, see [`reduction_distances`].
|
/// which `Reduce` keeps it, see [`reduction_distances`].
|
||||||
pub fn reduction_distances(&self) -> Vec<f64> {
|
pub fn reduction_distances(&self) -> Vec<f64> {
|
||||||
|
|||||||
@@ -1169,24 +1169,6 @@ fn test_categories_are_shared_and_kept_by_the_history() {
|
|||||||
assert_eq!(expand(&engine.statistics().surface, 5), [1, 1, 0, 2, 2]);
|
assert_eq!(expand(&engine.statistics().surface, 5), [1, 1, 0, 2, 2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_trackpoint() {
|
|
||||||
let mut engine = TestEngine::default();
|
|
||||||
load(&mut engine, "data/simple.gpx");
|
|
||||||
let file = engine.order()[0];
|
|
||||||
let structure = engine.file_structure(&file).unwrap();
|
|
||||||
let seg = &structure.tracks[0].segments[0];
|
|
||||||
let (seg_id, len) = (seg.id, seg.len);
|
|
||||||
let coordinates = engine.segment_coordinates(&seg_id).to_vec();
|
|
||||||
let last = engine.trackpoint(&file, &seg_id, len - 1).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
[last.coordinates.lng, last.coordinates.lat],
|
|
||||||
coordinates[(len - 1) * 2..]
|
|
||||||
);
|
|
||||||
assert!(engine.trackpoint(&file, &seg_id, len).is_none());
|
|
||||||
assert!(engine.trackpoint(&Default::default(), &seg_id, 0).is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_export_writes_the_file_as_it_is() {
|
fn test_export_writes_the_file_as_it_is() {
|
||||||
let mut engine = TestEngine::default();
|
let mut engine = TestEngine::default();
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
#[cfg(test)]
|
||||||
Batch, ChunkKey, ChunkKind, CommitError, FileId, Revision, Storage, StorageError, StoredData,
|
use crate::ChunkKind;
|
||||||
};
|
use crate::{Batch, ChunkKey, CommitError, FileId, Revision, Storage, StorageError, StoredData};
|
||||||
|
|
||||||
/// A storage that lives as long as the session. It is what an engine without a host storage uses,
|
/// A storage that lives as long as the session. It is what an engine without a host storage uses,
|
||||||
/// and what the tests use.
|
/// and what the tests use.
|
||||||
@@ -22,6 +22,7 @@ struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// How much there is in a storage.
|
/// How much there is in a storage.
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct StorageCounts {
|
pub struct StorageCounts {
|
||||||
pub files: usize,
|
pub files: usize,
|
||||||
@@ -29,6 +30,7 @@ pub struct StorageCounts {
|
|||||||
pub waypoint_chunks: usize,
|
pub waypoint_chunks: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
impl MemoryStorage {
|
impl MemoryStorage {
|
||||||
/// How many files and chunks are stored.
|
/// How many files and chunks are stored.
|
||||||
pub fn counts(&self) -> StorageCounts {
|
pub fn counts(&self) -> StorageCounts {
|
||||||
|
|||||||
@@ -57,16 +57,6 @@ pub fn waypoint(
|
|||||||
state.read(move |e| api::waypoint(e, file_id, waypoint_id))
|
state.read(move |e| api::waypoint(e, file_id, waypoint_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command(async)]
|
|
||||||
pub fn trackpoint(
|
|
||||||
state: State<AppState>,
|
|
||||||
file_id: Uuid,
|
|
||||||
segment_id: Uuid,
|
|
||||||
index: usize,
|
|
||||||
) -> Option<api::TrackpointDetails> {
|
|
||||||
state.read(move |e| api::trackpoint(e, file_id, segment_id, index))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A file as GPX (UTF-8 bytes), the first byte telling whether the file exists.
|
/// A file as GPX (UTF-8 bytes), the first byte telling whether the file exists.
|
||||||
#[tauri::command(async)]
|
#[tauri::command(async)]
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
|||||||
@@ -173,7 +173,6 @@ pub fn register_commands<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri
|
|||||||
queries::can_redo,
|
queries::can_redo,
|
||||||
queries::can_paste,
|
queries::can_paste,
|
||||||
queries::waypoint,
|
queries::waypoint,
|
||||||
queries::trackpoint,
|
|
||||||
queries::export_file,
|
queries::export_file,
|
||||||
queries::exportable_data,
|
queries::exportable_data,
|
||||||
queries::reduction_distances,
|
queries::reduction_distances,
|
||||||
|
|||||||
@@ -101,18 +101,6 @@ pub fn waypoint(file_id: &str, waypoint_id: &str) -> WaypointDetails {
|
|||||||
optional_js(details).unchecked_into()
|
optional_js(details).unchecked_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trackpoint of a segment of a file, `undefined` if it does not exist.
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn trackpoint(file_id: &str, segment_id: &str, index: usize) -> TrackpointDetails {
|
|
||||||
let details =
|
|
||||||
parse_uuid(file_id)
|
|
||||||
.zip(parse_uuid(segment_id))
|
|
||||||
.and_then(|(file_id, segment_id)| {
|
|
||||||
with_engine(|e| api::trackpoint(e, file_id, segment_id, index)).flatten()
|
|
||||||
});
|
|
||||||
optional_js(details).unchecked_into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// What was copied or cut and is waiting to be pasted, `undefined` if nothing: the kind of the
|
/// What was copied or cut and is waiting to be pasted, `undefined` if nothing: the kind of the
|
||||||
/// elements and their ids (UUID strings).
|
/// elements and their ids (UUID strings).
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
|||||||
@@ -59,14 +59,6 @@ export interface WaypointDetails {
|
|||||||
links?: { href: string; text?: string }[];
|
links?: { href: string; text?: string }[];
|
||||||
sym?: string;
|
sym?: string;
|
||||||
}
|
}
|
||||||
/** The position, elevation and time of a trackpoint. */
|
|
||||||
export interface TrackpointDetails {
|
|
||||||
lng: number;
|
|
||||||
lat: number;
|
|
||||||
ele: number;
|
|
||||||
/** ms since epoch */
|
|
||||||
time?: number;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* A trackpoint of the selection: what the statistics buffers do not hold for each trackpoint.
|
* A trackpoint of the selection: what the statistics buffers do not hold for each trackpoint.
|
||||||
* Absent fields are unknown.
|
* Absent fields are unknown.
|
||||||
@@ -189,8 +181,6 @@ extern "C" {
|
|||||||
pub type Selection;
|
pub type Selection;
|
||||||
#[wasm_bindgen(typescript_type = "WaypointDetails | undefined")]
|
#[wasm_bindgen(typescript_type = "WaypointDetails | undefined")]
|
||||||
pub type WaypointDetails;
|
pub type WaypointDetails;
|
||||||
#[wasm_bindgen(typescript_type = "TrackpointDetails | undefined")]
|
|
||||||
pub type TrackpointDetails;
|
|
||||||
#[wasm_bindgen(typescript_type = "SelectionPoint | undefined")]
|
#[wasm_bindgen(typescript_type = "SelectionPoint | undefined")]
|
||||||
pub type SelectionPoint;
|
pub type SelectionPoint;
|
||||||
#[wasm_bindgen(typescript_type = "MoveTarget")]
|
#[wasm_bindgen(typescript_type = "MoveTarget")]
|
||||||
|
|||||||
@@ -159,8 +159,6 @@ export async function createTauriBackend(): Promise<Backend> {
|
|||||||
(await invoke('file_statistics', { fileId })) ?? undefined,
|
(await invoke('file_statistics', { fileId })) ?? undefined,
|
||||||
waypoint: async (fileId, waypointId) =>
|
waypoint: async (fileId, waypointId) =>
|
||||||
(await invoke('waypoint', { fileId, waypointId })) ?? undefined,
|
(await invoke('waypoint', { fileId, waypointId })) ?? undefined,
|
||||||
trackpoint: async (fileId, segmentId, index) =>
|
|
||||||
(await invoke('trackpoint', { fileId, segmentId, index })) ?? undefined,
|
|
||||||
export_file: async (fileId, time, hr, cad, atemp, power, osm) => {
|
export_file: async (fileId, time, hr, cad, atemp, power, osm) => {
|
||||||
const file = await optionalArray('export_file', Uint8Array, {
|
const file = await optionalArray('export_file', Uint8Array, {
|
||||||
fileId,
|
fileId,
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import type {
|
|||||||
Selection,
|
Selection,
|
||||||
SelectionPoint,
|
SelectionPoint,
|
||||||
StorageOpened,
|
StorageOpened,
|
||||||
TrackpointDetails,
|
|
||||||
WaypointDetails,
|
WaypointDetails,
|
||||||
} from 'gpx-wasm';
|
} from 'gpx-wasm';
|
||||||
import type { ExportOptions, MergeType, SelectMode, SplitType } from '../types';
|
import type { ExportOptions, MergeType, SelectMode, SplitType } from '../types';
|
||||||
@@ -266,11 +265,6 @@ export interface Backend {
|
|||||||
file_structure(fileId: string): Promise<FileStructure | undefined>;
|
file_structure(fileId: string): Promise<FileStructure | undefined>;
|
||||||
file_statistics(fileId: string): Promise<GlobalStatistics | undefined>;
|
file_statistics(fileId: string): Promise<GlobalStatistics | undefined>;
|
||||||
waypoint(fileId: string, waypointId: string): Promise<WaypointDetails | undefined>;
|
waypoint(fileId: string, waypointId: string): Promise<WaypointDetails | undefined>;
|
||||||
trackpoint(
|
|
||||||
fileId: string,
|
|
||||||
segmentId: string,
|
|
||||||
index: number
|
|
||||||
): Promise<TrackpointDetails | undefined>;
|
|
||||||
/** A file as GPX (UTF-8 bytes), `undefined` if it does not exist. */
|
/** A file as GPX (UTF-8 bytes), `undefined` if it does not exist. */
|
||||||
export_file(
|
export_file(
|
||||||
fileId: string,
|
fileId: string,
|
||||||
|
|||||||
@@ -123,7 +123,6 @@ export async function createWasmBackend(): Promise<Backend> {
|
|||||||
file_structure: lift(w.file_structure),
|
file_structure: lift(w.file_structure),
|
||||||
file_statistics: lift(w.file_statistics),
|
file_statistics: lift(w.file_statistics),
|
||||||
waypoint: lift(w.waypoint),
|
waypoint: lift(w.waypoint),
|
||||||
trackpoint: lift(w.trackpoint),
|
|
||||||
// a copy out of the memory of the engine, so a plain ArrayBuffer
|
// a copy out of the memory of the engine, so a plain ArrayBuffer
|
||||||
export_file: lift(
|
export_file: lift(
|
||||||
(...args: Parameters<Backend['export_file']>) =>
|
(...args: Parameters<Backend['export_file']>) =>
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import {
|
|||||||
type FolderEntry,
|
type FolderEntry,
|
||||||
type UnsavedChoice,
|
type UnsavedChoice,
|
||||||
type WorkspaceState,
|
type WorkspaceState,
|
||||||
type TrackpointDetails,
|
|
||||||
type WaypointDetails,
|
type WaypointDetails,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
@@ -881,15 +880,6 @@ class Engine {
|
|||||||
return this.read((b) => b.waypoint(fileId, waypointId), undefined);
|
return this.read((b) => b.waypoint(fileId, waypointId), undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A trackpoint of a segment, `undefined` if it does not exist. */
|
|
||||||
trackpoint(
|
|
||||||
fileId: string,
|
|
||||||
segmentId: string,
|
|
||||||
index: number
|
|
||||||
): Promise<TrackpointDetails | undefined> {
|
|
||||||
return this.read((b) => b.trackpoint(fileId, segmentId, index), undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A file as GPX (UTF-8 bytes), `undefined` if it does not exist. The options say which data of the
|
* A file as GPX (UTF-8 bytes), `undefined` if it does not exist. The options say which data of the
|
||||||
* trackpoints to keep.
|
* trackpoints to keep.
|
||||||
@@ -935,17 +925,6 @@ class Engine {
|
|||||||
return this.read((b) => b.reduction_distances(), new Float64Array());
|
return this.read((b) => b.reduction_distances(), new Float64Array());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Coordinates, as flat [lng, lat, ...] arrays: copies.
|
|
||||||
// Refetch them when the `rev` of the segment (or the `waypointsRev` of the file) changed.
|
|
||||||
|
|
||||||
segmentCoordinates(segmentId: string): Promise<Float64Array> {
|
|
||||||
return this.read((b) => b.segment_coordinates(segmentId), new Float64Array());
|
|
||||||
}
|
|
||||||
|
|
||||||
waypointCoordinates(fileId: string): Promise<Float64Array> {
|
|
||||||
return this.read((b) => b.waypoint_coordinates(fileId), new Float64Array());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a consumer of the statistics that needs some of the metrics that are not part of
|
* Registers a consumer of the statistics that needs some of the metrics that are not part of
|
||||||
* them by default (see `StatisticsMetric`). The metrics asked for by all the consumers are
|
* them by default (see `StatisticsMetric`). The metrics asked for by all the consumers are
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
hasSelectionWithin,
|
hasSelectionWithin,
|
||||||
isCovered,
|
isCovered,
|
||||||
isInClipboard,
|
isInClipboard,
|
||||||
isEmpty,
|
|
||||||
isSelected,
|
isSelected,
|
||||||
isSelectionHidden,
|
isSelectionHidden,
|
||||||
selectedElementIds,
|
selectedElementIds,
|
||||||
@@ -68,12 +67,6 @@ describe('selection helpers', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tells whether the selection is empty', () => {
|
|
||||||
assert.equal(isEmpty(empty), true);
|
|
||||||
assert.equal(isEmpty(files('F1')), false);
|
|
||||||
assert.equal(isEmpty(waypoints), false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('lists the files holding something selected', () => {
|
it('lists the files holding something selected', () => {
|
||||||
assert.deepEqual(selectedFileIds(empty), []);
|
assert.deepEqual(selectedFileIds(empty), []);
|
||||||
assert.deepEqual(selectedFileIds(files('F1', 'F2')), ['F1', 'F2']);
|
assert.deepEqual(selectedFileIds(files('F1', 'F2')), ['F1', 'F2']);
|
||||||
|
|||||||
@@ -65,10 +65,6 @@ export function coversSegments(selection: Selection): boolean {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isEmpty(selection: Selection): boolean {
|
|
||||||
return selection.type === 'empty';
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Ids of the files holding something selected (or selected themselves). */
|
/** Ids of the files holding something selected (or selected themselves). */
|
||||||
export function selectedFileIds(selection: Selection): string[] {
|
export function selectedFileIds(selection: Selection): string[] {
|
||||||
switch (selection.type) {
|
switch (selection.type) {
|
||||||
|
|||||||
@@ -3,52 +3,30 @@ import assert from 'node:assert/strict';
|
|||||||
import {
|
import {
|
||||||
categoryIntervals,
|
categoryIntervals,
|
||||||
categoryValue,
|
categoryValue,
|
||||||
categoryValues,
|
|
||||||
intervalAt,
|
intervalAt,
|
||||||
type CategoryIntervals,
|
type CategoryIntervals,
|
||||||
} from '$lib/engine/trackpoint-categories';
|
} from '$lib/engine/trackpoint-categories';
|
||||||
|
|
||||||
describe('categoryValues', () => {
|
/** The value of each of the `length` trackpoints, to compare with what is expected. */
|
||||||
// asphalt, asphalt, unknown, gravel, gravel, gravel, unknown
|
function categoryValues(
|
||||||
const intervals: CategoryIntervals = {
|
intervals: CategoryIntervals | undefined,
|
||||||
starts: new Uint32Array([0, 2, 3, 6]),
|
length: number
|
||||||
values: new Uint8Array([1, 0, 2, 0]),
|
): (string | undefined)[] {
|
||||||
names: ['asphalt', 'gravel'],
|
const result: (string | undefined)[] = new Array(length).fill(undefined);
|
||||||
};
|
if (!intervals) {
|
||||||
|
return result;
|
||||||
it('is the name of the value of the interval of each trackpoint', () => {
|
}
|
||||||
assert.deepEqual(categoryValues(intervals, 7), [
|
const { starts, values, names } = intervals;
|
||||||
'asphalt',
|
for (let i = 0; i < starts.length; i++) {
|
||||||
'asphalt',
|
if (!values[i]) {
|
||||||
undefined,
|
continue; // unknown, already `undefined`
|
||||||
'gravel',
|
}
|
||||||
'gravel',
|
const name = names[values[i] - 1];
|
||||||
'gravel',
|
const end = i + 1 < starts.length ? Math.min(starts[i + 1], length) : length;
|
||||||
undefined,
|
result.fill(name, starts[i], end);
|
||||||
]);
|
}
|
||||||
});
|
return result;
|
||||||
|
}
|
||||||
it('goes on with the last interval until the last trackpoint', () => {
|
|
||||||
const last = { ...intervals, values: new Uint8Array([1, 0, 2, 2]) };
|
|
||||||
assert.deepEqual(categoryValues(last, 9).slice(5), [
|
|
||||||
'gravel',
|
|
||||||
'gravel',
|
|
||||||
'gravel',
|
|
||||||
'gravel',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not go past the trackpoints', () => {
|
|
||||||
assert.deepEqual(categoryValues(intervals, 3), ['asphalt', 'asphalt', undefined]);
|
|
||||||
assert.deepEqual(categoryValues(intervals, 0), []);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('is undefined without intervals, or for a code without name', () => {
|
|
||||||
assert.deepEqual(categoryValues(undefined, 2), [undefined, undefined]);
|
|
||||||
const unnamed = { starts: new Uint32Array([0]), values: new Uint8Array([3]), names: [] };
|
|
||||||
assert.deepEqual(categoryValues(unnamed, 2), [undefined, undefined]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('categoryIntervals', () => {
|
describe('categoryIntervals', () => {
|
||||||
it('groups the trackpoints that share a value', () => {
|
it('groups the trackpoints that share a value', () => {
|
||||||
|
|||||||
@@ -11,31 +11,6 @@ export type CategoryIntervals = {
|
|||||||
names: string[];
|
names: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* The value of each of the `length` trackpoints for a category of the engine, `undefined` when it
|
|
||||||
* is unknown, or when the category is missing (it is unknown for every trackpoint). The intervals
|
|
||||||
* are scanned once, so it takes a time linear in `length`.
|
|
||||||
*/
|
|
||||||
export function categoryValues(
|
|
||||||
intervals: CategoryIntervals | undefined,
|
|
||||||
length: number
|
|
||||||
): (string | undefined)[] {
|
|
||||||
const result: (string | undefined)[] = new Array(length).fill(undefined);
|
|
||||||
if (!intervals) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
const { starts, values, names } = intervals;
|
|
||||||
for (let i = 0; i < starts.length; i++) {
|
|
||||||
if (!values[i]) {
|
|
||||||
continue; // unknown, already `undefined`
|
|
||||||
}
|
|
||||||
const name = names[values[i] - 1];
|
|
||||||
const end = i + 1 < starts.length ? Math.min(starts[i + 1], length) : length;
|
|
||||||
result.fill(name, starts[i], end);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The index of the interval of `starts` (sorted) that the trackpoint `index` is in, -1 if none. */
|
/** The index of the interval of `starts` (sorted) that the trackpoint `index` is in, -1 if none. */
|
||||||
export function intervalAt(starts: Uint32Array, index: number): number {
|
export function intervalAt(starts: Uint32Array, index: number): number {
|
||||||
let low = 0;
|
let low = 0;
|
||||||
@@ -66,7 +41,7 @@ export function categoryValue(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The intervals of the trackpoints that share a value, for a value per trackpoint (`undefined`
|
* The intervals of the trackpoints that share a value, for a value per trackpoint (`undefined`
|
||||||
* when unknown): the inverse of `categoryValues`. The names are in the order of their first
|
* when unknown). The names are in the order of their first
|
||||||
* appearance. A value that is unknown everywhere gives no intervals.
|
* appearance. A value that is unknown everywhere gives no intervals.
|
||||||
*/
|
*/
|
||||||
export function categoryIntervals(values: readonly (string | undefined)[]): CategoryIntervals {
|
export function categoryIntervals(values: readonly (string | undefined)[]): CategoryIntervals {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ export type { FileStatus, FolderEntry, UnsavedChoice, WorkspaceState } from './b
|
|||||||
export type {
|
export type {
|
||||||
Clipboard,
|
Clipboard,
|
||||||
WaypointDetails,
|
WaypointDetails,
|
||||||
TrackpointDetails,
|
|
||||||
MoveTarget,
|
MoveTarget,
|
||||||
GlobalStatistics,
|
GlobalStatistics,
|
||||||
SelectionPoint,
|
SelectionPoint,
|
||||||
|
|||||||
Reference in new issue
Block a user