diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..cb14d106
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,47 @@
+# How to contribute.
+
+## Required tools
+
+- node.js
+- npm
+- on mac-os, you have to install xcode command line developer tools (run xcode-select --install)
+- gcloud
+- docker
+- the IDE of your choice
+
+
+## Project setup
+
+- run `npm install`
+- add default keys definitions
+ - `cp apps/fxc-front/src/app/keys.ts.dist apps/fxc-front/src/app/keys.ts`
+ - `cp libs/common/src/lib/keys.ts.dist libs/common/src/lib/keys.ts`
+
+### Simplistic configuration
+
+**redis server**
+- `cd docker; docker compose up -d redis`
+
+**pubsub**
+- `cd docker; docker compose up -d pubsub`
+
+**datastore**
+
+For the moment, it does not work with docker compose. But if you install the cloud-datastore-emulator, you will have a working configuration.
+
+***Installation***
+- `gcloud components install cloud-datastore-emulator`
+
+***run:***
+- `gcloud beta emulators datastore start`
+
+**before npm run dev:**
+
+define the required env variables:
+```
+export DATASTORE_DATASET=flyxc
+export DATASTORE_EMULATOR_HOST=localhost:8081
+export DATASTORE_EMULATOR_HOST_PATH=localhost:8081/datastore
+export DATASTORE_HOST=http://localhost:8081
+export DATASTORE_PROJECT_ID=flyxc
+```
diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md
deleted file mode 100644
index 866e2604..00000000
--- a/CONTRIBUTION.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# How to contribute.
-
-## Required tools
-
-- node.js
-- npm
-- on mac-os, you have to install xcode command line developer tools (run xcode-select --install)
-- gcloud
-- docker
-- the IDE of your choice
-
-
-## Project setup
-
-- run `npm install`
-- add default keys definitions
- - `cp apps/fxc-front/src/app/keys.ts.dist apps/fxc-front/src/app/keys.ts`
- - `cp libs/common/src/lib/keys.ts.dist libs/common/src/lib/keys.ts`
-
-### Simplistic configuration
-
-**redis server**
-- docker run -ti --rm -p 6378:6379 redis
-
-For a simplistic local configuration, you can install and use gcloud local simulators for storage db and pubsup
-
-**installation:**
-- gcloud components install pubsub-emulator
-- gcloud components install cloud-datastore-emulator
-
-**run:**
-- gcloud beta emulators datastore start
-- gcloud beta emulators pubsub start
-
-**before npm run dev:**
-set environment variables given by this 2 commands
-- gcloud beta emulators datastore env-init
-- gcloud beta emulators pubsub env-init
diff --git a/apps/fxc-front/src/app/components/2d/planner-element.ts b/apps/fxc-front/src/app/components/2d/planner-element.ts
index 3760e710..4efbbd33 100644
--- a/apps/fxc-front/src/app/components/2d/planner-element.ts
+++ b/apps/fxc-front/src/app/components/2d/planner-element.ts
@@ -9,9 +9,9 @@ import * as units from '../../logic/units';
import { decrementSpeed, incrementSpeed, setSpeed } from '../../redux/planner-slice';
import { RootState, store } from '../../redux/store';
import { scoreTrack } from '../../logic/track';
-import * as common from "@flyxc/common";
-import { currentTrack } from "../../redux/selectors";
-import { LEAGUES } from "../../logic/score/league/leagues";
+// introduce here a circular dependency. Issue to solve later
+import * as common from '@flyxc/common';
+import { currentLeague, currentTrack } from '../../redux/selectors';
const ICON_MINUS =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJAQMAAADaX5RTAAAABlBMVEX///9xe4e/5menAAAAE0lEQVQImWP438DQAEP7kNj/GwCK4wo9HA2mvgAAAABJRU5ErkJggg==';
@@ -37,9 +37,7 @@ export class PlannerElement extends connect(store)(LitElement) {
@state()
private isFreeDrawing = false;
@state()
- private track?: common.RuntimeTrack;
- @state()
- private league?: string;
+ private track: common.RuntimeTrack | undefined;
private duration?: number;
private readonly closeHandler = () => this.dispatchEvent(new CustomEvent('close'));
@@ -57,7 +55,6 @@ export class PlannerElement extends connect(store)(LitElement) {
this.duration = ((this.distance / this.speed) * 60) / 1000;
this.isFreeDrawing = state.planner.isFreeDrawing;
this.track = currentTrack(state);
- this.league = LEAGUES[state.planner.league].name ;
}
static get styles(): CSSResult {
@@ -148,10 +145,11 @@ export class PlannerElement extends connect(store)(LitElement) {
${when(
this.track,
- () => html `
-
-
π Compute score π
-
`
+ () => html` `,
)}
${this.score.circuit}
@@ -160,7 +158,8 @@ export class PlannerElement extends connect(store)(LitElement) {
-
Points = ${this.getMultiplier()}
${this.league}
+
Points = ${this.getMultiplier()}
+
${store.getState().planner.leagueName}
${this.score.points.toFixed(1)}
@@ -277,9 +276,10 @@ export class PlannerElement extends connect(store)(LitElement) {
store.dispatch(e.deltaY > 0 ? incrementSpeed() : decrementSpeed());
}
- private computeScore() {
+ // compute score on the current selected track
+ private scoreTrack() {
if (this.track) {
- scoreTrack(this.track);
+ scoreTrack(this.track, currentLeague(store.getState()));
}
}
}
diff --git a/apps/fxc-front/src/app/components/ui/main-menu.ts b/apps/fxc-front/src/app/components/ui/main-menu.ts
index c1f9da2d..c58d9be4 100644
--- a/apps/fxc-front/src/app/components/ui/main-menu.ts
+++ b/apps/fxc-front/src/app/components/ui/main-menu.ts
@@ -514,8 +514,8 @@ export class TrackItems extends connect(store)(LitElement) {
pushCurrentState();
addUrlParamValues(ParamNames.groupId, ids);
el.value = '';
+ await menuController.close();
}
- await menuController.close();
}
}
diff --git a/apps/fxc-front/src/app/components/ui/track-modal.ts b/apps/fxc-front/src/app/components/ui/track-modal.ts
index 27e1a5a9..5f57eab6 100644
--- a/apps/fxc-front/src/app/components/ui/track-modal.ts
+++ b/apps/fxc-front/src/app/components/ui/track-modal.ts
@@ -37,7 +37,7 @@ export class TrackModal extends connect(store)(LitElement) {
${this.tracks.map(
(track: RuntimeTrack) =>
- html` {
if (!_solver) {
const { solver } = await import('igc-xc-score');
@@ -18,14 +20,18 @@ let _solver: (
config?: { [key: string]: any } | undefined,
) => Iterator;
+// ScoreAndWaypoints could be more appropriate here?
export type ScoreAndRoute = { score: Score; route: Point[] };
-export type ScoringTrack = { lat: number[]; lon: number[]; timeSec: number[]; minTimeSec: number };
+
+// ScoringTrack is a subset of RuntimeTrack
+// we define it for the sake of clarity and define the minimal information required to invoke the scoreTrack function
+export type ScoringTrack = Pick
export async function scoreTrack(track: ScoringTrack, leagueCode: LeagueCode): Promise {
const scoringRules = getScoringRules(leagueCode);
if (scoringRules) {
const solver = await lazyLoadedSolver();
- const solutions = solver(igcFile(track), scoringRules, undefined);
+ const solutions = solver(createIgcFile(track), scoringRules, undefined);
const solution = solutions.next().value;
return { score: toScore(solution), route: toRoute(solution) };
}
@@ -43,7 +49,6 @@ function toScore(solution: Solution): Score {
});
}
-// duplicated code from apps/fxc-front/src/app/logic/track.ts
type CircuitTypeCode = 'od' | 'tri' | 'fai' | 'oar';
function toCircuitType(code: CircuitTypeCode) {
@@ -59,36 +64,46 @@ function toCircuitType(code: CircuitTypeCode) {
}
}
-// end duplication
-
+// return indices of solution points
+// Pay attention to the high coupling between getIndexes and toRoute function.
+// They HAVE TO use the same points in the same order
+// May be a visitor pattern would be valuable here.
function getIndexes(solution: Solution) {
let currentIndex = -1;
const entryPointsStart = getEntryPointsStart(solution);
const result = entryPointsStart ? [currentIndex++] : [];
const closingPointsIn = getClosingPointsIn(solution);
- if (closingPointsIn) result.push(currentIndex++);
+ if (closingPointsIn) {
+ result.push(currentIndex++);
+ }
solution.scoreInfo?.legs?.map((leg) => leg.start.r).forEach(() => result.push(currentIndex++));
const closingPointsOut = getClosingPointsOut(solution);
- if (closingPointsOut) result.push(currentIndex++);
+ if (closingPointsOut) {
+ result.push(currentIndex++);
+ }
const entryPointsFinish = getEntryPointsFinish(solution);
- if (entryPointsFinish) result.push(currentIndex++);
+ if (entryPointsFinish) {
+ result.push(currentIndex++);
+ }
return result;
}
-function push(point: XcScorePoint | undefined, route: Point[]) {
- if (point) route.push(getPoint(point));
-}
-
function toRoute(solution: Solution): Point[] {
const route: Point[] = [];
push(getEntryPointsStart(solution), route);
const closingPointsIn = getClosingPointsIn(solution);
- if (closingPointsIn) route.push(getPoint(closingPointsIn));
+ if (closingPointsIn) {
+ route.push(getPoint(closingPointsIn));
+ }
solution.scoreInfo?.legs?.map((leg) => leg.start).forEach((it) => route.push(getPoint(it)));
const closingPointsOut = getClosingPointsOut(solution);
- if (closingPointsOut) route.push(getPoint(closingPointsOut));
+ if (closingPointsOut) {
+ route.push(getPoint(closingPointsOut));
+ }
const entryPointsFinish = getEntryPointsFinish(solution);
- if (entryPointsFinish) route.push(getPoint(entryPointsFinish));
+ if (entryPointsFinish) {
+ route.push(getPoint(entryPointsFinish));
+ }
return route;
}
@@ -112,22 +127,35 @@ function getPoint(point: XcScorePoint): Point {
return { ...point };
}
-// build a fake igc file from a track
-function igcFile(track: ScoringTrack): IGCFile {
+function push(point: XcScorePoint | undefined, route: Point[]) {
+ if (point) {
+ route.push(getPoint(point));
+ }
+}
+
+// build a fake igc file from a track, so that the solver can use it.
+function createIgcFile(track: ScoringTrack): IGCFile {
const fixes: BRecord[] = [];
for (let i = 0; i < track.lon.length; i++) {
- // @ts-ignore
+ const timeMilliseconds = track.timeSec[i]*1000;
const record: BRecord = {
- timestamp: track.timeSec[i],
+ timestamp: timeMilliseconds,
+ time: new Date(timeMilliseconds).toISOString(),
latitude: track.lat[i],
longitude: track.lon[i],
valid: true,
+ pressureAltitude: null,
+ gpsAltitude: track.alt[i],
+ extensions: {},
+ fixAccuracy: null,
+ enl: null,
};
fixes.push(record);
}
+ // we ignore some properties of the igc-file, as they are not required for the computation
// @ts-ignore
return {
- date: new Date(track.minTimeSec).toISOString(),
+ date: new Date(track.minTimeSec*1000).toISOString(),
fixes: fixes,
};
}
@@ -136,6 +164,9 @@ function getScoringRules(leagueCode: LeagueCode): object | undefined {
return leaguesScoringRules.get(leagueCode);
}
+// scoring rules could have been defined individually in each League subclass, but as the definition of rules is
+// tedious and error-prone, it seems more practical to define all rules here.
+// The downside is that we have to define a "coupling key" (LeagueCode) in each League
const scoringBaseModel = scoringRules['XContest'];
const openDistanceBase = scoringBaseModel[0];
const freeTriangleBase = scoringBaseModel[1];
@@ -216,16 +247,17 @@ const wxcScoringRule = [
{ ...faiTriangleBase, multiplier: 2, closingDistanceFixed: 0.2 },
];
-const leaguesScoringRules: Map = new Map()
- .set('czl', czlScoringRule)
- .set('cze', czeScoringRule)
- .set('czo', czoScoringRule)
- .set('fr', scoringRules['FFVL'])
- .set('leo', leoScoringRule)
- .set('nor', norScoringRule)
- .set('ukc', ukcScoringRule)
- .set('uki', ukiScoringRule)
- .set('ukn', uknScoringRule)
- .set('xc', scoringRules.XContest)
- .set('xcppg', xcppgScoringRule)
- .set('wxc', wxcScoringRule);
+const leaguesScoringRules: Map = new Map([
+ ['czl', czlScoringRule],
+ ['cze', czeScoringRule],
+ ['czo', czoScoringRule],
+ ['fr', scoringRules['FFVL']],
+ ['leo', leoScoringRule],
+ ['nor', norScoringRule],
+ ['ukc', ukcScoringRule],
+ ['uki', ukiScoringRule],
+ ['ukn', uknScoringRule],
+ ['xc', scoringRules.XContest],
+ ['xcppg', xcppgScoringRule],
+ ['wxc', wxcScoringRule],
+]);
diff --git a/apps/fxc-front/src/app/logic/score/league.ts b/apps/fxc-front/src/app/logic/score/league.ts
index dae4f084..7cd990fd 100644
--- a/apps/fxc-front/src/app/logic/score/league.ts
+++ b/apps/fxc-front/src/app/logic/score/league.ts
@@ -1,50 +1,13 @@
import { Measure } from './measure';
import { Score } from './scorer';
-import { ScoreAndRoute, scoreTrack, ScoringTrack } from './improvedScorer';
-import { LatLon } from '@flyxc/common';
export abstract class League {
abstract name: string;
abstract code: LeagueCode;
abstract score(measure: Measure): Score[];
-
- // An attempt for using the new scorer in League classes
- async scorePoints(latLons: LatLon[]): Promise {
- return await scoreTrack(toTrack(latLons), this.code);
- }
}
+// allowed league codes
+// ensure that all league codes defined in each League sub classes are in this
+// closed set.
export type LeagueCode = 'czl' | 'cze' | 'czo' | 'fr' | 'leo' | 'nor' | 'ukc' | 'uki' | 'ukn' | 'xc' | 'xcppg' | 'wxc';
-
-function toTrack(latLons: LatLon[]): ScoringTrack {
- let copy = latLons.map((it) => it);
- while (copy.length < 6) {
- copy = doublePoints(copy);
- }
- const date = new Date();
- const minTimeSec = date.getSeconds();
- date.setSeconds(1);
- return {
- lat: copy.map((it) => it.lat),
- lon: copy.map((it) => it.lon),
- timeSec: copy.map((_value, index) => minTimeSec + index),
- minTimeSec: minTimeSec,
- };
-}
-
-function doublePoints(source: LatLon[]): LatLon[] {
- const result = [];
- for (let i = 0; i < source.length - 1; i++) {
- result.push(source[i]);
- result.push(middle(source[i], source[i + 1]));
- }
- result.push(source[source.length - 1]);
- return result;
-}
-
-function middle(p1: LatLon, p2: LatLon): LatLon {
- return {
- lat: (p1.lat + p2.lat) / 2,
- lon: (p1.lon + p2.lon) / 2,
- };
-}
diff --git a/apps/fxc-front/src/app/logic/score/scorer.ts b/apps/fxc-front/src/app/logic/score/scorer.ts
index 094f98d8..c5319d68 100644
--- a/apps/fxc-front/src/app/logic/score/scorer.ts
+++ b/apps/fxc-front/src/app/logic/score/scorer.ts
@@ -22,9 +22,7 @@ export class Score {
this.indexes = score.indexes || [];
this.multiplier = score.multiplier || 1;
this.circuit = score.circuit || CircuitType.OpenDistance;
- // when score.closingRadius = 0
- // 'score.closingRadius || null' expression is ... null, because "0 is false", WTF!
- this.closingRadius = score.closingRadius != null ? score.closingRadius : null;
+ this.closingRadius = score.closingRadius ?? null;
this.points = score.points ? score.points : (this.distance * this.multiplier) / 1000;
}
}
diff --git a/apps/fxc-front/src/app/logic/track.ts b/apps/fxc-front/src/app/logic/track.ts
index 6f03437b..71f6d214 100644
--- a/apps/fxc-front/src/app/logic/track.ts
+++ b/apps/fxc-front/src/app/logic/track.ts
@@ -3,11 +3,9 @@ import { extractGroupId, Point, RuntimeTrack } from '@flyxc/common';
import { unwrapResult } from '@reduxjs/toolkit';
import { AppDispatch, store } from '../redux/store';
-import { currentLeague } from '../redux/selectors';
import { fetchTrack } from '../redux/track-slice';
// @ts-ignore
import ScoreWorker from '../workers/score-track?worker';
-import { Request as ScoreRequest } from '../workers/score-track';
import {
setEnabled as setPlannerEnabled,
setIsFreeDrawing as setPlannerIsFreeDrawing,
@@ -15,8 +13,11 @@ import {
setScore as setPlannerScore,
} from '../redux/planner-slice';
import { ScoreAndRoute } from './score/improvedScorer';
+import { LeagueCode } from "./score/league";
// Uploads files to the server and adds the tracks.
+// after loading, the planner menu is displayed to permit
+// score computation on loaded tracks
export async function uploadTracks(files: File[]): Promise {
if (files.length == 0) {
return [];
@@ -60,9 +61,8 @@ async function fetchAndReturnGroupIds(url: string, options?: RequestInit): Promi
return Array.from(groupIds);
}
-export function scoreTrack(track: RuntimeTrack) {
- const request: ScoreRequest = { track: track, leagueCode: currentLeague(store.getState()) };
- getScoreWorker(store.dispatch).postMessage(request);
+export function scoreTrack(track: RuntimeTrack, leagueCode: LeagueCode) {
+ getScoreWorker(store.dispatch).postMessage({ track, leagueCode });
}
let scoreWorker: Worker | undefined;
diff --git a/apps/fxc-front/src/app/redux/planner-slice.ts b/apps/fxc-front/src/app/redux/planner-slice.ts
index d7e8e27e..46055210 100644
--- a/apps/fxc-front/src/app/redux/planner-slice.ts
+++ b/apps/fxc-front/src/app/redux/planner-slice.ts
@@ -3,12 +3,14 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { deleteUrlParam, getUrlParamValues, ParamNames, setUrlParamValue } from '../logic/history';
import { Score } from '../logic/score/scorer';
import { LeagueCode } from '../logic/score/league';
+import { LEAGUES } from "../logic/score/league/leagues";
export type PlannerState = {
score?: Score;
speed: number;
distance: number;
league: LeagueCode;
+ leagueName: string;
enabled: boolean;
// Encoded route.
route: string;
@@ -18,11 +20,16 @@ export type PlannerState = {
const route = getUrlParamValues(ParamNames.route)[0] ?? '';
const enabled = route.length > 0;
+function getLeagueCode() {
+ return (getUrlParamValues(ParamNames.league)[0] ?? localStorage.getItem('league') ?? 'xc') as LeagueCode;
+}
+
const initialState: PlannerState = {
score: undefined,
speed: Number(getUrlParamValues(ParamNames.speed)[0] ?? 20),
distance: 0,
- league: (getUrlParamValues(ParamNames.league)[0] ?? localStorage.getItem('league') ?? 'xc') as LeagueCode,
+ league: getLeagueCode(),
+ leagueName: LEAGUES[getLeagueCode()].name,
enabled,
route,
isFreeDrawing: false,
@@ -47,6 +54,7 @@ const plannerSlice = createSlice({
setUrlParamValue(ParamNames.league, leagueCode);
localStorage.setItem('league', leagueCode);
state.league = leagueCode;
+ state.leagueName = LEAGUES[leagueCode].name;
},
incrementSpeed: (state) => {
state.speed = Math.floor(state.speed + 1);
diff --git a/apps/fxc-front/src/app/redux/track-slice.ts b/apps/fxc-front/src/app/redux/track-slice.ts
index 4a90969e..7a8df36a 100644
--- a/apps/fxc-front/src/app/redux/track-slice.ts
+++ b/apps/fxc-front/src/app/redux/track-slice.ts
@@ -15,7 +15,6 @@ import TrackWorker from '../workers/track?worker';
import { setTimeSec } from './app-slice';
import { setEnabled, setRoute } from './planner-slice';
import { AppDispatch, AppThunk, RootState } from './store';
-import { Score } from '../logic/score/scorer';
const FETCH_EVERY_SECONDS = 15;
export const FETCH_FOR_MINUTES = 3;
@@ -45,8 +44,6 @@ export type TrackState = {
loaded: boolean;
};
-export type RuntimeTrackId = Pick;
-
const initialState: TrackState = {
currentTrackId: undefined,
fetching: false,
@@ -149,10 +146,8 @@ export const fetchTrack = createAsyncThunk('track/fetch', async (params: FetchTr
if (route && route.alt.length > 0) {
const coords = [];
for (let i = 0; i < route.alt.length; i++) {
- // @ts-ignore funky error: google name not found
coords.push(new google.maps.LatLng(route.lat[i], route.lon[i]));
}
- // @ts-ignore same error
api.dispatch(setRoute(google.maps.geometry.encoding.encodePath(coords)));
api.dispatch(setEnabled(true));
}
@@ -212,8 +207,12 @@ const trackSlice = createSlice({
state.currentTrackId = String(state.tracks.ids[(index + 1) % state.tracks.ids.length]);
}
},
- patchTrack: (state, action: PayloadAction & RuntimeTrackId>) => {
- doPatchTrack(state, action.payload);
+ patchTrack: (state, action: PayloadAction & Pick>) => {
+ const update = action.payload;
+ trackAdapter.updateOne(state.tracks, {
+ id: update.id,
+ changes: update,
+ });
},
setFetchingMetadata: (state, action: PayloadAction) => {
state.metadata.fetchPending = action.payload;
@@ -235,9 +234,6 @@ const trackSlice = createSlice({
}
}
},
- setScore: (state, action: PayloadAction) => {
- doPatchTrack(state, { score: action.payload, id: action.payload.id });
- },
},
extraReducers: (builder) => {
builder
@@ -302,13 +298,6 @@ const trackSlice = createSlice({
},
});
-function doPatchTrack(state: TrackState, update: Partial & RuntimeTrackId) {
- trackAdapter.updateOne(state.tracks, {
- id: update.id,
- changes: update,
- });
-}
-
export const reducer = trackSlice.reducer;
export const {
removeTracksByGroupIds,
@@ -318,6 +307,5 @@ export const {
setLockOnPilot,
setTrackDomain,
setTrackLoaded,
- setScore,
} = trackSlice.actions;
export const trackAdapterSelector = trackAdapter.getSelectors((state: RootState) => state.track.tracks);
diff --git a/apps/fxc-front/src/app/workers/score-track.ts b/apps/fxc-front/src/app/workers/score-track.ts
index 153180c2..47a35f9a 100644
--- a/apps/fxc-front/src/app/workers/score-track.ts
+++ b/apps/fxc-front/src/app/workers/score-track.ts
@@ -17,7 +17,6 @@ export interface Response {
const w: Worker = self as any;
w.onmessage = async (message: MessageEvent) => {
- console.info('scoring: received', message);
try {
const request = message.data;
if (request.leagueCode) {
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index 488040e9..9945240f 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -1,16 +1,23 @@
+# This file permits to launch docker images of services required for this app
+#
services:
+ # launch it with ' docker compose up -d redis'
redis:
image: redis:latest
ports:
- 6378:6379
+ # launch it with ' docker compose up -d pubsub'
pubsub:
image: gcr.io/google.com/cloudsdktool/google-cloud-cli:latest
ports:
- 8085:8085
command: gcloud beta emulators pubsub start
+ # could not manage to make it work (port issue?)
+ # instead you can use the emulator on your workstation
+ # by launching "gcloud beta emulators datastore start"
datastore:
image: gcr.io/google.com/cloudsdktool/google-cloud-cli:latest
command: gcloud beta emulators datastore start --project flyxc
diff --git a/libs/common/src/lib/runtime-track.ts b/libs/common/src/lib/runtime-track.ts
index 6161f7c2..5c7a6d7f 100644
--- a/libs/common/src/lib/runtime-track.ts
+++ b/libs/common/src/lib/runtime-track.ts
@@ -2,7 +2,6 @@ import { getDistance } from 'geolib';
import * as protos from '../protos/track';
import { diffDecodeArray, diffEncodeArray } from './math';
-import { Score } from '../../../../apps/fxc-front/src/app/logic/score/scorer';
export type Point = {
x: number;
@@ -53,7 +52,6 @@ export type RuntimeTrack = {
// maximum distance between two consecutive points.
maxDistance: number;
airspaces?: protos.Airspaces;
- score?: Score;
};
// Creates a runtime track id from the datastore id and the group index.