Skip to content
Lucent
SEARCH LUCENT

Search guides, APIs, and examples.

GitHub

Very early and experimental. The language, the generated native code and every package API change without notice. Do not use Lucent in production.

3. Simplify the route off the JS thread

An async method that runs on the Lucent thread, and stops when JavaScript aborts it.

src/trip.lucent.ts
return 2 * EARTH_RADIUS_M * Math.asin(Math.sqrt(h));
}
/** Meters from p to the line through a and b, on a flat map around a. */
function offset(p: Fix, a: Fix, b: Fix): number {
const scale = Math.cos(radians(a.latitude)) * EARTH_RADIUS_M;
const x = (f: Fix) => radians(f.longitude - a.longitude) * scale;
const y = (f: Fix) => radians(f.latitude - a.latitude) * EARTH_RADIUS_M;
const length = Math.hypot(x(b), y(b));
if (length === 0) return Math.hypot(x(p), y(p));
return Math.abs(x(b) * y(p) - y(b) * x(p)) / length;
}
/** Meters per second from a to b. */
export function speed(a: Fix, b: Fix): number {
const seconds = (b.time - a.time) / 1000;
…
const seconds = first && last ? (last.time - first.time) / 1000 : 0;
return { fixes: this.fixes.length, meters, seconds, topSpeed };
}
/** The fixes that shape the route, within `tolerance` meters (Douglas–Peucker). */
async simplify(tolerance: number, signal: AbortSignal): Promise<Fix[]> {
const fixes = this.fixes;
if (fixes.length < 3) return [...fixes];
const keep = fixes.map((_, i) => i === 0 || i === fixes.length - 1);
const spans: [number, number][] = [[0, fixes.length - 1]];
while (spans.length > 0) {
signal.throwIfAborted();
const [first, last] = spans.pop()!;
let farthest = -1;
let farthestOffset = tolerance;
for (let i = first + 1; i < last; i++) {
const d = offset(fixes[i]!, fixes[first]!, fixes[last]!);
if (d > farthestOffset) {
farthest = i;
farthestOffset = d;
}
}
if (farthest >= 0) {
keep[farthest] = true;
spans.push([first, farthest], [farthest, last]);
}
}
return fixes.filter((_, i) => keep[i] === true);
}
}

simplify keeps the fixes that shape the route, and drops those within tolerance meters of a straight line. On a long trip that is slow work, so it's async: it runs on the Lucent thread, and the JS thread stays free.

The AbortSignal comes from an AbortController in JavaScript. When the screen goes away, controller.abort() sets the signal, and signal.throwIfAborted() stops the loop with an AbortError.

The screen shows Simplifying… for a moment, then 4 fixes shape the route.: one fix sat within 100 meters of the line through its neighbors.