From 7ddd48dad2e7963c573a45ad0177687f9ef23ff0 Mon Sep 17 00:00:00 2001 From: Manuel Rego Casasnovas Date: Wed, 11 Jul 2012 16:33:30 +0200 Subject: [PATCH] Bug #1503: Fix intervals in estimation accuracy chart FEA: ItEr76S04BugFixing --- .../web/dashboard/DashboardController.java | 9 +- .../web/dashboard/DashboardModel.java | 143 +++++++++++++++--- .../web/dashboard/IDashboardModel.java | 3 +- 3 files changed, 125 insertions(+), 30 deletions(-) diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardController.java b/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardController.java index c1c138c0a..7b6998c86 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardController.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardController.java @@ -34,6 +34,7 @@ import java.util.Set; import org.libreplan.business.orders.entities.Order; import org.libreplan.business.planner.entities.TaskElement; import org.libreplan.business.planner.entities.TaskStatusEnum; +import org.libreplan.web.dashboard.DashboardModel.IntegerInterval; import org.libreplan.web.dashboard.DashboardModel.Interval; import org.libreplan.web.planner.order.PlanningStateCreator.PlanningState; import org.springframework.beans.factory.config.BeanDefinition; @@ -388,7 +389,7 @@ public class DashboardController extends GenericForwardComposer { private final IDashboardModel dashboardModel; - private Map estimationAccuracyData; + private Map estimationAccuracyData; private EstimationAccuracy(IDashboardModel dashboardModel) { this.dashboardModel = dashboardModel; @@ -398,7 +399,7 @@ public class DashboardController extends GenericForwardComposer { return new EstimationAccuracy(dashboardModel); } - private Map getData() { + private Map getData() { if (estimationAccuracyData == null) { estimationAccuracyData = dashboardModel .calculateEstimationAccuracy(); @@ -407,10 +408,10 @@ public class DashboardController extends GenericForwardComposer { } public String[] getTicks() { - Set intervals = getData().keySet(); + Set intervals = getData().keySet(); String[] result = new String[intervals.size()]; int i = 0; - for (Interval each : intervals) { + for (IntegerInterval each : intervals) { result[i++] = each.toString(); } diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardModel.java b/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardModel.java index 298d3a256..f121bc266 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardModel.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardModel.java @@ -58,6 +58,7 @@ import org.springframework.stereotype.Component; * @author Nacho Barrientos * @author Lorenzo Tilve Álvaro * @author Diego Pino García + * @author Manuel Rego Casasnovas * * Model for UI operations related to Order Dashboard View * @@ -322,48 +323,110 @@ public class DashboardModel implements IDashboardModel { } /** - * Calculates the estimation accuracy deviations for the current order + * Calculates the estimation accuracy deviations for the current order. * - * All the deviations are groups in Interval.MAX_INTERVALS intervals of - * equal size. If the order contains just one single task then, the upper - * limit will be the deviation of the task + 30, and the lower limit will be - * deviation of the task - 20 + * All the deviations are groups in 6 intervals of equal size (not less than + * 10). There're some restrictions: + *
    + *
  • If the order contains just one single task then, the upper limit will + * be the deviation of the task +30, and the lower limit will be deviation + * of the task -30.
  • + *
  • If the difference between values is bigger than 60, then the + * intervals will be bigger than 10 but it'll keep generating 6 intervals. + * For example with min -45 and max +45, we'll have 6 intervals of size 15.
  • + *
  • In the case that we have enough distance for, it doesn't need to set + * the min to -30. For example, with min 0 and max 60, it'll keep intervals + * of size 10.
  • + *
  • If the min was 10 and the max 40, it'll have to decrease the min and + * increase the max to get a difference of 60. For example setting min to + * -10 and max to 50. (In order to calculate this it subtracts 10 to the min + * and check if the difference is 60 again, if not it adds 10 to the max and + * check it again, repeating this till it has a difference of 60).
  • + *
