From 17edbe9bb483a135c635ea22fa72590ad80de869 Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Tue, 17 Sep 2024 09:38:59 +0200 Subject: [PATCH] Add a "none" league without optim --- .../src/app/components/2d/planner-element.ts | 8 ++- .../src/app/logic/score/league/leagues.ts | 2 + libs/optimizer/src/lib/api.ts | 1 + libs/optimizer/src/lib/optimizer.spec.ts | 8 +++ libs/optimizer/src/lib/optimizer.ts | 66 ++++++++++++++++++- libs/optimizer/src/lib/scoring-rules.ts | 11 ++-- libs/optimizer/src/modules.d.ts | 1 + 7 files changed, 88 insertions(+), 9 deletions(-) create mode 100644 libs/optimizer/src/modules.d.ts 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 82ddc5a8..83355287 100644 --- a/apps/fxc-front/src/app/components/2d/planner-element.ts +++ b/apps/fxc-front/src/app/components/2d/planner-element.ts @@ -6,6 +6,7 @@ import { unsafeHTML } from 'lit/directives/unsafe-html.js'; import { when } from 'lit/directives/when.js'; import { connect } from 'pwa-helpers'; +import type { LeagueCode } from '../../logic/score/league/leagues'; import * as units from '../../logic/units'; import * as plannerSlice from '../../redux/planner-slice'; import { currentTrack } from '../../redux/selectors'; @@ -37,6 +38,8 @@ export class PlannerElement extends connect(store)(LitElement) { private isFreeDrawing = false; @state() private hasCurrentTrack = false; + @state() + private league: LeagueCode = 'xc'; private duration?: number; private readonly closeHandler = () => this.dispatchEvent(new CustomEvent('close')); @@ -55,6 +58,7 @@ export class PlannerElement extends connect(store)(LitElement) { this.units = state.units; this.duration = ((this.distanceM / this.speedKmh) * 60) / 1000; this.isFreeDrawing = state.planner.isFreeDrawing; + this.league = state.planner.league; } static get styles(): CSSResult { @@ -191,9 +195,9 @@ export class PlannerElement extends connect(store)(LitElement) { ${when( - this.hasCurrentTrack, + this.hasCurrentTrack && this.league != 'none', () => html`
- Score Track + Score track
`, )}
> = { czo: { name: 'Czech (ČPP outside Europe)', ruleName: 'CzechOutsideEurope' }, fr: { name: 'France (CFD)', ruleName: 'FFVL' }, leo: { name: 'Leonardo', ruleName: 'Leonardo' }, + none: { name: 'None (no scoring)', ruleName: 'None' }, nor: { name: 'Norway (Distanseligaen)', ruleName: 'Norway' }, ukc: { name: 'UK (XC League, Club)', ruleName: 'UKClub' }, uki: { name: 'UK (XC League, International)', ruleName: 'UKInternational' }, diff --git a/libs/optimizer/src/lib/api.ts b/libs/optimizer/src/lib/api.ts index f0d8fb8f..7e9989ea 100644 --- a/libs/optimizer/src/lib/api.ts +++ b/libs/optimizer/src/lib/api.ts @@ -7,6 +7,7 @@ export const scoringRuleNames = [ 'CzechOutsideEurope', 'FFVL', 'Leonardo', + 'None', 'Norway', 'UKClub', 'UKInternational', diff --git a/libs/optimizer/src/lib/optimizer.spec.ts b/libs/optimizer/src/lib/optimizer.spec.ts index 3503f912..34f9d6ea 100644 --- a/libs/optimizer/src/lib/optimizer.spec.ts +++ b/libs/optimizer/src/lib/optimizer.spec.ts @@ -8,6 +8,9 @@ import { mergeTracks } from './utils/merge-tracks'; describe('optimizer', () => { scoringRuleNames.forEach((ruleName) => { + if (ruleName === 'None') { + return; + } describe(`${ruleName} rules`, () => { it('Scores an empty request with a score of 0', () => { const request = { @@ -306,6 +309,7 @@ function getFreeDistanceMultiplier(scoringRules: ScoringRuleName) { case 'XContest': case 'XContestPPG': case 'WorldXC': + case 'None': return 1; case 'CzechOutsideEurope': return 0.8; @@ -335,6 +339,8 @@ function getFlatTriangleMultiplier(scoringRules: ScoringRuleName) { return 1.8; case 'XContestPPG': return 2; + case 'None': + return 1; } } @@ -360,5 +366,7 @@ function getFaiTriangleMultiplier(scoringRules: ScoringRuleName) { return 1.5; case 'XContestPPG': return 4; + case 'None': + return 1; } } diff --git a/libs/optimizer/src/lib/optimizer.ts b/libs/optimizer/src/lib/optimizer.ts index 896f2db3..6347ad9b 100644 --- a/libs/optimizer/src/lib/optimizer.ts +++ b/libs/optimizer/src/lib/optimizer.ts @@ -92,8 +92,8 @@ export function* getOptimizer(request: ScoringRequest): Iterator Math.min(index!, inputTrack.points.length - 1)) ); } + +// https://github.com/mmomtchev/igc-xc-score/blob/da601fa5ade432c1e55808de5ad3336905ea6cf8/src/foundation.js#L48C1-L64C6 +function distanceEarthFCC(p1: LatLon, p2: LatLon) { + const df = p1.lat - p2.lat; + const dg = p1.lon - p2.lon; + const fmDegree = (p2.lat + p1.lat) / 2; + const fm = fmDegree / (180 / Math.PI); + // Speed up cos computation using: + // - cos(2x) = 2 * cos(x)^2 - 1 + // - cos(a+b) = 2 * cos(a)cos(b) - cos(a-b) + const cosfm = Math.cos(fm); + const cos2fm = 2 * cosfm * cosfm - 1; + const cos3fm = cosfm * (2 * cos2fm - 1); + const cos4fm = 2 * cos2fm * cos2fm - 1; + const cos5fm = 2 * cos2fm * cos3fm - cosfm; + const k1 = 111.13209 - 0.566605 * cos2fm + 0.0012 * cos4fm; + const k2 = 111.41513 * cosfm - 0.09455 * cos3fm + 0.00012 * cos5fm; + return Math.sqrt(k1 * df * (k1 * df) + k2 * dg * (k2 * dg)); +} diff --git a/libs/optimizer/src/lib/scoring-rules.ts b/libs/optimizer/src/lib/scoring-rules.ts index b6ce17a0..be66900d 100644 --- a/libs/optimizer/src/lib/scoring-rules.ts +++ b/libs/optimizer/src/lib/scoring-rules.ts @@ -3,10 +3,10 @@ import * as igcXcScore from 'igc-xc-score'; import type { ScoringRuleName } from './api'; // TODO: Export the rules from igc-xc-score -const scoringBaseModel = igcXcScore.scoringRules['XContest']; -const openDistance = scoringBaseModel[0]; -const freeTriangle = scoringBaseModel[1]; -const faiTriangle = scoringBaseModel[2]; +const XContestScoring = igcXcScore.scoringRules['XContest']; +const openDistance = XContestScoring[0]; +const freeTriangle = XContestScoring[1]; +const faiTriangle = XContestScoring[2]; const outAndReturn = igcXcScore.scoringRules['FAI-OAR'][0]; //Czech rules see https://www.xcontest.org/cesko/pravidla/ @@ -85,12 +85,13 @@ const wxcRule = [ { ...faiTriangle, multiplier: 2, closingDistanceFixed: 0.2 }, ]; -export const scoringRules: Map = new Map([ +export const scoringRules: Map = new Map([ ['CzechEurope', czechEuropeRule], ['CzechLocal', czechLocalRule], ['CzechOutsideEurope', czechOutEuropeRule], ['FFVL', igcXcScore.scoringRules['FFVL']], ['Leonardo', leonardoRule], + ['None', undefined], ['Norway', norwayRule], ['UKClub', ukXclClubRule], ['UKInternational', ukXclInternationalRule], diff --git a/libs/optimizer/src/modules.d.ts b/libs/optimizer/src/modules.d.ts new file mode 100644 index 00000000..a24dc332 --- /dev/null +++ b/libs/optimizer/src/modules.d.ts @@ -0,0 +1 @@ +declare module 'igc-xc-score/src/foundation';