ItEr49S10CUVisualizacionResponsabilidadesTRaballoNaPlanificacionItEr48S10: Adding or operation to AvailabilityTimeLine

This commit is contained in:
Óscar González Fernández 2010-02-28 21:34:09 +01:00
parent 4ca561567a
commit 25bf19c453
2 changed files with 161 additions and 11 deletions

View file

@ -137,6 +137,11 @@ public class AvailabilityTimeLine {
public String toString() {
return date.toString();
}
public static LocalDate tryExtract(DatePoint start) {
FixedPoint point = (FixedPoint) start;
return point.getDate();
}
}
public static class EndOfTime extends DatePoint {
@ -299,6 +304,11 @@ public class AvailabilityTimeLine {
&& end.compareTo(other.start) >= 0;
}
public Interval intersect(Interval other) {
Validate.isTrue(overlaps(other));
return new Interval(max(start, other.start), min(end, other.end));
}
public Interval coalesce(Interval other) {
if (!overlaps(other)) {
throw new IllegalArgumentException(
@ -361,37 +371,63 @@ public class AvailabilityTimeLine {
}
private void insert(Interval toBeInserted) {
int binarySearch = Collections.binarySearch(invalids, toBeInserted);
if (invalids.isEmpty()) {
invalids.add(toBeInserted);
return;
}
toBeInserted = coalesceWithAdjacent(insertionPoint(binarySearch),
toBeInserted);
toBeInserted = coalesceWithAdjacent(toBeInserted);
int insertionPoint = insertBeforeAllAdjacent(toBeInserted);
removeAdjacent(insertionPoint, toBeInserted);
}
/**
* Returns the insertion position for the interval. Inserting the interval
* at that position guarantees that interval start is posterior or equal to
* any previous interval start. If the next interval start is equal to the
* interval, the length of the former is less than the latter
*/
private int findInsertionPosition(Interval interval) {
int binarySearch = Collections.binarySearch(invalids, interval);
return insertionPoint(binarySearch);
}
private int insertBeforeAllAdjacent(Interval toBeInserted) {
int n = Collections.binarySearch(invalids, toBeInserted);
int insertionPoint = insertionPoint(n);
int insertionPoint = findInsertionPosition(toBeInserted);
invalids.add(insertionPoint, toBeInserted);
return insertionPoint;
}
private Interval coalesceWithAdjacent(int insertionPoint,
Interval toBeInserted) {
private Interval coalesceWithAdjacent(Interval toBeInserted) {
Interval result = toBeInserted;
List<Interval> adjacent = getAdjacent(toBeInserted);
for (Interval each : adjacent) {
result = result.coalesce(each);
}
return result;
}
private List<Interval> getAdjacent(Interval toBeInserted) {
final int insertionPoint = findInsertionPosition(toBeInserted);
List<Interval> result = new ArrayList<Interval>();
for (int i = insertionPoint; i >= 0
&& (i == invalids.size() || at(i).overlaps(
toBeInserted)); i--) {
&& (i == invalids.size() || at(i).overlaps(toBeInserted)); i--) {
if (i < invalids.size()) {
result = result.coalesce(at(i));
result.add(at(i));
}
}
for (int i = insertionPoint; i < invalids.size()
&& at(i).overlaps(toBeInserted); i++) {
result = result.coalesce(at(i));
result.add(at(i));
}
return result;
}
private List<Interval> intersectWithAdjacent(Interval interval) {
List<Interval> result = new ArrayList<Interval>();
List<Interval> adjacent = getAdjacent(interval);
for (Interval each : adjacent) {
assert interval.overlaps(each);
result.add(interval.intersect(each));
}
return result;
}
@ -440,6 +476,36 @@ public class AvailabilityTimeLine {
return result;
}
public AvailabilityTimeLine or(AvailabilityTimeLine another) {
List<Interval> intersections = doIntersections(this, another);
AvailabilityTimeLine result = AvailabilityTimeLine.allValid();
for (Interval each : intersections) {
boolean fromStartOfTime = each.getStart().equals(
StartOfTime.create());
boolean untilEndOfTime = each.getEnd().equals(EndOfTime.create());
if (fromStartOfTime && untilEndOfTime) {
result.allInvalid();
} else if (fromStartOfTime) {
result.invalidUntil(FixedPoint.tryExtract(each.getEnd()));
} else if (untilEndOfTime) {
result.invalidFrom(FixedPoint.tryExtract(each.getStart()));
} else {
result.invalidAt(FixedPoint.tryExtract(each.getStart()),
FixedPoint.tryExtract(each.getEnd()));
}
}
return result;
}
private static List<Interval> doIntersections(AvailabilityTimeLine one,
AvailabilityTimeLine another) {
List<Interval> result = new ArrayList<Interval>();
for (Interval each : one.invalids) {
result.addAll(another.intersectWithAdjacent(each));
}
return result;
}
private void inserting(AvailabilityTimeLine result, List<Interval> invalid) {
for (Interval each : invalid) {
result.insert(each);

View file

@ -234,6 +234,90 @@ public class AvailabilityTimeLineTest {
}
}
@Test
public void doingOROnTwoTimeLinesResultingOnAnAllValidTimeLine() {
AvailabilityTimeLine one = AvailabilityTimeLine.allValid();
one.invalidAt(contemporaryExample.minusDays(40), contemporaryExample
.minusDays(20));
AvailabilityTimeLine another = AvailabilityTimeLine.allValid();
another.invalidAt(contemporaryExample.minusDays(10),
contemporaryExample.plusDays(10));
AvailabilityTimeLine result = one.or(another);
assertThat(result.getValidPeriods(), definedBy(StartOfTime.create(),
EndOfTime.create()));
}
@Test
public void doingORonTwoTimeLinesWithSeveralIntersectingInvalidPeriods() {
AvailabilityTimeLine one = AvailabilityTimeLine.allValid();
one.invalidAt(contemporaryExample.minusDays(40), contemporaryExample
.minusDays(20));
one.invalidAt(contemporaryExample.plusDays(35), contemporaryExample
.plusDays(50));
AvailabilityTimeLine another = AvailabilityTimeLine.allValid();
another.invalidAt(contemporaryExample.minusDays(25),
contemporaryExample.plusDays(10));
another.invalidAt(contemporaryExample.plusDays(30), contemporaryExample
.plusDays(40));
AvailabilityTimeLine result = one.or(another);
assertThat(result.getValidPeriods(), definedBy(StartOfTime.create(),
point(contemporaryExample.minusDays(25)),
point(contemporaryExample.minusDays(20)),
point(contemporaryExample.plusDays(35)),
point(contemporaryExample.plusDays(40)), EndOfTime.create()));
}
@Test
public void doingOROnTheSameTimeLineResultsInTheSameTimeLine() {
AvailabilityTimeLine timeLine = AvailabilityTimeLine.allValid();
timeLine.invalidAt(earlyExample, contemporaryExample);
timeLine.invalidAt(lateExample, lateExample.plusDays(20));
AvailabilityTimeLine result = timeLine.or(timeLine);
assertThat(result.getValidPeriods(), definedBy(StartOfTime.create(),
point(earlyExample), point(contemporaryExample),
point(lateExample), point(lateExample
.plusDays(20)), EndOfTime.create()));
}
@Test
public void doingAnAndWithAnAllValidTimeLineProducesTheSameTimeLine() {
AvailabilityTimeLine timeLine = AvailabilityTimeLine.allValid();
timeLine.invalidAt(earlyExample, contemporaryExample);
timeLine.invalidAt(lateExample, lateExample.plusDays(20));
AvailabilityTimeLine result = timeLine.and(AvailabilityTimeLine
.allValid());
assertThat(result.getValidPeriods(), definedBy(StartOfTime.create(),
point(earlyExample), point(contemporaryExample),
point(lateExample), point(lateExample
.plusDays(20)), EndOfTime.create()));
}
@Test
public void doingAnOrWithANeverValidTimeLineProducesTheSameTimeLine() {
AvailabilityTimeLine timeLine = AvailabilityTimeLine.allValid();
timeLine.invalidAt(earlyExample, contemporaryExample);
timeLine.invalidAt(lateExample, lateExample.plusDays(20));
AvailabilityTimeLine another = AvailabilityTimeLine.allValid();
another.allInvalid();
AvailabilityTimeLine result = timeLine.and(another);
assertThat(result.getValidPeriods(), definedBy(StartOfTime.create(),
point(earlyExample), point(contemporaryExample),
point(lateExample), point(lateExample.plusDays(20)), EndOfTime
.create()));
}
@Test
public void anAllValidPeriodsGeneratesAnAllEncompassingInterval() {
AvailabilityTimeLine timeLine = AvailabilityTimeLine.allValid();