int toRatio)
{
this();
+ fromRange = coalesceRanges(fromRange);
+ toRange = coalesceRanges(toRange);
this.fromShifts = fromRange;
this.toShifts = toRange;
this.fromRatio = fromRatio;
}
/**
+ * Consolidates a list of ranges so that any contiguous ranges are merged
+ *
+ * @param ranges
+ * @return
+ */
+ public static List<int[]> coalesceRanges(List<int[]> ranges)
+ {
+ if (ranges == null || ranges.size() < 2) {
+ return ranges;
+ }
+
+ boolean changed = false;
+ List<int[]> merged = new ArrayList<int[]>();
+ int[] lastRange = ranges.get(0);
+ int lastDirection = lastRange[1] >= lastRange[0] ? 1 : -1;
+ merged.add(lastRange);
+
+ for (int[] range : ranges)
+ {
+ if (range == lastRange)
+ {
+ continue;
+ }
+ int direction = range[1] >= range[0] ? 1 : -1;
+
+ /*
+ * if next range is in the same direction as last and contiguous,
+ * just update the end position of the last range
+ */
+ if ((range[1] == range[0] || direction == lastDirection)
+ && (range[0] == lastRange[1] || range[0] == lastRange[1]
+ + lastDirection))
+ {
+ lastRange[1] = range[1];
+ changed = true;
+ }
+ else
+ {
+ merged.add(range);
+ lastRange = range;
+ // careful: merging [5, 5] after [7, 6] should keep negative direction
+ lastDirection = (range[1] == range[0]) ? lastDirection : direction;
+ }
+ }
+
+ return changed ? merged : ranges;
+ }
+
+ /**
* get all mapped positions from 'from' to 'to'
*
* @return int[][] { int[] { fromStart, fromFinish, toStart, toFinish }, int