mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-11-01 12:17:18 +00:00
progress
This commit is contained in:
1 parent
41b9116c6a
commit
97d597e139
181 files changed
+1970
-2643
No files matched your search
@@ -0,0 +1,33 @@
|
||||
//! The coordinates of the trackpoints and waypoints, as flat typed arrays.
|
||||
|
||||
use gpx_engine::api;
|
||||
use js_sys::Float64Array;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use crate::ids::*;
|
||||
use crate::session::*;
|
||||
|
||||
// Coordinates buffers
|
||||
//
|
||||
// Like the statistics buffers, these are copies. They are flat `[lng, lat, ...]` arrays. Compare `rev` / `waypointsRev` of the file structures with the previous ones to know which
|
||||
// buffers actually changed.
|
||||
|
||||
fn coordinates(
|
||||
id: Option<uuid::Uuid>,
|
||||
f: impl FnOnce(&gpx_engine::Engine, uuid::Uuid) -> &[f64],
|
||||
) -> Float64Array {
|
||||
id.and_then(|id| with_engine(|e| Float64Array::from(f(e, id))))
|
||||
.unwrap_or_else(|| Float64Array::new_with_length(0))
|
||||
}
|
||||
|
||||
/// Coordinates of the trackpoints of a segment (empty if the id is unknown).
|
||||
#[wasm_bindgen]
|
||||
pub fn segment_coordinates(segment_id: &str) -> Float64Array {
|
||||
coordinates(parse_uuid(segment_id), api::segment_coordinates)
|
||||
}
|
||||
|
||||
/// Coordinates of the waypoints of a file (empty if the id is unknown).
|
||||
#[wasm_bindgen]
|
||||
pub fn waypoint_coordinates(file_id: &str) -> Float64Array {
|
||||
coordinates(parse_uuid(file_id), api::waypoint_coordinates)
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
//! The files, their structure and statistics, the selection and the clipboard.
|
||||
|
||||
// File order and structures
|
||||
//
|
||||
// The files are described by one ordered list of ids and one structure object per file, so that
|
||||
// the UI can react to what changed only: after each action, the outcome tells which structures to
|
||||
// (re)read or drop and whether the order changed. Ids are UUID strings. The trackpoints of a
|
||||
// segment and the waypoints of a file are in the same order as the coordinates of their buffers
|
||||
// (see below).
|
||||
|
||||
use gpx_engine::{ExportOptions, api};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use crate::convert::*;
|
||||
use crate::ids::*;
|
||||
use crate::session::*;
|
||||
use crate::ts::*;
|
||||
|
||||
/// Ids of the files in display order.
|
||||
#[wasm_bindgen]
|
||||
pub fn file_order() -> FileOrder {
|
||||
to_js(&with_engine(api::file_order).unwrap_or_default()).unchecked_into()
|
||||
}
|
||||
|
||||
/// Structure of a file, `undefined` if the id is unknown.
|
||||
#[wasm_bindgen]
|
||||
pub fn file_structure(file_id: &str) -> FileStructure {
|
||||
let structure =
|
||||
parse_uuid(file_id).and_then(|id| with_engine(|e| api::file_structure(e, id)).flatten());
|
||||
optional_js(structure).unchecked_into()
|
||||
}
|
||||
|
||||
/// Global statistics of a file, `undefined` if the id is unknown.
|
||||
#[wasm_bindgen]
|
||||
pub fn file_statistics(file_id: &str) -> GlobalStatistics {
|
||||
let statistics =
|
||||
parse_uuid(file_id).and_then(|id| with_engine(|e| api::file_statistics(e, id)).flatten());
|
||||
optional_js(statistics).unchecked_into()
|
||||
}
|
||||
|
||||
/// Global statistics of the whole selection (the arrays of the statistics buffers cover it).
|
||||
#[wasm_bindgen]
|
||||
pub fn selection_statistics() -> GlobalStatistics {
|
||||
optional_js(with_engine(api::selection_statistics)).unchecked_into()
|
||||
}
|
||||
|
||||
/// A file as GPX (UTF-8 bytes), `undefined` if it does not exist. The options say which data of the trackpoints
|
||||
/// to keep, and with `as_route` that the segments are written as routes (`rte`) instead of tracks:
|
||||
/// the anchors are the route points, and the trackpoints between them the points of their path.
|
||||
#[wasm_bindgen]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn export_file(
|
||||
file_id: &str,
|
||||
time: bool,
|
||||
hr: bool,
|
||||
cad: bool,
|
||||
atemp: bool,
|
||||
power: bool,
|
||||
osm: bool,
|
||||
as_route: bool,
|
||||
) -> Option<Vec<u8>> {
|
||||
let id = parse_uuid(file_id)?;
|
||||
let options = ExportOptions {
|
||||
time,
|
||||
hr,
|
||||
cad,
|
||||
atemp,
|
||||
power,
|
||||
osm,
|
||||
as_route,
|
||||
};
|
||||
with_engine(|e| api::export_file(e, id, options)).flatten()
|
||||
}
|
||||
|
||||
/// The data that some files have, so that the ones that none has are not offered when exporting
|
||||
/// them: a bit for the time (1), heart rate (2), cadence (4), temperature (8), power (16) and the
|
||||
/// OpenStreetMap data (32). `file_ids` are concatenated UUIDs.
|
||||
#[wasm_bindgen]
|
||||
pub fn exportable_data(file_ids: &[u8]) -> u8 {
|
||||
let Some(ids) = uuid_list(file_ids) else {
|
||||
return 0;
|
||||
};
|
||||
with_engine(|e| api::exportable_data(e, &ids)).unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Global statistics of the trackpoints from `start` to `end` (both included) of the selection,
|
||||
/// as indexed by the statistics buffers. `undefined` when the range is not in the selection.
|
||||
#[wasm_bindgen]
|
||||
pub fn slice_statistics(start: usize, end: usize) -> GlobalStatistics {
|
||||
optional_js(with_engine(|e| api::slice_statistics(e, start, end)).flatten()).unchecked_into()
|
||||
}
|
||||
|
||||
/// The current selection (ids are UUID strings).
|
||||
#[wasm_bindgen]
|
||||
pub fn selection() -> Selection {
|
||||
to_js(&with_engine(api::selection).unwrap_or(api::Selection::Empty)).unchecked_into()
|
||||
}
|
||||
|
||||
/// All the data of a waypoint of a file, `undefined` if it does not exist.
|
||||
#[wasm_bindgen]
|
||||
pub fn waypoint(file_id: &str, waypoint_id: &str) -> WaypointDetails {
|
||||
let details = parse_uuid(file_id)
|
||||
.zip(parse_uuid(waypoint_id))
|
||||
.and_then(|(file_id, id)| with_engine(|e| api::waypoint(e, file_id, id)).flatten());
|
||||
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
|
||||
/// elements and their ids (UUID strings).
|
||||
#[wasm_bindgen]
|
||||
pub fn clipboard() -> Clipboard {
|
||||
optional_js(with_engine(api::clipboard).flatten()).unchecked_into()
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
pub(crate) mod coordinates;
|
||||
pub(crate) mod files;
|
||||
pub(crate) mod routing;
|
||||
pub(crate) mod statistics;
|
||||
@@ -0,0 +1,48 @@
|
||||
//! The anchors of the routing tool among the trackpoints of the selection.
|
||||
|
||||
use gpx_engine::api;
|
||||
use js_sys::{Uint8Array, Uint32Array};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use crate::convert::*;
|
||||
use crate::session::*;
|
||||
use crate::ts::*;
|
||||
|
||||
// Routing buffers
|
||||
//
|
||||
// The anchors of the routing tool among the trackpoints of the selection (the numbering is the one
|
||||
// of the statistics buffers). The ends of the segments are always anchors.
|
||||
|
||||
/// The index in the selection of each anchor.
|
||||
#[wasm_bindgen]
|
||||
pub fn anchor_indices() -> Uint32Array {
|
||||
with_engine(|e| Uint32Array::from(api::anchor_indices(e)))
|
||||
.unwrap_or_else(|| Uint32Array::new_with_length(0))
|
||||
}
|
||||
|
||||
/// The lowest map zoom level at which each anchor is shown.
|
||||
#[wasm_bindgen]
|
||||
pub fn anchor_zooms() -> Uint8Array {
|
||||
with_engine(|e| Uint8Array::from(api::anchor_zooms(e)))
|
||||
.unwrap_or_else(|| Uint8Array::new_with_length(0))
|
||||
}
|
||||
|
||||
/// Index in the selection of the first trackpoint of each selected segment that has some.
|
||||
#[wasm_bindgen]
|
||||
pub fn segment_starts() -> Uint32Array {
|
||||
with_engine(|e| Uint32Array::from(api::segment_starts(e)))
|
||||
.unwrap_or_else(|| Uint32Array::new_with_length(0))
|
||||
}
|
||||
|
||||
/// The id of each selected segment that has trackpoints, as `segment_starts`.
|
||||
#[wasm_bindgen]
|
||||
pub fn segment_ids() -> StringList {
|
||||
to_js(&with_engine(api::segment_ids).unwrap_or_default()).unchecked_into()
|
||||
}
|
||||
|
||||
/// Changes when the selected segments or their trackpoints change: the indices in the selection
|
||||
/// are only valid while it stays the same.
|
||||
#[wasm_bindgen]
|
||||
pub fn routing_revision() -> u32 {
|
||||
with_engine(api::routing_revision).unwrap_or_default()
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
//! The statistics of the selection, as typed arrays, and the categories they refer to.
|
||||
|
||||
use gpx_engine::api;
|
||||
use js_sys::{BigInt64Array, Float64Array, Uint8Array, Uint32Array};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use crate::convert::*;
|
||||
use crate::session::*;
|
||||
use crate::ts::*;
|
||||
|
||||
// Statistics buffers
|
||||
//
|
||||
// Each getter returns a copy of the buffer, as a new JS typed array.
|
||||
|
||||
macro_rules! stats_getter {
|
||||
($name:ident, $array:ident) => {
|
||||
#[wasm_bindgen]
|
||||
pub fn $name() -> $array {
|
||||
with_engine(|e| $array::from(api::$name(e)))
|
||||
.unwrap_or_else(|| $array::new_with_length(0))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
stats_getter!(total_distance, Float64Array);
|
||||
stats_getter!(elevation_gain, Float64Array);
|
||||
stats_getter!(elevation_loss, Float64Array);
|
||||
stats_getter!(slope, Float64Array);
|
||||
stats_getter!(slope_segment_slope, Float64Array);
|
||||
stats_getter!(slope_segment_distance, Float64Array);
|
||||
stats_getter!(lng, Float64Array);
|
||||
stats_getter!(lat, Float64Array);
|
||||
stats_getter!(ele, Float64Array);
|
||||
|
||||
// The optional values are `undefined` when no trackpoint of the selection has one, else they have
|
||||
// an entry per trackpoint, the missing ones being NaN (`NO_TIME` for the timestamps, 0 before the
|
||||
// first trackpoint that has them for the cumulative distances and durations).
|
||||
macro_rules! optional_stats_getter {
|
||||
($name:ident, $array:ident) => {
|
||||
#[wasm_bindgen]
|
||||
pub fn $name() -> Option<$array> {
|
||||
with_engine(|e| api::$name(e).map($array::from)).flatten()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
optional_stats_getter!(moving_distance, Float64Array);
|
||||
// Durations since the start of the selection, in milliseconds.
|
||||
optional_stats_getter!(total_time, BigInt64Array);
|
||||
optional_stats_getter!(moving_time, BigInt64Array);
|
||||
optional_stats_getter!(speed, Float64Array);
|
||||
// Timestamps in milliseconds since the epoch (`NO_TIME`, the smallest i64, when missing).
|
||||
optional_stats_getter!(timestamps, BigInt64Array);
|
||||
|
||||
/// Value of the timestamps of the trackpoints that have none.
|
||||
#[wasm_bindgen]
|
||||
pub fn no_time() -> i64 {
|
||||
gpx_engine::NO_TIME
|
||||
}
|
||||
|
||||
optional_stats_getter!(hr, Float64Array);
|
||||
optional_stats_getter!(cad, Float64Array);
|
||||
optional_stats_getter!(atemp, Float64Array);
|
||||
optional_stats_getter!(power, Float64Array);
|
||||
|
||||
// Surface, highway, SAC scale and MTB scale of the trackpoints, as intervals of trackpoints that
|
||||
// have the same value: `<name>_starts` holds the index of the first trackpoint of each interval,
|
||||
// and `<name>_values` its value (0 when unknown, else 1 + the index in `surfaces()`,
|
||||
// `highways()`, `sac_scales()` or `mtb_scales()`). A value that is unknown for every trackpoint is
|
||||
// a single interval.
|
||||
macro_rules! categories_getters {
|
||||
($starts:ident, $values:ident, $names:ident) => {
|
||||
#[wasm_bindgen]
|
||||
pub fn $starts() -> Uint32Array {
|
||||
with_engine(|e| Uint32Array::from(api::$starts(e)))
|
||||
.unwrap_or_else(|| Uint32Array::new_with_length(0))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn $values() -> Uint8Array {
|
||||
with_engine(|e| Uint8Array::from(api::$values(e)))
|
||||
.unwrap_or_else(|| Uint8Array::new_with_length(0))
|
||||
}
|
||||
|
||||
/// The names of the category, in the order of their codes. The list only grows: a name
|
||||
/// keeps its index.
|
||||
#[wasm_bindgen]
|
||||
pub fn $names() -> StringList {
|
||||
to_js(&with_engine(|e| api::$names(e).to_vec()).unwrap_or_default()).unchecked_into()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
categories_getters!(surface_starts, surface_values, surfaces);
|
||||
categories_getters!(highway_starts, highway_values, highways);
|
||||
categories_getters!(sac_scale_starts, sac_scale_values, sac_scales);
|
||||
categories_getters!(mtb_scale_starts, mtb_scale_values, mtb_scales);
|
||||
|
||||
/// For each trackpoint of the selection (numbered as in the statistics), the highest tolerance
|
||||
/// (m) of `reduce` that keeps it: infinite for the ends of the segments.
|
||||
#[wasm_bindgen]
|
||||
pub fn reduction_distances() -> Float64Array {
|
||||
with_engine(|e| Float64Array::from(&api::reduction_distances(e)[..]))
|
||||
.unwrap_or_else(|| Float64Array::new_with_length(0))
|
||||
}
|
||||
Reference in new issue
Block a user