@pond-ts/fit 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3254 -0
- package/LICENSE +21 -0
- package/README.md +229 -0
- package/dist/activity/index.d.ts +254 -0
- package/dist/activity/index.js +652 -0
- package/dist/cjs-fallback.cjs +15 -0
- package/dist/geo/index.d.ts +358 -0
- package/dist/geo/index.js +864 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +18 -0
- package/dist/intervals.d.ts +10 -0
- package/dist/intervals.js +17 -0
- package/dist/power/index.d.ts +126 -0
- package/dist/power/index.js +279 -0
- package/dist/profile/index.d.ts +125 -0
- package/dist/profile/index.js +217 -0
- package/dist/quantities.d.ts +108 -0
- package/dist/quantities.js +207 -0
- package/dist/summary/index.d.ts +138 -0
- package/dist/summary/index.js +450 -0
- package/dist/track/index.d.ts +44 -0
- package/dist/track/index.js +65 -0
- package/dist/types.d.ts +96 -0
- package/dist/types.js +10 -0
- package/dist/units.d.ts +41 -0
- package/dist/units.js +69 -0
- package/dist/zones/index.d.ts +32 -0
- package/dist/zones/index.js +61 -0
- package/package.json +46 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Geospatial operators on a pond-ts `TimeSeries` — the geo layer of
|
|
3
|
+
* `@pond-ts/fit`. The thesis: a GPS track is already a time-keyed series of
|
|
4
|
+
* `number` columns, so the geospatial value lives in operators over those
|
|
5
|
+
* columns, not in a new storage primitive.
|
|
6
|
+
*
|
|
7
|
+
* Built strictly on pond's PUBLIC surface: two `number` columns for lat/lng,
|
|
8
|
+
* `column(name).toFloat64Array()` for zero-copy reads, and column reductions.
|
|
9
|
+
* Two places reach past what pond expresses directly today:
|
|
10
|
+
* - Scalar / plain-array results are computed over the raw typed arrays rather
|
|
11
|
+
* than attached back as derived columns — a deliberate choice (no row
|
|
12
|
+
* rebuild). Where a derived column IS wanted, pond's `withColumn` covers it.
|
|
13
|
+
* - Distance-axis aggregation: value-axis histograms (zones / distribution)
|
|
14
|
+
* are pond-native via `byColumn`, but per-interval *splits* (many metrics
|
|
15
|
+
* per distance bucket) and contiguous-run segmentation still walk the arrays
|
|
16
|
+
* — candidate pond primitives (a multi-metric value-axis aggregate; a
|
|
17
|
+
* `scan` / run-length family). See `splitsByDistance` / `segmentsInRange`.
|
|
18
|
+
*/
|
|
19
|
+
import { TimeSeries } from 'pond-ts';
|
|
20
|
+
/**
|
|
21
|
+
* The canonical activity schema: time key + lat/lng, with every other per-sample
|
|
22
|
+
* channel optional (present iff the source recorded it). This is the single
|
|
23
|
+
* source the compute layer reads — the "consume the series directly" seam:
|
|
24
|
+
* power/cadence/temp live IN the series alongside ele/hr, not as orphaned
|
|
25
|
+
* parallel arrays.
|
|
26
|
+
*/
|
|
27
|
+
export declare const TRACK_SCHEMA: readonly [{
|
|
28
|
+
readonly name: "time";
|
|
29
|
+
readonly kind: "time";
|
|
30
|
+
}, {
|
|
31
|
+
readonly name: "lat";
|
|
32
|
+
readonly kind: "number";
|
|
33
|
+
readonly required: false;
|
|
34
|
+
}, {
|
|
35
|
+
readonly name: "lng";
|
|
36
|
+
readonly kind: "number";
|
|
37
|
+
readonly required: false;
|
|
38
|
+
}, {
|
|
39
|
+
readonly name: "ele";
|
|
40
|
+
readonly kind: "number";
|
|
41
|
+
readonly required: false;
|
|
42
|
+
}, {
|
|
43
|
+
readonly name: "hr";
|
|
44
|
+
readonly kind: "number";
|
|
45
|
+
readonly required: false;
|
|
46
|
+
}, {
|
|
47
|
+
readonly name: "power";
|
|
48
|
+
readonly kind: "number";
|
|
49
|
+
readonly required: false;
|
|
50
|
+
}, {
|
|
51
|
+
readonly name: "cadence";
|
|
52
|
+
readonly kind: "number";
|
|
53
|
+
readonly required: false;
|
|
54
|
+
}, {
|
|
55
|
+
readonly name: "temp";
|
|
56
|
+
readonly kind: "number";
|
|
57
|
+
readonly required: false;
|
|
58
|
+
}, {
|
|
59
|
+
readonly name: "distance";
|
|
60
|
+
readonly kind: "number";
|
|
61
|
+
readonly required: false;
|
|
62
|
+
}];
|
|
63
|
+
export type TrackSeries = TimeSeries<typeof TRACK_SCHEMA>;
|
|
64
|
+
/**
|
|
65
|
+
* One sample as a tuple matching {@link TRACK_SCHEMA}. Every channel is optional
|
|
66
|
+
* — including lat/lng, absent for a GPS-less indoor activity (the series is then
|
|
67
|
+
* just time + the recorded channels). Absent values are `undefined`: the
|
|
68
|
+
* constructor accepts `undefined` for `required: false` columns and records it in
|
|
69
|
+
* the validity bitmap (lossless); as of pond 0.29 `RowForSchema` honors
|
|
70
|
+
* `required: false` so the row type admits it too. It rejects `null` and `NaN`.
|
|
71
|
+
*/
|
|
72
|
+
export type TrackPoint = [
|
|
73
|
+
timeMs: number,
|
|
74
|
+
lat: number | undefined,
|
|
75
|
+
lng: number | undefined,
|
|
76
|
+
ele: number | undefined,
|
|
77
|
+
hr: number | undefined,
|
|
78
|
+
power: number | undefined,
|
|
79
|
+
cadence: number | undefined,
|
|
80
|
+
temp: number | undefined,
|
|
81
|
+
distance: number | undefined
|
|
82
|
+
];
|
|
83
|
+
/** Build a pond track from parallel sample tuples (already time-sorted). */
|
|
84
|
+
export declare function buildTrack(name: string, points: ReadonlyArray<TrackPoint>): TrackSeries;
|
|
85
|
+
/**
|
|
86
|
+
* The raw typed-array columns of an activity — the zero-copy read path the whole
|
|
87
|
+
* compute layer reads from. `lat`/`lng` are present only for a GPS activity; the
|
|
88
|
+
* other channels are present iff the source recorded them (missing cells are
|
|
89
|
+
* NaN). Optional channels are absent from the object when the source had none.
|
|
90
|
+
*/
|
|
91
|
+
export interface TrackColumns {
|
|
92
|
+
/** Positions — present (length n) for a GPS activity, EMPTY for a GPS-less one
|
|
93
|
+
* (the `cols.lat.length` hasTrack signal). */
|
|
94
|
+
lat: Float64Array;
|
|
95
|
+
lng: Float64Array;
|
|
96
|
+
ele: Float64Array;
|
|
97
|
+
/** Absolute sample times in seconds (key column, ms → s). */
|
|
98
|
+
timeSec: Float64Array;
|
|
99
|
+
hr?: Float64Array;
|
|
100
|
+
power?: Float64Array;
|
|
101
|
+
cadence?: Float64Array;
|
|
102
|
+
temp?: Float64Array;
|
|
103
|
+
/** Device-recorded cumulative distance (m); present iff the source carried it
|
|
104
|
+
* (a GPS-less ride's distance axis). */
|
|
105
|
+
distance?: Float64Array;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Read a track's columns as `Float64Array`s. lat/lng off the packed value
|
|
109
|
+
* columns (required — never missing); the time axis off the key column via
|
|
110
|
+
* `keyColumn().begin` (a `Float64Array` of ms-since-epoch). Optional channels
|
|
111
|
+
* are read validity-aware and included only when the column carried any value.
|
|
112
|
+
*/
|
|
113
|
+
export declare function readColumns(track: TrackSeries): TrackColumns;
|
|
114
|
+
/** Great-circle distance between two WGS84 points, in metres. */
|
|
115
|
+
export declare function haversineMeters(lat1: number, lng1: number, lat2: number, lng2: number): number;
|
|
116
|
+
/** Per-step distances (step[0] = 0), in metres. */
|
|
117
|
+
export declare function stepDistances(lat: Float64Array, lng: Float64Array): Float64Array;
|
|
118
|
+
/** Running total of a per-step series (cumulative[0] = step[0]). */
|
|
119
|
+
export declare function cumulative(step: Float64Array): Float64Array;
|
|
120
|
+
/** Total track distance, in metres. */
|
|
121
|
+
export declare function totalDistanceMeters(lat: Float64Array, lng: Float64Array): number;
|
|
122
|
+
/**
|
|
123
|
+
* Cumulative elevation gain/loss with a hysteresis threshold to reject the
|
|
124
|
+
* metre-scale jitter in barometric/GPS elevation. We only commit a move once it
|
|
125
|
+
* exceeds `thresholdMeters` from the last committed reference — the standard way
|
|
126
|
+
* to keep noise from inflating "gain" (raw positive-diff sums overcount wildly).
|
|
127
|
+
* NaN samples (missing ele) are skipped.
|
|
128
|
+
*/
|
|
129
|
+
export declare function elevationGainLoss(ele: Float64Array, thresholdMeters?: number): {
|
|
130
|
+
gainMeters: number;
|
|
131
|
+
lossMeters: number;
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Moving time: sum of inter-sample intervals where instantaneous speed is at or
|
|
135
|
+
* above `speedThresholdMps` (default 0.5 m/s ≈ 1.8 km/h — below this you're
|
|
136
|
+
* stopped/drifting). This is what separates "moving time" from "elapsed time".
|
|
137
|
+
*/
|
|
138
|
+
export declare function movingTimeSeconds(step: Float64Array, timeSec: Float64Array, speedThresholdMps?: number): number;
|
|
139
|
+
/** Bounding box as `[[minLat, minLng], [maxLat, maxLng]]`. */
|
|
140
|
+
export declare function boundsOf(lat: Float64Array, lng: Float64Array): [[number, number], [number, number]];
|
|
141
|
+
/** A contiguous window of an activity, in cumulative distance (metres). */
|
|
142
|
+
export interface Segment {
|
|
143
|
+
startMeters: number;
|
|
144
|
+
endMeters: number;
|
|
145
|
+
}
|
|
146
|
+
/** Cumulative distance (m) at each polyline vertex; `[0] = 0`. */
|
|
147
|
+
export declare function polylineCumulative(polyline: ReadonlyArray<[number, number]>): number[];
|
|
148
|
+
/** The `[lat,lng]` point at cumulative distance `meters` along the polyline,
|
|
149
|
+
* linearly interpolated between the bracketing vertices. Clamps to the ends;
|
|
150
|
+
* non-finite `meters` resolves to the start; null for an empty polyline.
|
|
151
|
+
* `cum` may be passed to avoid recomputation — it MUST correspond to
|
|
152
|
+
* `polyline` (same length/order); a mismatch yields silently wrong results. */
|
|
153
|
+
export declare function interpolateAtDistance(polyline: ReadonlyArray<[number, number]>, meters: number, cum?: number[]): [number, number] | null;
|
|
154
|
+
/**
|
|
155
|
+
* The sub-polyline covering `[startMeters, endMeters]` of the route, with the
|
|
156
|
+
* endpoints interpolated to the exact distances (so a highlight begins and ends
|
|
157
|
+
* where the segment does, not at the nearest vertex) plus every vertex strictly
|
|
158
|
+
* between. Range is clamped to the track and normalized (start ≤ end). Returns
|
|
159
|
+
* the two interpolated endpoints for a zero-length range, `[]` for an empty
|
|
160
|
+
* polyline.
|
|
161
|
+
*
|
|
162
|
+
* `opts.domainTotal` is the length of the ruler `start`/`end` are measured in
|
|
163
|
+
* when that differs from this polyline's own length — laps come in FIT
|
|
164
|
+
* odometer metres and splits in raw-track haversine metres, but the polyline is
|
|
165
|
+
* Douglas–Peucker-simplified and a fraction shorter, so feeding those metres in
|
|
166
|
+
* raw would drift the highlight (≈1 km late on a 180 km ride). Given
|
|
167
|
+
* `domainTotal`, the window is rescaled proportionally onto the polyline so the
|
|
168
|
+
* same FRACTION of the route is sliced. `opts.cum`, if passed, MUST correspond
|
|
169
|
+
* to `polyline`.
|
|
170
|
+
*/
|
|
171
|
+
export declare function polylineSlice(polyline: ReadonlyArray<[number, number]>, startMeters: number, endMeters: number, opts?: {
|
|
172
|
+
domainTotal?: number;
|
|
173
|
+
cum?: number[];
|
|
174
|
+
}): Array<[number, number]>;
|
|
175
|
+
/**
|
|
176
|
+
* Bounding box via pond's column min/max reductions — the pond-native path,
|
|
177
|
+
* over the public column API.
|
|
178
|
+
*/
|
|
179
|
+
export declare function boundsViaPond(track: TrackSeries): [[number, number], [number, number]];
|
|
180
|
+
/**
|
|
181
|
+
* Douglas–Peucker polyline simplification with a metre tolerance, for the map
|
|
182
|
+
* overview line. Returns the kept `[lat, lng]` points (endpoints always kept).
|
|
183
|
+
* Perpendicular distance is approximated in a local equirectangular projection
|
|
184
|
+
* (fine at track scale; we are not a projection engine — RFC §6 non-goals).
|
|
185
|
+
*/
|
|
186
|
+
export declare function simplify(points: ReadonlyArray<[number, number]>, toleranceMeters: number): Array<[number, number]>;
|
|
187
|
+
/** A per-interval split (the per-km/per-mile row). */
|
|
188
|
+
export interface Split {
|
|
189
|
+
/** 1-based split index. */
|
|
190
|
+
index: number;
|
|
191
|
+
/** Distance covered in this split, metres (the last split may be short). */
|
|
192
|
+
distanceMeters: number;
|
|
193
|
+
/** Elapsed seconds within the split. */
|
|
194
|
+
durationSeconds: number;
|
|
195
|
+
/** Elevation gain within the split, metres. */
|
|
196
|
+
elevationGainMeters: number;
|
|
197
|
+
/** Elevation loss within the split, metres (same ±3 m hysteresis as gain,
|
|
198
|
+
* reference carried across split boundaries). */
|
|
199
|
+
elevationLossMeters: number;
|
|
200
|
+
/** Normalized power over the split, watts — present only with a power meter
|
|
201
|
+
* (caller passes the 30 s-rolled power; see `splitsByDistance`). */
|
|
202
|
+
normalizedWatts?: number | undefined;
|
|
203
|
+
/** Per-split channel aggregates (mean of finite samples; max of finite
|
|
204
|
+
* samples) — present only when the matching stream is supplied to
|
|
205
|
+
* `splitsByDistance` via `extras`. Speed is m/s. */
|
|
206
|
+
avgHeartrate?: number | undefined;
|
|
207
|
+
maxHeartrate?: number | undefined;
|
|
208
|
+
avgWatts?: number | undefined;
|
|
209
|
+
maxWatts?: number | undefined;
|
|
210
|
+
avgCadence?: number | undefined;
|
|
211
|
+
avgSpeedMps?: number | undefined;
|
|
212
|
+
maxSpeedMps?: number | undefined;
|
|
213
|
+
}
|
|
214
|
+
/** Optional per-sample channels for `splitsByDistance` to aggregate per split
|
|
215
|
+
* (avg = mean of finite samples, max = max finite). All aligned to `step`. */
|
|
216
|
+
export interface SplitExtras {
|
|
217
|
+
heartrate?: Float64Array | undefined;
|
|
218
|
+
watts?: Float64Array | undefined;
|
|
219
|
+
cadence?: Float64Array | undefined;
|
|
220
|
+
/** Derived instantaneous speed (m/s); index 0 is typically NaN. */
|
|
221
|
+
speed?: Float64Array | undefined;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Per-interval splits over the DISTANCE axis (per-km, per-mile). A split is a
|
|
225
|
+
* bucket over *cumulative distance* (a derived, monotonic, non-key column) that
|
|
226
|
+
* carries MANY metrics per bucket — time, elevation gain/loss, NP, and avg/max
|
|
227
|
+
* of arbitrary extra channels. `byColumn` bins a single reducer over a value
|
|
228
|
+
* column; this multi-metric-per-bucket shape isn't a single `byColumn` call, so
|
|
229
|
+
* it walks the arrays here. A multi-metric value-axis aggregate is a candidate
|
|
230
|
+
* pond primitive.
|
|
231
|
+
*/
|
|
232
|
+
export declare function splitsByDistance(step: Float64Array, timeSec: Float64Array, ele: Float64Array, intervalMeters?: number,
|
|
233
|
+
/** Optional 30 s-rolled power (NP smoothing) aligned to the samples; when
|
|
234
|
+
* given, each split gets `normalizedWatts = (mean of rolled^4)^¼`. */
|
|
235
|
+
npRolled?: Float64Array,
|
|
236
|
+
/** Optional raw channels to aggregate per split (avg + max). See {@link SplitExtras}. */
|
|
237
|
+
extras?: SplitExtras): Split[];
|
|
238
|
+
/** A point on the elevation-vs-distance profile. */
|
|
239
|
+
export interface ProfilePoint {
|
|
240
|
+
distanceMeters: number;
|
|
241
|
+
elevationMeters: number;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* The elevation-vs-distance profile, resampled onto an even distance grid
|
|
245
|
+
* (distance-domain, not time). We average elevation within each distance bucket.
|
|
246
|
+
* Used for the profile chart and as the downsample for drawing.
|
|
247
|
+
*/
|
|
248
|
+
export declare function elevationProfile(cumDist: Float64Array, ele: Float64Array, bucketMeters?: number): ProfilePoint[];
|
|
249
|
+
/** A `(distance, value)` sample on a distance-domain channel profile. */
|
|
250
|
+
export interface ProfileSample {
|
|
251
|
+
distanceMeters: number;
|
|
252
|
+
/** Median of the raw samples in the bucket — robust to anomalies. */
|
|
253
|
+
value: number;
|
|
254
|
+
/** Outer band edge (low) — a low percentile, not the raw min. NaN if empty. */
|
|
255
|
+
bandLo: number;
|
|
256
|
+
/** Outer band edge (high) — a high percentile, not the raw max. */
|
|
257
|
+
bandHi: number;
|
|
258
|
+
/** Inner band edge (low) — the 25th percentile (the typical-range floor). */
|
|
259
|
+
innerLo: number;
|
|
260
|
+
/** Inner band edge (high) — the 75th percentile (the typical-range ceiling). */
|
|
261
|
+
innerHi: number;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Resample ANY per-sample channel (elevation, hr, power, cadence, speed, …)
|
|
265
|
+
* onto an even distance grid — the generalization of {@link elevationProfile}
|
|
266
|
+
* to any value column. Per bucket: `value` is the **median** (robust), and
|
|
267
|
+
* `bandLo`/`bandHi` are the central-90% **percentiles** (not raw min/max), so
|
|
268
|
+
* a single anomalous sample can't set the band or the chart scale. `NaN`
|
|
269
|
+
* (missing) samples are skipped; the last bucket carries forward so the line
|
|
270
|
+
* stays continuous. Distance-domain bucketing of a value array — like the
|
|
271
|
+
* `byColumn` histograms, but emitting a median + percentile band per bucket.
|
|
272
|
+
*/
|
|
273
|
+
export declare function profileByDistance(cumDist: Float64Array, values: Float64Array, bucketMeters?: number): ProfileSample[];
|
|
274
|
+
/**
|
|
275
|
+
* Like {@link profileByDistance} but buckets ONLY the samples whose cumulative
|
|
276
|
+
* distance falls in `[startMeters, endMeters]`, at `bucketMeters` resolution.
|
|
277
|
+
* Returned `distanceMeters` are absolute (offset by `startMeters`), so the
|
|
278
|
+
* output drops straight into the same distance axis as the full-activity
|
|
279
|
+
* profile. This is what lets the chart reveal fine detail when zoomed to a
|
|
280
|
+
* locked split/lap — the bucket can be far finer than the whole-activity grid
|
|
281
|
+
* (e.g. ~10 m vs 100 m) without paying to re-bucket the entire track. Buckets
|
|
282
|
+
* here are aligned to `startMeters`, an independent grid from profileByDistance.
|
|
283
|
+
*/
|
|
284
|
+
export declare function profileByDistanceWindow(cumDist: Float64Array, values: Float64Array, startMeters: number, endMeters: number, bucketMeters?: number): ProfileSample[];
|
|
285
|
+
/** Percentile spread of the raw samples around a point — the variance band. */
|
|
286
|
+
export interface Spread {
|
|
287
|
+
/** Outer envelope (p5..p95) — the full excursions. NaN if no samples. */
|
|
288
|
+
bandLo: number;
|
|
289
|
+
bandHi: number;
|
|
290
|
+
/** Inner band (p25..p75) — the dense typical range. */
|
|
291
|
+
innerLo: number;
|
|
292
|
+
innerHi: number;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Rolling percentile spread of a raw per-sample channel, evaluated at each
|
|
296
|
+
* `distance` over a FIXED ±`radiusMeters` window of the raw samples — NOT the
|
|
297
|
+
* chart's buckets. This is what makes the variance underlay zoom-stable: the
|
|
298
|
+
* band measures the same real span of churn whether the chart is bucketed at
|
|
299
|
+
* 100 m (whole ride) or 10 m (a locked split), so it blooms where effort was
|
|
300
|
+
* genuinely punchy and pinches where steady, identically at every zoom. The
|
|
301
|
+
* within-bucket percentiles in {@link profileByDistance} can't do this — their
|
|
302
|
+
* width scales with bucket duration.
|
|
303
|
+
*
|
|
304
|
+
* pond 0.30's `rollingByColumn('dist', { radius, at: distances }, …)` owns the
|
|
305
|
+
* whole thing: the raw samples are the rows, and `at` evaluates the ±radius
|
|
306
|
+
* window + the four percentiles at each chart-grid center directly (one record
|
|
307
|
+
* per center) — no interleave, no read-back bookkeeping. `cum` and `distances`
|
|
308
|
+
* must both ascend (rollingByColumn enforces it). The `{ at }` option (added in
|
|
309
|
+
* pond 0.30) evaluates the window at each grid center directly.
|
|
310
|
+
*/
|
|
311
|
+
export declare function rollingSpread(cumDist: Float64Array, values: Float64Array, distances: number[], radiusMeters: number): Spread[];
|
|
312
|
+
/** Canonical distances (metres) for a run's best-efforts table: 400 m, ½ mi,
|
|
313
|
+
* 1 K, 1 mi, 2 mi, 5 K, 10 K, half, full. */
|
|
314
|
+
export declare const BEST_EFFORT_DISTANCES: number[];
|
|
315
|
+
/** A fastest-over-distance effort: the quickest time to cover `meters`. */
|
|
316
|
+
export interface DistanceEffort {
|
|
317
|
+
meters: number;
|
|
318
|
+
/** Fastest time over any window covering ≥ `meters`, seconds. */
|
|
319
|
+
seconds: number;
|
|
320
|
+
/** Mean HR over that fastest window, when an `hr` channel is supplied. */
|
|
321
|
+
avgHeartrate?: number;
|
|
322
|
+
/** Inclusive sample range of the fastest window — for focusing the chart/map
|
|
323
|
+
* on where the effort happened (maps to distance via `cumDist`). */
|
|
324
|
+
startIndex?: number;
|
|
325
|
+
endIndex?: number;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Best efforts over distance: for each target distance, the fastest time over
|
|
329
|
+
* any window covering at least that distance. The distance-axis analogue of the
|
|
330
|
+
* power curve — a two-pointer over cumulative distance keeps the window just ≥
|
|
331
|
+
* the target while minimising elapsed time, O(n) per distance. Times are clamped
|
|
332
|
+
* non-decreasing across the (ascending) distance list. Walks the arrays: it's a
|
|
333
|
+
* fastest-window search over a derived monotonic axis swept across many target
|
|
334
|
+
* distances — beyond pond's single-window `rolling` (a multi-window sweep is a
|
|
335
|
+
* candidate pond primitive). `hr` (optional) yields the mean heart rate over each
|
|
336
|
+
* fastest window.
|
|
337
|
+
* Precondition: `distances` must be ascending — the `> total` early-exit and the
|
|
338
|
+
* non-decreasing-time clamp both rely on it (`BEST_EFFORT_DISTANCES` is).
|
|
339
|
+
*/
|
|
340
|
+
export declare function bestEffortsByDistance(cumDist: Float64Array, timeSec: Float64Array, distances?: number[], hr?: Float64Array): DistanceEffort[];
|
|
341
|
+
/**
|
|
342
|
+
* The contiguous track pieces where a per-sample channel falls within
|
|
343
|
+
* `[lo, hi]` (inclusive) — the selection driver behind zone / power-distribution
|
|
344
|
+
* highlighting. A value predicate over the series yields the scattered stretches
|
|
345
|
+
* of the ride that match (e.g. "every part in the Tempo HR band"). Non-finite
|
|
346
|
+
* samples are out of range (they break a run). `cumDist` and `values` are
|
|
347
|
+
* sample-aligned. Adjacent runs separated by ≤ `bridgeMeters` of out-of-range
|
|
348
|
+
* distance merge into one (default 0 = faithful, no merge) so a momentary
|
|
349
|
+
* excursion doesn't shatter the selection into hundreds of slivers. Each run
|
|
350
|
+
* spans [cum at its first in-range sample, cum at its last]; a lone sample is a
|
|
351
|
+
* zero-length segment at its point.
|
|
352
|
+
*
|
|
353
|
+
* Run-length encoding of a predicate over a value column. pond has no
|
|
354
|
+
* contiguous-run / RLE-by-predicate primitive yet — a `scan` / segmentation
|
|
355
|
+
* family is a candidate pond primitive; until then this walks the arrays.
|
|
356
|
+
*/
|
|
357
|
+
export declare function segmentsInRange(cumDist: Float64Array, values: ArrayLike<number>, lo: number, hi: number, bridgeMeters?: number): Segment[];
|
|
358
|
+
//# sourceMappingURL=index.d.ts.map
|