Blame mono/Assistance/Track.cs

cfceb0
using System;
cfceb0
using System.Collections.Generic;
b82ef4
using Assistance.Drawing;
cfceb0
cfceb0
namespace Assistance {
cfceb0
	public class Track {
589f9a
		public interface IOwner { }
61bedf
a62e15
		public class Handler {
589f9a
			public readonly IOwner owner;
a62e15
			public readonly Track original;
a62e15
			public readonly List<track> tracks = new List<track>();
589f9a
			public Handler(IOwner owner, Track original) {
a62e15
				this.owner = owner;
a62e15
				this.original = original;
a62e15
			}
a62e15
		}
a62e15
a62e15
		public class Modifier {
a62e15
			public readonly Handler handler;
a62e15
			public readonly double timeOffset;
a62e15
a62e15
			public Modifier(Handler handler, double timeOffset = 0.0)
a62e15
				{ this.handler = handler; this.timeOffset = timeOffset; }
589f9a
			public IOwner owner
a62e15
				{ get { return handler.owner; } }
a62e15
			public Track original
a62e15
				{ get { return handler.original; } }
c3ebff
			public virtual WayPoint calcWayPoint(double originalIndex)
a62e15
				{ return original.calcWayPoint(originalIndex); }
a62e15
		}
a62e15
a62e15
		public struct Point {
a62e15
			public Assistance.Point position;
a62e15
			public double pressure;
589f9a
			public Assistance.Point tilt;
a62e15
	
a62e15
			public Point(
a62e15
				Assistance.Point position,
a62e15
				double pressure,
589f9a
				Assistance.Point tilt
a62e15
			) {
a62e15
				this.position = position;
a62e15
				this.pressure = pressure;
a62e15
				this.tilt = tilt;
a62e15
			}
a62e15
			
a62e15
			public static Point operator+ (Point a, Point b)
a62e15
				{ return new Point(a.position + b.position, a.pressure + b.pressure, a.tilt + b.tilt); }
a62e15
			public static Point operator- (Point a, Point b)
a62e15
				{ return new Point(a.position - b.position, a.pressure - b.pressure, a.tilt - b.tilt); }
a62e15
			public static Point operator* (Point a, double b)
a62e15
				{ return new Point(a.position*b, a.pressure*b, a.tilt*b); }
589f9a
			public static Point operator* (double a, Point b)
a62e15
				{ return a*b; }
a62e15
			public static Point operator/ (Point a, double b)
589f9a
				{ return a*(1.0/b); }
a62e15
	
a62e15
			public bool isEqual(Point other) {
a62e15
				return position.isEqual(other.position)
a62e15
					&& Geometry.isEqual(pressure, other.pressure)
a62e15
					&& tilt.isEqual(other.tilt);
a62e15
			}
a62e15
	
a62e15
			public Point normalize() {
a62e15
				double l = position.len();
a62e15
				return l > Geometry.precision ? this/l : this;
a62e15
			}
a62e15
		}
a62e15
a62e15
		public struct WayPoint {
a62e15
			public Point point;
a62e15
			public Point tangent;
a62e15
a62e15
			public double originalIndex;
a62e15
			public double time;
a62e15
			public double length;
a62e15
			
61bedf
			public int depRootIndex;
a62e15
			public bool final;
a62e15
	
a62e15
			public WayPoint(
a62e15
				Point point,
61bedf
				Point tangent = new Point(),
a62e15
				double originalIndex = 0.0,
a62e15
				double time = 0.0,
a62e15
				double length = 0.0,
61bedf
				int depRootIndex = 0,
a62e15
				bool final = false
a62e15
			) {
a62e15
				this.point = point;
a62e15
				this.tangent = tangent;
a62e15
				this.originalIndex = originalIndex;
a62e15
				this.time = time;
a62e15
				this.length = length;
61bedf
				this.depRootIndex = depRootIndex;
a62e15
				this.final = final;
a62e15
			}
a62e15
		}
a62e15
		
77e178
61bedf
		private static long lastId;
77e178
		
61bedf
		public readonly long id;
c66393
		public readonly Gdk.Device device;
61bedf
		public readonly long touchId;
a62e15
		public readonly List<waypoint> points = new List<waypoint>();</waypoint></waypoint>
a62e15
		public readonly KeyHistory<gdk.key>.Holder keyHistory;</gdk.key>
a62e15
		public readonly KeyHistory<uint>.Holder buttonHistory;</uint>
cfceb0
a62e15
		public readonly Modifier modifier;
a62e15
		
a62e15
		public Handler handler;
a62e15
		public int wayPointsRemoved;
a62e15
		public int wayPointsAdded;
77c1c7
a62e15
		public Track(
61bedf
			Gdk.Device device = null,
61bedf
			long touchId = 0,
61bedf
			KeyHistory<gdk.key>.Holder keyHistory = null,</gdk.key>
61bedf
			KeyHistory<uint>.Holder buttonHistory = null</uint>
a62e15
		) {
61bedf
			this.id = ++lastId;
c66393
			this.device = device;
61bedf
			this.touchId = touchId;
a62e15
			this.keyHistory = keyHistory;
a62e15
			this.buttonHistory = buttonHistory;
c66393
		}
a62e15
		
61bedf
		public Track(Modifier modifier):
a62e15
			this( modifier.original.device,
589f9a
				  modifier.original.touchId,
a62e15
				  modifier.original.keyHistory.offset( modifier.timeOffset ),
61bedf
				  modifier.original.buttonHistory.offset( modifier.timeOffset ) )
a62e15
			{ this.modifier = modifier; }
77c1c7
a62e15
		public Track original
a62e15
			{ get { return modifier != null ? modifier.original : null; } }
a62e15
		public double timeOffset
a62e15
			{ get { return modifier != null ? modifier.timeOffset : 0.0; } }
720280
		public long ticks
720280
			{ get { return keyHistory.ticks; } }
c3ebff
			
c3ebff
		public bool isChanged
c3ebff
			{ get { return wayPointsAdded != 0 || wayPointsRemoved != 0; } }
77c1c7
a62e15
		public Track getRoot()
a62e15
			{ return original == null ? this : original.getRoot(); }
a62e15
		public int getLevel()
a62e15
			{ return original == null ? 0 : original.getLevel() + 1; }
c66393
		
a62e15
		public WayPoint getFirst()
a62e15
			{ return getWayPoint(0); }
a62e15
		public WayPoint getLast()
a62e15
			{ return getWayPoint(points.Count - 1); }
a62e15
		public bool isFinished()
0f2bf8
			{ return points.Count > 0 && getLast().final; }
a62e15
		
a62e15
		public int clampIndex(int index)
a62e15
			{ return Math.Min(Math.Max(index, 0), points.Count - 1); }
a62e15
		public int floorIndex(double index, out double frac) {
a62e15
			int i = (int)Math.Floor(index + Geometry.precision);
a62e15
			if (i > points.Count - 1)
a62e15
				{ frac = 0.0; return points.Count - 1; }
a62e15
			if (i < 0)
a62e15
				{ frac = 0.0; return 0; }
a62e15
			frac = Math.Max(0.0, index - (double)i);
a62e15
			return i;
72b17c
		}
1cdf17
		public int floorIndexNoClamp(double index)
1cdf17
			{ return (int)Math.Floor(index + Geometry.precision); }
a62e15
		public int floorIndex(double index)
1cdf17
			{ return clampIndex(floorIndexNoClamp(index)); }
1cdf17
		public int ceilIndexNoClamp(double index)
1cdf17
			{ return (int)Math.Ceiling(index - Geometry.precision); }
a62e15
		public int ceilIndex(double index)
1cdf17
			{ return clampIndex(ceilIndexNoClamp(index)); }
a62e15
		
a62e15
		public WayPoint getWayPoint(int index) {
a62e15
			index = clampIndex(index);
a62e15
			return index < 0 ? new WayPoint() : points[index];
77c1c7
		}
a62e15
		public WayPoint floorWayPoint(double index, out double frac)
a62e15
			{ return getWayPoint(floorIndex(index, out frac)); }
a62e15
		public WayPoint floorWayPoint(double index)
a62e15
			{ return getWayPoint(floorIndex(index)); }
a62e15
		public WayPoint ceilWayPoint(double index)
0f2bf8
			{ return getWayPoint(ceilIndex(index)); }
77c1c7
		
a62e15
		private delegate double WayPointFieldGetter(WayPoint p);
a62e15
		private double binarySearch(double value, WayPointFieldGetter getter) {
a62e15
			// points[a].value <= value < points[b].value
77c1c7
			
a62e15
			if (points.Count <= 0) return 0.0;
a62e15
			int a = 0;
a62e15
			double aa = getter(points[a]);
0f2bf8
			if (Geometry.isLess(value, aa)) return 0.0;
a62e15
a62e15
			int b = points.Count - 1;
a62e15
			double bb = getter(points[b]);
a62e15
			if (Geometry.isGreaterOrEqual(value, bb)) return (double)b;
77c1c7
			
a62e15
			while(true) {
a62e15
				int c = (a + b)/2;
a62e15
				if (a == c) break;
a62e15
				double cc = getter(points[c]);
a62e15
				if (Geometry.isLess(value, cc))
a62e15
					{ b = c; bb = cc; } else { a = c; aa = cc; }
77c1c7
			}
a62e15
1cdf17
			return Geometry.isLess(aa, bb) ? (double)a + (value - aa)/(bb - aa) : (double)a;
a62e15
		}
77c1c7
			
a62e15
		public double indexByOriginalIndex(double originalIndex)
a62e15
			{ return binarySearch(originalIndex, delegate(WayPoint p) { return p.originalIndex; }); }
a62e15
		public double indexByTime(double time)
a62e15
			{ return binarySearch(time, delegate(WayPoint p) { return p.time; }); }
a62e15
		public double indexByLength(double length)
a62e15
			{ return binarySearch(length, delegate(WayPoint p) { return p.length; }); }
a62e15
		
a62e15
		public double originalIndexByIndex(double index) {
a62e15
			double frac;
a62e15
			WayPoint p0 = floorWayPoint(index, out frac), p1 = ceilWayPoint(index);
a62e15
			return Geometry.interpolationLinear(p0.originalIndex, p1.originalIndex, frac);
a62e15
		}
a62e15
		public double timeByIndex(double index) {
a62e15
			double frac;
a62e15
			WayPoint p0 = floorWayPoint(index, out frac), p1 = ceilWayPoint(index);
a62e15
			return Geometry.interpolationLinear(p0.time, p1.time, frac);
a62e15
		}
a62e15
		public double lengthByIndex(double index) {
a62e15
			double frac;
a62e15
			WayPoint p0 = floorWayPoint(index, out frac), p1 = ceilWayPoint(index);
a62e15
			return Geometry.interpolationLinear(p0.length, p1.length, frac);
77c1c7
		}
cfceb0
a62e15
		public WayPoint calcWayPoint(double index) {
a62e15
			return modifier == null
a62e15
			     ? interpolate(index)
a62e15
			     : modifier.calcWayPoint( originalIndexByIndex(index) );
a62e15
		}
a62e15
		
a62e15
		public WayPoint interpolate(double index) {
a62e15
			double frac;
589f9a
			WayPoint p0 = floorWayPoint(index, out frac);
a62e15
			WayPoint p1 = ceilWayPoint(index);
a62e15
			return interpolate(p0, p1, frac);
a62e15
		}
a62e15
a62e15
		public static WayPoint interpolate(WayPoint p0, WayPoint p1, double l) {
a62e15
			if (l <= Geometry.precision) return p0;
a62e15
			if (l >= 1.0 - Geometry.precision) return p1;
a62e15
			return new WayPoint(
0f2bf8
				Geometry.interpolationSpline(p0.point, p1.point, p0.tangent, p1.tangent, l),
0f2bf8
				Geometry.interpolationSplineTangent(p0.point, p1.point, p0.tangent, p1.tangent, l),
a62e15
				Geometry.interpolationLinear(p0.originalIndex, p1.originalIndex, l),
a62e15
				Geometry.interpolationLinear(p0.time, p1.time, l),
61bedf
				Geometry.interpolationLinear(p0.length, p1.length, l),
61bedf
				p1.depRootIndex );
cfceb0
		}
cfceb0
	}
cfceb0
}
cfceb0