From d08a768e988e8127f0404f22e6f6894b06532dd4 Mon Sep 17 00:00:00 2001 From: Diego Pino Garcia Date: Sun, 20 Feb 2011 23:22:54 +0100 Subject: [PATCH] [Bug #864] S-curve changes the end date of a task FEA: ItEr70S04BugFixing --- .../planner/entities/SigmoidFunction.java | 77 ++++++++++++++----- 1 file changed, 57 insertions(+), 20 deletions(-) diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/SigmoidFunction.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/SigmoidFunction.java index 64cefa350..6528f84c9 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/SigmoidFunction.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/SigmoidFunction.java @@ -20,7 +20,6 @@ package org.navalplanner.business.planner.entities; import java.math.BigDecimal; -import org.joda.time.Days; import org.joda.time.LocalDate; import org.navalplanner.business.calendars.entities.BaseCalendar; import org.navalplanner.business.workingday.EffortDuration; @@ -56,20 +55,32 @@ public class SigmoidFunction extends AssignmentFunction { @Override public void applyTo(ResourceAllocation resourceAllocation) { final Task task = resourceAllocation.getTask(); - LocalDate start = LocalDate.fromDateFields(task.getStartDate()); - LocalDate end = LocalDate.fromDateFields(task.getEndDate()); int totalHours = resourceAllocation.getAssignedHours(); + apply(resourceAllocation, task.getStartAsLocalDate(), task.getEndAsLocalDate(), totalHours); + } - apply(resourceAllocation, start, end, totalHours); + private int labourDaysBetween(BaseCalendar calendar, LocalDate start, + LocalDate end) { + EffortDuration capacity; + int result = 0; + + LocalDate day = new LocalDate(start); + while (day.isBefore(end)) { + capacity = calendar.getCapacityOn(PartialDay.wholeDay(day)); + if (!EffortDuration.zero().equals(capacity)) { + result += 1; + } + day = day.plusDays(1); + } + return result != 0 ? result : 1; } private void apply(ResourceAllocation resourceAllocation, LocalDate start, LocalDate end, int totalHours) { - System.out.println("### SigmoidFunction.apply: " + start + "; " + end + "; " + totalHours); - - final int daysDuration = Days.daysBetween(start, end).getDays(); EffortDuration capacity; + BaseCalendar calendar = resourceAllocation.getTask().getCalendar(); + int daysDuration = labourDaysBetween(calendar, start, end); // Calculate hours per day and round values (take only integer part) BigDecimal[] hoursToAllocatePerDay = generateHoursToAllocateFor(daysDuration, totalHours); @@ -80,12 +91,14 @@ public class SigmoidFunction extends AssignmentFunction { assert(totalHoursToAllocate.compareTo(BigDecimal.valueOf(totalHours)) <= 0); BigDecimal remindingHours = BigDecimal.valueOf(totalHours).subtract(totalHoursToAllocate); allocateRemindingHours(hoursToAllocatePerDay, remindingHours); + avoidZeroHoursInDays(hoursToAllocatePerDay); + + assert(hoursToAllocatePerDay.length == daysDuration); // Starting from startDate do allocation, one slot of hours per day in resource - BaseCalendar calendar = resourceAllocation.getTask().getCalendar(); LocalDate day = new LocalDate(start); int hours = 0, i = 0; - for (; i < hoursToAllocatePerDay.length;) { + while (i < hoursToAllocatePerDay.length) { hours = hoursToAllocatePerDay[i].intValue(); capacity = calendar.getCapacityOn(PartialDay.wholeDay(day)); if (!EffortDuration.zero().equals(capacity)) { @@ -98,6 +111,30 @@ public class SigmoidFunction extends AssignmentFunction { clearPreviouslyAllocatedDays(resourceAllocation, day, end); } + /** + * Days with zero hours can occur at the beginning days. + * + * To avoid allocating days with zero hours, we iterate through the days and + * subtract a day from the next day to the current day, until we come up + * with a day which is no zero + * + * @param hoursToAllocatePerDay + */ + private void avoidZeroHoursInDays(BigDecimal[] hoursToAllocatePerDay) { + int length = hoursToAllocatePerDay.length; + for (int i = 0; i < length; i++) { + BigDecimal hours = hoursToAllocatePerDay[i]; + if (hours.doubleValue() != 0) { + return; + } + if (i + 1 <= length) { + BigDecimal next = hoursToAllocatePerDay[i + 1]; + hoursToAllocatePerDay[i + 1] = next.subtract(BigDecimal.ONE); + hoursToAllocatePerDay[i] = hours.add(BigDecimal.ONE); + } + } + } + private void clearPreviouslyAllocatedDays( ResourceAllocation resourceAllocation, LocalDate start, LocalDate end) { @@ -189,6 +226,17 @@ public class SigmoidFunction extends AssignmentFunction { return allocatedHoursPerDay; } + private BigDecimal[] generatePointValuesForDays(int days) { + final BigDecimal dayIntervalConstant = getDayIntervalConstant(days); + + BigDecimal[] result = new BigDecimal[days]; + for (int i = 0; i < days; i++) { + result[i] = BigDecimal.valueOf(-6) + .add(dayIntervalConstant.multiply(BigDecimal.valueOf(i))); + } + return result; + } + private BigDecimal[] calculateNumberOfAllocatedHoursForDays(BigDecimal[] acummulatedHoursPerDay) { BigDecimal[] result = new BigDecimal[acummulatedHoursPerDay.length]; @@ -217,17 +265,6 @@ public class SigmoidFunction extends AssignmentFunction { PRECISSION, ROUND_MODE); } - private BigDecimal[] generatePointValuesForDays(int days) { - final BigDecimal dayIntervalConstant = getDayIntervalConstant(days); - - BigDecimal[] result = new BigDecimal[days]; - for (int i = 0; i < days; i++) { - result[i] = BigDecimal.valueOf(-6) - .add(dayIntervalConstant.multiply(BigDecimal.valueOf(i))); - } - return result; - } - // 12 divide by days private BigDecimal getDayIntervalConstant(int days) { return BigDecimal.valueOf(12).divide(BigDecimal.valueOf(days),