Skip to content

Commit

Permalink
Add a "none" league without optim
Browse files Browse the repository at this point in the history
  • Loading branch information
vicb committed Sep 17, 2024
1 parent 827f656 commit 17edbe9
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 9 deletions.
8 changes: 6 additions & 2 deletions apps/fxc-front/src/app/components/2d/planner-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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'));
Expand All @@ -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 {
Expand Down Expand Up @@ -191,9 +195,9 @@ export class PlannerElement extends connect(store)(LitElement) {
</div>
</div>
${when(
this.hasCurrentTrack,
this.hasCurrentTrack && this.league != 'none',
() => html` <div class="collapsible hoverable" @click=${this.scoreHandler}>
<span><i class="las la-trophy"></i>Score Track</span>
<span><i class="las la-trophy"></i>Score track</span>
</div>`,
)}
<div
Expand Down
2 changes: 2 additions & 0 deletions apps/fxc-front/src/app/logic/score/league/leagues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const LEAGUE_CODES = [
'czo',
'fr',
'leo',
'none',
'nor',
'ukc',
'uki',
Expand All @@ -28,6 +29,7 @@ export const LEAGUES: Readonly<Record<LeagueCode, LeagueDetails>> = {
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' },
Expand Down
1 change: 1 addition & 0 deletions libs/optimizer/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const scoringRuleNames = [
'CzechOutsideEurope',
'FFVL',
'Leonardo',
'None',
'Norway',
'UKClub',
'UKInternational',
Expand Down
8 changes: 8 additions & 0 deletions libs/optimizer/src/lib/optimizer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -306,6 +309,7 @@ function getFreeDistanceMultiplier(scoringRules: ScoringRuleName) {
case 'XContest':
case 'XContestPPG':
case 'WorldXC':
case 'None':
return 1;
case 'CzechOutsideEurope':
return 0.8;
Expand Down Expand Up @@ -335,6 +339,8 @@ function getFlatTriangleMultiplier(scoringRules: ScoringRuleName) {
return 1.8;
case 'XContestPPG':
return 2;
case 'None':
return 1;
}
}

Expand All @@ -360,5 +366,7 @@ function getFaiTriangleMultiplier(scoringRules: ScoringRuleName) {
return 1.5;
case 'XContestPPG':
return 4;
case 'None':
return 1;
}
}
66 changes: 64 additions & 2 deletions libs/optimizer/src/lib/optimizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ export function* getOptimizer(request: ScoringRequest): Iterator<ScoringResult,
const { track } = request;
const flight = toIgcFile(appendPointsIfNeeded(track, MIN_IGC_XC_SCORE_POINTS));
const solverScoringRules = scoringRules.get(request.ruleName);
if (solverScoringRules == null) {
throw new Error(`Unknown scoring rule: ${request.ruleName}`);
if (solverScoringRules === undefined) {
return toOptimizationResult(toUnoptimizedSolution(track), track);
}
const options = toSolverOptions(request);
const solutionIterator = solver(flight, solverScoringRules, options);
Expand All @@ -106,6 +106,44 @@ export function* getOptimizer(request: ScoringRequest): Iterator<ScoringResult,
}
}

function toUnoptimizedSolution(track: ScoringTrack): Solution {
const tp: Point[] = [];
let distance = 0;
for (let i = 1; i < track.points.length - 1; i++) {
tp.push(trackToPoint(track.points, i));
}
for (let i = 1; i < track.points.length; i++) {
const from = track.points[i - 1];
const to = track.points[i];
distance += distanceEarthFCC(from, to);
}

return {
scoreInfo: {
ep: {
start: trackToPoint(track.points, 0),
finish: trackToPoint(track.points, track.points.length - 1),
},
tp,
distance,
penalty: 0,
score: distance,
},
opt: {
scoring: {
name: '',
code: 'od',
multiplier: 1,
},
flight: undefined as any,
},
optimal: true,
id: 0,
bound: 0,
currentUpperBound: 0,
};
}

/**
* Append points if the track is too short for igc-xc-score.
*
Expand Down Expand Up @@ -206,6 +244,11 @@ function pointToLatTon(point: Point): LatLon {
return { lat: point.y, lon: point.x };
}

function trackToPoint(track: LatLon[], index: number): Point {
const latLon = track[index];
return { x: latLon.lon, y: latLon.lat, r: index };
}

function getClosingRadiusKm(solution: Solution): number | undefined {
const closingDistance = solution.scoreInfo?.cp?.d;

Expand Down Expand Up @@ -273,3 +316,22 @@ function getSolutionIndices(solution: Solution, inputTrack: ScoringTrack): numbe
.map((index) => 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));
}
11 changes: 6 additions & 5 deletions libs/optimizer/src/lib/scoring-rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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/
Expand Down Expand Up @@ -85,12 +85,13 @@ const wxcRule = [
{ ...faiTriangle, multiplier: 2, closingDistanceFixed: 0.2 },
];

export const scoringRules: Map<ScoringRuleName, object> = new Map([
export const scoringRules: Map<ScoringRuleName, object | undefined> = new Map([
['CzechEurope', czechEuropeRule],
['CzechLocal', czechLocalRule],
['CzechOutsideEurope', czechOutEuropeRule],
['FFVL', igcXcScore.scoringRules['FFVL']],
['Leonardo', leonardoRule],
['None', undefined],
['Norway', norwayRule],
['UKClub', ukXclClubRule],
['UKInternational', ukXclInternationalRule],
Expand Down
1 change: 1 addition & 0 deletions libs/optimizer/src/modules.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module 'igc-xc-score/src/foundation';

0 comments on commit 17edbe9

Please sign in to comment.