From a401493bb0c993bd1445a08eaade1cf26f0d4bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Lamy?= Date: Wed, 29 Jan 2025 13:32:08 -0500 Subject: [PATCH] 55.3.0-alpha01 --- .github/workflows/release.yaml | 2 +- docs/FeatureToggles.md | 2 +- .../java/app/owlcms/data/athlete/Athlete.java | 140 +++++++++++------- .../athleteSort/AbstractLifterComparator.java | 30 ++++ .../app/owlcms/data/athleteSort/Ranking.java | 45 ++++-- .../athleteSort/WinningOrderComparator.java | 48 ++++-- .../spreadsheet/JXLSCompetitionBook.java | 2 + .../spreadsheet/JXLSWorkbookStreamSource.java | 12 ++ pom.xml | 2 +- src/main/markdown/ReleaseNotes.md | 3 + 10 files changed, 201 insertions(+), 85 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index b8bca93cd..77e8dabc3 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -6,7 +6,7 @@ on: revision: description: 'Revision for the release' required: true - default: '55.2.1' + default: '55.3.0-alpha01' env: REPO_OWNER: owlcms diff --git a/docs/FeatureToggles.md b/docs/FeatureToggles.md index f73394a59..93b378d14 100644 --- a/docs/FeatureToggles.md +++ b/docs/FeatureToggles.md @@ -28,7 +28,7 @@ These switches change the default behavior of the interface | forceAllFederationRecords | On scoreboards show records from all federations, not just that of the current athlete. E.g. South American records would be shown for a North American athlete during a Pan American championship. | Only available as a feature switch. | | lightBarU13 | Ignore the 20kg bar when a youth age group includes athletes 12 or younger (U13, U11, U9 for example). | Only available as a feature switch. | | childrenEquipment | If present, it is assumed that all platforms have 2,5kg and 5kg large discs, and have 5kg and 10kg bars | Only available as a feature switch. | -| interimScores | If present, the Sinclair/SM(H)F/Q-points scores will be shown on the scoreboard and included in the results documents even if the total is 0. | Only available as a feature switch. | +| noInterimScoresInResults | If present, scoreboards will show interim scores, but result sheets will not (on the result sheets QPoints will be 0 if total is 0) | Only available as a feature switch. | ### Specialty Features diff --git a/owlcms/src/main/java/app/owlcms/data/athlete/Athlete.java b/owlcms/src/main/java/app/owlcms/data/athlete/Athlete.java index 2be9c7cad..beee4d5ae 100644 --- a/owlcms/src/main/java/app/owlcms/data/athlete/Athlete.java +++ b/owlcms/src/main/java/app/owlcms/data/athlete/Athlete.java @@ -841,13 +841,6 @@ public Integer getAge() { return date.getYear() - fullBirthDate2.getYear(); } - @Transient - @JsonIgnore - public Double getAgeAdjustedTotal() { - Integer total = getBestCleanJerk() + getBestSnatch(); - return (double) AgeFactors.getAgeAdjustedTotal(this, total); - } - @Transient @JsonIgnore public Integer getAgeAdjustedTotalRank() { @@ -1215,53 +1208,10 @@ public Boolean getCategoryFinished() { return code != null ? allUnfinished.contains(code) : false; } - @Transient - @JsonIgnore - public Double getCategoryScore() { - Double computedScore = computedCategoryScore(); - // logger.debug("{} getCategoryScore {}", this.getClass().getSimpleName(), this.getCategoryCode(), computedScore); - return computedScore; - } - public int getCategoryScoreRank() { return (getMainRankings() != null ? getMainRankings().getCategoryScoreRank() : -1); } - /** - * Compute the body weight at the maximum weight of the Athlete's category. Note: for the purpose of this computation, only "official" categories are used - * as the purpose is to totalRank athletes according to their competition potential. - * - * @return the category sinclair - */ - @Transient - @JsonIgnore - public Double getCategorySinclair() { - Category category = getCategory(); - if (category == null) { - return 0.0; - } - Double categoryWeight = category.getMaximumWeight(); - final Integer total1 = getTotal(); - if (total1 == null || total1 < 0.1) { - return 0.0; - } - if (getGender() == Gender.M) { // $NON-NLS-1$ - if (categoryWeight < 55.0) { - categoryWeight = 55.0; - } else if (categoryWeight > getSinclairProperties().menMaxWeight()) { - categoryWeight = getSinclairProperties().menMaxWeight(); - } - } else if (getGender() == Gender.F) { - if (categoryWeight < 45.0) { - categoryWeight = 45.0; - } else if (categoryWeight > getSinclairProperties().womenMaxWeight()) { - categoryWeight = getSinclairProperties().womenMaxWeight(); - } - } else { - return 0.0D; - } - return getSinclair(categoryWeight); - } @Transient @JsonIgnore @@ -2308,10 +2258,7 @@ public int getProgression(Integer requestedWeight) { return doGetProgression(requestedWeight, attempt); } - public Double getQAge() { - double d = getQPoints() * getQMastersFactor(); - return d; - } + public int getqAgeRank() { return this.qAgeRank; @@ -5774,4 +5721,89 @@ private void validateDeclaration(int curLift, String automaticProgression, Strin this.timingLogger.info("validateDeclaration {}ms {} {}", System.currentTimeMillis() - start, curLift, LoggerUtils.whereFrom()); } + + @Transient + @JsonIgnore + public Double getAgeAdjustedTotal() { + Integer total = getBestCleanJerk() + getBestSnatch(); + if (total == 0) { + return 0.0D; + } else { + return getAgeAdjustedTotalForDelta(); + } + } + + @Transient + @JsonIgnore + public Double getAgeAdjustedTotalForDelta() { + Integer total = getBestCleanJerk() + getBestSnatch(); + var val = (double) AgeFactors.getAgeAdjustedTotal(this, total); + return val; + } + + @Transient + @JsonIgnore + public Double getQAge() { + double d = getQPoints() * getQMastersFactor(); + return d; + } + + @Transient + @JsonIgnore + public Double getQAgeForDelta() { + double d = getQPointsForDelta() * getQMastersFactor(); + return d; + } + + @Transient + @JsonIgnore + public Double getCategoryScore() { + return getTotal() == 0 ? getCategoryScoreForDelta() : 0.0D; + } + + @Transient + @JsonIgnore + public Double getCategoryScoreForDelta() { + Double computedScore = computedCategoryScore(); + return computedScore; + } + + @Transient + @JsonIgnore + public Double getCategorySinclair() { + return getTotal() == 0 ? getCategorySinclairForDelta() : 0.0D; + } + + /** + * Compute the body weight at the maximum weight of the Athlete's category. Note: for the purpose of this computation, only "official" categories are used + * as the purpose is to totalRank athletes according to their competition potential. + * + * @return the category sinclair + */ + @Transient + @JsonIgnore + public Double getCategorySinclairForDelta() { + Category category = getCategory(); + if (category == null) { + return 0.0; + } + Double categoryWeight = category.getMaximumWeight(); + if (getGender() == Gender.M) { // $NON-NLS-1$ + if (categoryWeight < 55.0) { + categoryWeight = 55.0; + } else if (categoryWeight > getSinclairProperties().menMaxWeight()) { + categoryWeight = getSinclairProperties().menMaxWeight(); + } + } else if (getGender() == Gender.F) { + if (categoryWeight < 45.0) { + categoryWeight = 45.0; + } else if (categoryWeight > getSinclairProperties().womenMaxWeight()) { + categoryWeight = getSinclairProperties().womenMaxWeight(); + } + } else { + return 0.0D; + } + return getSinclair(categoryWeight); + } + } diff --git a/owlcms/src/main/java/app/owlcms/data/athleteSort/AbstractLifterComparator.java b/owlcms/src/main/java/app/owlcms/data/athleteSort/AbstractLifterComparator.java index 26c332b82..4a9b4af9e 100644 --- a/owlcms/src/main/java/app/owlcms/data/athleteSort/AbstractLifterComparator.java +++ b/owlcms/src/main/java/app/owlcms/data/athleteSort/AbstractLifterComparator.java @@ -775,6 +775,36 @@ int compareQAge(Athlete lifter1, Athlete lifter2) { // bigger sinclair comes first return -lifter1Value.compareTo(lifter2Value); } + + /** + * Compare Q-masters. + * + * @param lifter1 the lifter 1 + * @param lifter2 the lifter 2 + * @return the int + */ + int compareQAgeForDelta(Athlete lifter1, Athlete lifter2) { + Gender gender = lifter1.getGender(); + if (gender == null) { + return -1; + } + int compare = gender.compareTo(lifter2.getGender()); + if (compare != 0) { + return compare; + } + + Double lifter1Value = lifter1.getQAgeForDelta(); + Double lifter2Value = lifter2.getQAgeForDelta(); + final Double notWeighed = 0D; + if (lifter1Value == null) { + lifter1Value = notWeighed; + } + if (lifter2Value == null) { + lifter2Value = notWeighed; + } + // bigger sinclair comes first + return -lifter1Value.compareTo(lifter2Value); + } /** * Compare registration category. diff --git a/owlcms/src/main/java/app/owlcms/data/athleteSort/Ranking.java b/owlcms/src/main/java/app/owlcms/data/athleteSort/Ranking.java index 9c35a49ff..b0e01e5ad 100644 --- a/owlcms/src/main/java/app/owlcms/data/athleteSort/Ranking.java +++ b/owlcms/src/main/java/app/owlcms/data/athleteSort/Ranking.java @@ -15,8 +15,8 @@ import org.slf4j.LoggerFactory; import app.owlcms.data.athlete.Athlete; -import app.owlcms.data.config.Config; import app.owlcms.i18n.Translator; +import app.owlcms.spreadsheet.JXLSWorkbookStreamSource; import ch.qos.logback.classic.Logger; /** @@ -151,41 +151,56 @@ public static double getRankingValue(Athlete curLifter, Ranking rankingType) { d = 0D; // no such thing break; case BW_SINCLAIR: - if (Config.getCurrent().featureSwitch("interimScores")) { - d = curLifter.getSinclairForDelta(); - } else { + if (JXLSWorkbookStreamSource.isNoInterimScoresInResults()) { d = curLifter.getSinclair(); + } else { + d = curLifter.getSinclairForDelta(); } break; case CAT_SINCLAIR: - d = curLifter.getCategorySinclair(); + if (JXLSWorkbookStreamSource.isNoInterimScoresInResults()) { + d = curLifter.getCategorySinclair(); + } else { + d = curLifter.getCategorySinclairForDelta(); + } break; case SMM: - if (Config.getCurrent().featureSwitch("interimScores")) { - d = curLifter.getSmhfForDelta(); - } else { + if (JXLSWorkbookStreamSource.isNoInterimScoresInResults()) { d = curLifter.getSmhf(); + } else { + d = curLifter.getSmhfForDelta(); } break; case GAMX: d = curLifter.getGamx(); break; case AGEFACTORS: - d = curLifter.getAgeAdjustedTotal(); + if (JXLSWorkbookStreamSource.isNoInterimScoresInResults()) { + d = curLifter.getAgeAdjustedTotal(); + } else { + d = curLifter.getAgeAdjustedTotalForDelta(); + } break; case QPOINTS: - if (Config.getCurrent().featureSwitch("interimScores")) { - d = curLifter.getQPointsForDelta(); - } else { + if (JXLSWorkbookStreamSource.isNoInterimScoresInResults()) { d = curLifter.getQPoints(); + } else { + d = curLifter.getQPointsForDelta(); } - break; case QAGE: - d = curLifter.getQAge(); + if (JXLSWorkbookStreamSource.isNoInterimScoresInResults()) { + d = curLifter.getQAge(); + } else { + d = curLifter.getQAgeForDelta(); + } break; case CATEGORY_SCORE: - d = curLifter.getCategoryScore(); + if (JXLSWorkbookStreamSource.isNoInterimScoresInResults()) { + d = curLifter.getCategoryScoreForDelta(); + } else { + d = curLifter.getCategoryScore(); + } break; } return d != null ? d : 0D; diff --git a/owlcms/src/main/java/app/owlcms/data/athleteSort/WinningOrderComparator.java b/owlcms/src/main/java/app/owlcms/data/athleteSort/WinningOrderComparator.java index 1b0831725..fa4c1bc35 100644 --- a/owlcms/src/main/java/app/owlcms/data/athleteSort/WinningOrderComparator.java +++ b/owlcms/src/main/java/app/owlcms/data/athleteSort/WinningOrderComparator.java @@ -14,8 +14,8 @@ import app.owlcms.data.athlete.Athlete; import app.owlcms.data.competition.Competition; -import app.owlcms.data.config.Config; import app.owlcms.data.group.Group; +import app.owlcms.spreadsheet.JXLSWorkbookStreamSource; import app.owlcms.utils.LoggerUtils; import ch.qos.logback.classic.Logger; @@ -95,6 +95,20 @@ public int compareAgeAdjustedTotal(Athlete lifter1, Athlete lifter2) { // bigger adjusted total comes first return -lifter1Value.compareTo(lifter2Value); } + + public int compareAgeAdjustedTotalForDelta(Athlete lifter1, Athlete lifter2) { + Double lifter1Value = lifter1.getAgeAdjustedTotalForDelta(); + Double lifter2Value = lifter2.getAgeAdjustedTotalForDelta(); + final Double notWeighed = 0D; + if (lifter1Value == null) { + lifter1Value = notWeighed; + } + if (lifter2Value == null) { + lifter2Value = notWeighed; + } + // bigger adjusted total comes first + return -lifter1Value.compareTo(lifter2Value); + } /** * Determine who ranks first on AgeFactor-adjusted total. @@ -109,8 +123,12 @@ public int compareAgeAdjustedTotalOrder(Athlete lifter1, Athlete lifter2) { if (compare != 0) { return compare; } - compare = compareAgeAdjustedTotal(lifter1, lifter2); - traceComparison("gamx", lifter1, lifter2, compare); + if (JXLSWorkbookStreamSource.isNoInterimScoresInResults()) { + compare = compareAgeAdjustedTotal(lifter1, lifter2); + } else { + compare = compareAgeAdjustedTotalForDelta(lifter1, lifter2); + } + traceComparison("ageAdjustedTotal", lifter1, lifter2, compare); if (compare != 0) { return compare; } @@ -238,7 +256,11 @@ public int compareQAgeResultOrder(Athlete lifter1, Athlete lifter2) { if (compare != 0) { return compare; } - compare = compareQAge(lifter1, lifter2); + if (JXLSWorkbookStreamSource.isNoInterimScoresInResults()) { + compare = compareQAge(lifter1, lifter2); + } else { + compare = compareQAgeForDelta(lifter1, lifter2); + } traceComparison("qPoints", lifter1, lifter2, compare); if (compare != 0) { return compare; @@ -261,10 +283,10 @@ public int compareQPointsResultOrder(Athlete lifter1, Athlete lifter2) { if (compare != 0) { return compare; } - if (Config.getCurrent().featureSwitch("interimScores")) { - compare = compareQPointsForDelta(lifter1, lifter2); - } else { + if (JXLSWorkbookStreamSource.isNoInterimScoresInResults()) { compare = compareQPoints(lifter1, lifter2); + } else { + compare = compareQPointsForDelta(lifter1, lifter2); } traceComparison("qPoints", lifter1, lifter2, compare); if (compare != 0) { @@ -339,10 +361,10 @@ public int compareSinclairResultOrder(Athlete lifter1, Athlete lifter2) { if (compare != 0) { return compare; } - if (Config.getCurrent().featureSwitch("interimScores")) { - compare = compareSinclairForDelta(lifter1, lifter2); - } else { + if (JXLSWorkbookStreamSource.isNoInterimScoresInResults()) { compare = compareSinclair(lifter1, lifter2); + } else { + compare = compareSinclairForDelta(lifter1, lifter2); } traceComparison("sinclair", lifter1, lifter2, compare); if (compare != 0) { @@ -367,10 +389,10 @@ public int compareSmhfResultOrder(Athlete lifter1, Athlete lifter2) { return compare; } - if (Config.getCurrent().featureSwitch("interimScores")) { - compare = compareSmhfForDelta(lifter1, lifter2); - } else { + if (JXLSWorkbookStreamSource.isNoInterimScoresInResults()) { compare = compareSmhf(lifter1, lifter2); + } else { + compare = compareSmhfForDelta(lifter1, lifter2); } traceComparison("smhf", lifter1, lifter2, compare); diff --git a/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSCompetitionBook.java b/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSCompetitionBook.java index 6339f50a4..40982f767 100644 --- a/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSCompetitionBook.java +++ b/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSCompetitionBook.java @@ -22,6 +22,7 @@ import app.owlcms.data.athlete.AthleteRepository; import app.owlcms.data.athleteSort.Ranking; import app.owlcms.data.competition.Competition; +import app.owlcms.data.config.Config; import app.owlcms.i18n.Translator; import app.owlcms.init.OwlcmsSession; import net.sf.jxls.transformer.XLSTransformer; @@ -146,6 +147,7 @@ protected void setReportingInfo() { overallScoringSystem = overallScoringSystem != null ? overallScoringSystem : Competition.getCurrent().getScoringSystem(); // make available to the Athlete class in this Thread (and subThreads). JXLSWorkbookStreamSource.setBestLifterRankingThreadLocal(overallScoringSystem); + JXLSWorkbookStreamSource.setNoInterimScoresInResults(Config.getCurrent().featureSwitch("noInterimScoresInResults")); reportingBeans.put("bestRankingTitle", Ranking.getScoringTitle(overallScoringSystem)); reportingBeans.put("mBest", reportingBeans.get(overallScoringSystem.getMReportingName())); diff --git a/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSWorkbookStreamSource.java b/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSWorkbookStreamSource.java index 9c861fc39..741588406 100644 --- a/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSWorkbookStreamSource.java +++ b/owlcms/src/main/java/app/owlcms/spreadsheet/JXLSWorkbookStreamSource.java @@ -81,6 +81,7 @@ public abstract class JXLSWorkbookStreamSource implements StreamResourceWriter, final private static Logger logger = (Logger) LoggerFactory.getLogger(JXLSWorkbookStreamSource.class); final private static Logger tagLogger = (Logger) LoggerFactory.getLogger("net.sf.jxls.tag.ForEachTag"); private static ThreadLocal bestLifterRankingSystem = InheritableThreadLocal.withInitial(() -> null); + private static ThreadLocal noInterimScoresInResults = InheritableThreadLocal.withInitial(() -> null); static { logger.setLevel(Level.INFO); @@ -100,6 +101,17 @@ protected static void setBestLifterRankingThreadLocal(Ranking bestLifterRankingV logger.debug("**** setting {}", bestLifterRankingValue); bestLifterRankingSystem.set(bestLifterRankingValue); } + + protected static void setNoInterimScoresInResults(boolean noInterimScoresInResultsP) { + logger.debug("**** setting {}", noInterimScoresInResultsP); + noInterimScoresInResults.set(noInterimScoresInResultsP); + } + + public static boolean isNoInterimScoresInResults() { + Boolean blss = noInterimScoresInResults.get(); + return Boolean.TRUE.equals(blss); + } + protected List sortedAthletes; private Championship championship; diff --git a/pom.xml b/pom.xml index 8ef5ac894..2b83646fb 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ - 55.2.0-SNAPSHOT + 55.3.0-SNAPSHOT 24.4.10 1.4.14 diff --git a/src/main/markdown/ReleaseNotes.md b/src/main/markdown/ReleaseNotes.md index 48a2a670c..2a1cc7452 100644 --- a/src/main/markdown/ReleaseNotes.md +++ b/src/main/markdown/ReleaseNotes.md @@ -6,6 +6,7 @@ **Maintenance Log** +- 55.3.0: Scores such as Q-Points or Sinclair will now be shown on scoreboards (see below) - 55.2.1: Fixed record definition import to deal with text cells that are not null but contain no text. - 55.2.0: Inclusion of 2025 Youth body weight classes in the AgeGroups2025 age group template - 55.2.0: Windows Installation documentation modified to refer to the owlcms_controlpanel.exe executable directly. The installer has been sidelined while Microsoft investigates a false warning. @@ -18,6 +19,8 @@ - New [Installation Instructions](https://owlcms.github.io/owlcms4-prerelease/#/LocalDownloads.md) and startup instructions using the [owlcms Control Panel](https://owlcms.github.io/owlcms4-prerelease/#/LocalControlPanel.md) for updating, launching and stopping OWLCMS on a local computer. +- When medals are awarded by score like (Q-Points/Q-Masters/Q-Youth/Sinclair/SMHF/etc,), the scores will be visible during the snatch. A feature toggle `noInterimScoresInResults` can be used so that the result sheets always show 0 is no total has been set. + - Inclusion of 2025 Youth body weight classes in the AgeGroups2025 age group template - Ability to set the duration of the clean & jerk break explicitly for a session, overriding the competition-wide rules.