package edu.gatech.cs2340.trydent.math.curve; import java.util.Arrays; import edu.gatech.cs2340.trydent.internal.TrydentInternalException; /** * TimingHandler which permits arbitrary durations for each span. (Advanced * functionality). */ public class ArbitraryTiming implements SplineTimingHandler { private double[] durations; private double[] times; private double totalDuration = 0; /** * Creates a new ArbitraryTiming object with the given array of durations, * such that the duration of the ith span is the ith value of the array. * (Advanced functionality). * * @param durations * array of durations as described above */ public ArbitraryTiming(double[] durations) { this.durations = durations; this.times = new double[durations.length]; int i = 0; for (double d : durations) { this.times[i++] = this.totalDuration; this.totalDuration += d; } } @Override public SpanTime transformTime(double time) { if (time < 0) time = 0; if (time > totalDuration) time = totalDuration; int left = 0; int right = times.length - 1; int index = (int) (time * (times.length - 1) / totalDuration); int iterations = 0; // While time is not between (times[index]) and (times[index] + // durations[index]) while (time > times[index] + durations[index] || time < times[index]) { if (left == right && index == left) { throw new TrydentInternalException( "Impossible timing occurred. This may indicate an internal logical programming error." + "\nTime = " + time + "\nTimes = " + Arrays.toString(times) + "\nDurations = " + Arrays.toString(durations)); } // Time at index is too big if (times[index] > time) { right = index - 1; } // Time at index is too small if (times[index] + durations[index] < time) { left = index + 1; } if (left > right) throw new TrydentInternalException( "Impossible timing occurred. This may indicate an internal logical programming error."); index = (left + right) / 2; iterations++; if (iterations > times.length + 1) { throw new TrydentInternalException( "BinarySearch is taking longer than O(n+1), something is seriously wrong.\n" + "time=" + time + ", left=" + left + ", right=" + right + ", index=" + index); } } return new SpanTime(index, (time - times[index]) / durations[index]); } }