Package com.almende.util

Source Code of com.almende.util.IntervalComparator

package com.almende.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.joda.time.DateTime;

import com.almende.eve.entity.Weight;

/**
* @class WeightsUtil
* Can order and merge a list with weights: intervals in time with a weight
*
* @author Jos de Jong, Almende B.V. 2012
*/
public class WeightsUtil {
  /**
   * Order the intervals by start date
   * @param intervals   A list with time intervals
   */
  public static void order(List<Weight> intervals) {
    class IntervalComparator implements Comparator<Weight> {
      @Override
      public int compare(Weight a, Weight b) {
        if (a.getStart().isAfter(b.getStart())) return 1;
        if (a.getStart().isBefore(b.getStart())) return -1;
        return 0;
      }
    }
   
    IntervalComparator comparator = new IntervalComparator();
    Collections.sort(intervals, comparator);
  }
 
  /**
   * Merge overlapping weighted intervals in given list
   * @param intervals
   * @return
   */
  public static List<Weight> merge(List<Weight> intervals) {   
    // copy the intervals
    ArrayList<Weight> merged = new ArrayList<Weight>();
   
    for (Weight newInterval : intervals) {
      // create a copy of the interval to be merged
      Weight interval = new Weight(newInterval);

      // check if the interval overlaps with any of the others
      int i = 0;
      while (i < merged.size() && interval != null) {
        Weight other = merged.get(i);
        if (interval.getInterval().overlaps(other.getInterval())) {
          // we have an overlap
          // split these two overlapping intervals in three intervals:
          // leftInterval, centerInterval, rightInterval

          // find the start of the left interval
          DateTime start = null;
          Double leftWeight = null;
          if (interval.getStart().isBefore(other.getStart())) {
            start = interval.getStart();
            leftWeight = interval.getWeight();
          }
          else {
            start = other.getStart();
            leftWeight = other.getWeight();
          }
         
          // find the start of the center interval (= end of left interval)
          DateTime centerStart = null;
          if (interval.getStart().isAfter(other.getStart())) {
            centerStart = interval.getStart();
          }
          else {
            centerStart = other.getStart();
          }

          Double centerWeight = interval.getWeight() + other.getWeight();
         
          // find the end of the center interval (= start of right interval)
          DateTime centerEnd = null;
          if (interval.getEnd().isBefore(other.getEnd())) {
            centerEnd = interval.getEnd();
          }
          else {
            centerEnd = other.getEnd();
          }

          // find the end of the right interval
          DateTime end = null;
          Double rightWeight = null;
          if (interval.getEnd().isAfter(other.getEnd())) {
            end = interval.getEnd();
            rightWeight = interval.getWeight();
          }
          else {
            end = other.getEnd();
            rightWeight = other.getWeight();
          }

          // replace old, merged interval with the overlapping part
          if (centerEnd.isAfter(centerStart)) {
            Weight centerInterval = new Weight(
                centerStart, centerEnd, centerWeight);
            merged.set(i, centerInterval);
          }

          // insert a new interval left from the overlapping part
          if (centerStart.isAfter(start)) {
            Weight leftInterval = new Weight(
                start, centerStart, leftWeight);
            merged.add(i, leftInterval);
            i++;
          }
         
          // replace interval with the residual, the non-overlapping
          // right part of the two intervals
          if (end.isAfter(centerEnd)) {
            interval = new Weight(centerEnd, end,
                rightWeight);
          }
          else {
            interval = null;
          }
        }
        else if (interval.getEnd().isBefore(other.getStart()) ||
            interval.getEnd().equals(other.getStart())) {
          // interval is before merged interval. Insert the interval
          // at this position in the list.
          merged.add(i, interval);
          interval = null;
          i++;
        }
        else {
          // interval is after merged interval. check the next merged
          // interval in the list
        }

        i++;
      }
     
      // if interval is not yet merged, add it to the end of the list
      if (interval != null) {
        merged.add(interval);
        interval = null;
      }     
    }
   
    // merge intervals which exactly align
    // (end equals start and weight is the same)
    int i = 1;
    while (i < merged.size()) {
      Weight prev = merged.get(i - 1);
      Weight cur = merged.get(i);
      if (prev.getWeight().equals(cur.getWeight()) &&
          prev.getEnd().equals(cur.getStart())) {
        Weight combi = new Weight(prev.getStart(),
            cur.getEnd(), prev.getWeight());
        merged.set(i - 1, combi);
        merged.remove(i);
        i--;
      }
      i++;
    }
   
    // return merged intervals
    return merged;
  }
 
  // TODO: move tests to a unittest
  public static void main (String[] args) {
    List<Weight> intervals = new ArrayList<Weight>();

    intervals.add(new Weight(
        new DateTime(2012, 8, 4, 8, 0, 0),
        new DateTime(2012, 8, 4, 10, 0, 0),
        new Double(1)));
   
    intervals.add(new Weight(
        new DateTime(2012, 8, 4, 12, 0, 0),
        new DateTime(2012, 8, 4, 14, 0, 0),
        new Double(1)));
   
    intervals.add(new Weight(
        new DateTime(2012, 8, 4, 13, 0, 0),
        new DateTime(2012, 8, 4, 16, 0, 0),
        new Double(1)));

    intervals.add(new Weight(
        new DateTime(2012, 8, 4, 3, 0, 0),
        new DateTime(2012, 8, 4, 4, 0, 0),
        new Double(1)));
   
    intervals.add(new Weight(
        new DateTime(2012, 8, 4, 3, 0, 0),
        new DateTime(2012, 8, 4, 4, 0, 0),
        new Double(1)));
   
    intervals.add(new Weight(
        new DateTime(2012, 8, 4, 3, 0, 0),
        new DateTime(2012, 8, 4, 5, 0, 0),
        new Double(1)));
   
    intervals.add(new Weight(
        new DateTime(2012, 8, 4, 17, 30, 0),
        new DateTime(2012, 8, 4, 18, 0, 0),
        new Double(1.5)));
    intervals.add(new Weight(
        new DateTime(2012, 8, 4, 17, 0, 0),
        new DateTime(2012, 8, 4, 17, 30, 0),
        new Double(1.5)));
   
    List<Weight> merged = WeightsUtil.merge(intervals);
    for (Weight i : merged) {
      System.out.println(i);
    }
  }
}
TOP

Related Classes of com.almende.util.IntervalComparator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.