1 module mutils.timeline.trace; 2 3 import mutils.container.sorted_vector; 4 import mutils.container.vector; 5 import mutils.linalg.algorithm; 6 import mutils.timeline.utils; 7 8 /** 9 * 10 * Class to get interpolated(mix) T value in given time, useful for contigious paths 11 * 12 */ 13 struct Trace(T, alias mixFunction = mix) { 14 SortedVector!(DataPoint, "a.time < b.time") data; 15 TimeIndexGetter indexGetter; 16 17 struct DataPoint { 18 T point; 19 float time = 0; 20 } 21 22 void add(T point, float time) { 23 data ~= DataPoint(point, time); 24 } 25 26 void remove(size_t i) { 27 data.remove(i); 28 } 29 30 T get(ref TimeIndexGetter getter, ref float time, bool loop) { 31 uint[2] ti = getter.index(data[], time); 32 DataPoint curr = data[ti[0]]; 33 DataPoint next = data[ti[1]]; 34 if (ti[0] == ti[1]) { 35 if (loop) { 36 time = 0; 37 } 38 return curr.point; 39 } 40 float blend = (time - curr.time) / (next.time - curr.time); 41 return mixFunction(curr.point, next.point, blend); 42 } 43 44 T get(float time) { 45 uint[2] ti = indexGetter.index(data[], time); 46 DataPoint curr = data[ti[0]]; 47 DataPoint next = data[ti[1]]; 48 if (ti[0] == ti[1]) { 49 return curr.point; 50 } 51 float blend = (time - curr.time) / (next.time - curr.time); 52 return mixFunction(curr.point, next.point, blend); 53 } 54 55 } 56 57 unittest { 58 import mutils.linalg.vec; 59 60 alias vec2i = Vec!(int, 2); //ints because there are no precision errors 61 alias TraceVec2i = Trace!(vec2i); 62 TraceVec2i trace; 63 trace.add(vec2i(0, 0), 0); 64 trace.add(vec2i(0, 0), 2); 65 trace.add(vec2i(2, 2), 1); 66 trace.add(vec2i(2, 2), 3); 67 68 assert(trace.data[2].point == vec2i(0, 0)); 69 70 assert(trace.get(-10) == vec2i(0, 0)); 71 assert(trace.get(0) == vec2i(0, 0)); 72 assert(trace.get(1) == vec2i(2, 2)); 73 assert(trace.get(2.5) == vec2i(1, 1)); 74 assert(trace.get(5) == vec2i(2, 2)); 75 assert(trace.get(-10) == vec2i(0, 0)); 76 assert(trace.get(0) == vec2i(0, 0)); 77 }