* * Each {@link Interval} contains the number of tasks that fit in that - * interval - * - * @return + * interval. */ @Override - public Map calculateEstimationAccuracy() { - Map result = new LinkedHashMap(); - Double max, min; + public Map calculateEstimationAccuracy() { + Map result = new LinkedHashMap(); + double maxDouble, minDouble; // Get deviations of finished tasks, calculate max, min and delta List deviations = getEstimationAccuracyDeviations(); if (deviations.isEmpty()) { - max = Double.valueOf(30); - min = Double.valueOf(-20); + minDouble = -30; + maxDouble = 30; } else if (deviations.size() == 1) { - max = deviations.get(0).doubleValue() + 30; - min = deviations.get(0).doubleValue() - 20; + minDouble = deviations.get(0) - 30; + maxDouble = deviations.get(0) + 30; } else { - max = Collections.max(deviations); - min = Collections.min(deviations); + minDouble = Collections.min(deviations); + maxDouble = Collections.max(deviations); } - double delta = (max - min) / Interval.MAX_INTERVALS; - // Create MAX_INTERVALS - double from = min; - for (int i = 0; i < Interval.MAX_INTERVALS; i++) { - result.put(Interval.create(from, from + delta), Integer.valueOf(0)); - from = from + delta; + // If min and max are between -30 and +30, set -30 as min and +30 as max + if (minDouble >= -30 && maxDouble <= 30) { + minDouble = -30; + maxDouble = 30; + } + + // If the difference between min and max is less than 60, decrease min + // and increase max till get that difference + boolean changeMin = true; + while (maxDouble - minDouble < 60) { + if (changeMin) { + minDouble -= 10; + } else { + maxDouble += 10; + } + } + + // Round min and max properly depending on decimal part or not + int min; + double minDecimalPart = minDouble - (int) minDouble; + if (minDouble >= 0) { + min = (int) (minDouble - minDecimalPart); + } else { + min = (int) (minDouble - minDecimalPart); + if (minDecimalPart != 0) { + min--; + } + } + int max; + double maxDecimalPart = maxDouble - (int) maxDouble; + if (maxDouble >= 0) { + max = (int) (maxDouble - maxDecimalPart); + if (maxDecimalPart != 0) { + max++; + } + } else { + max = (int) (maxDouble - maxDecimalPart); + } + + // Calculate intervals size + int intervalsNumber = 6; + double delta = (double) (max - min) / intervalsNumber; + double deltaDecimalPart = delta - (int) delta; + + // Generate intervals + int from = min; + for (int i = 0; i < intervalsNumber; i++) { + int to = from + (int) delta; + // Fix to depending on decimal part if it's not the last interval + if (deltaDecimalPart == 0 && i != (intervalsNumber - 1)) { + to--; + } + result.put(new IntegerInterval(from, to), Integer.valueOf(0)); + + from = to + 1; } // Construct map with number of tasks for each interval - final Set intervals = result.keySet(); + final Set intervals = result.keySet(); for (Double each : deviations) { - Interval interval = Interval.containingValue(intervals, each); + IntegerInterval interval = IntegerInterval.containingValue( + intervals, each); if (interval != null) { Integer value = result.get(interval); result.put(interval, value + 1); @@ -382,6 +445,36 @@ public class DashboardModel implements IDashboardModel { return visitor.getDeviations(); } + static class IntegerInterval { + private int min; + private int max; + + public IntegerInterval(int min, int max) { + this.min = min; + this.max = max; + } + + public static IntegerInterval containingValue( + Collection intervals, double value) { + for (IntegerInterval each : intervals) { + if (each.includes(value)) { + return each; + } + } + return null; + } + + private boolean includes(double value) { + return (value >= min) && (value <= max); + } + + @Override + public String toString() { + return "[" + min + ", " + max + "]"; + } + + } + /** * * @author Diego Pino García diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/IDashboardModel.java b/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/IDashboardModel.java index 7c9e3cd81..5461ab116 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/IDashboardModel.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/IDashboardModel.java @@ -25,6 +25,7 @@ import java.util.Map; import org.libreplan.business.planner.entities.TaskElement; import org.libreplan.business.planner.entities.TaskStatusEnum; +import org.libreplan.web.dashboard.DashboardModel.IntegerInterval; import org.libreplan.web.dashboard.DashboardModel.Interval; import org.libreplan.web.planner.order.PlanningStateCreator.PlanningState; @@ -73,7 +74,7 @@ interface IDashboardModel { Integer getAbsoluteMarginWithDeadLine(); /* Time KPI: "Estimation accuracy" */ - Map calculateEstimationAccuracy(); + Map calculateEstimationAccuracy(); /* Time KPI: "Lead/Lag in task completion" */ Map calculateTaskCompletion();