Blame mono/Assistance/Track.cs

Ivan Mahonin cfceb0
using System;
Ivan Mahonin cfceb0
using System.Collections.Generic;
Ivan Mahonin b82ef4
using Assistance.Drawing;
Ivan Mahonin cfceb0
Ivan Mahonin cfceb0
namespace Assistance {
Ivan Mahonin cfceb0
	public class Track {
Ivan Mahonin 589f9a
		public interface IOwner { }
Ivan Mahonin 61bedf
Ivan Mahonin a62e15
		public class Handler {
Ivan Mahonin 589f9a
			public readonly IOwner owner;
Ivan Mahonin a62e15
			public readonly Track original;
Ivan Mahonin a62e15
			public readonly List<Track> tracks = new List<Track>();
Ivan Mahonin 589f9a
			public Handler(IOwner owner, Track original) {
Ivan Mahonin a62e15
				this.owner = owner;
Ivan Mahonin a62e15
				this.original = original;
Ivan Mahonin a62e15
			}
Ivan Mahonin a62e15
		}
Ivan Mahonin a62e15
Ivan Mahonin a62e15
		public class Modifier {
Ivan Mahonin a62e15
			public readonly Handler handler;
Ivan Mahonin a62e15
			public readonly double timeOffset;
Ivan Mahonin a62e15
Ivan Mahonin a62e15
			public Modifier(Handler handler, double timeOffset = 0.0)
Ivan Mahonin a62e15
				{ this.handler = handler; this.timeOffset = timeOffset; }
Ivan Mahonin 589f9a
			public IOwner owner
Ivan Mahonin a62e15
				{ get { return handler.owner; } }
Ivan Mahonin a62e15
			public Track original
Ivan Mahonin a62e15
				{ get { return handler.original; } }
Ivan Mahonin 702257
			public virtual Point calcPoint(double originalIndex) {
Ivan Mahonin 702257
				Point p = original.calcPoint(originalIndex);
Ivan Mahonin 7bbf70
				p.originalIndex = originalIndex;
Ivan Mahonin 7bbf70
				return p;
Ivan Mahonin 7bbf70
			}
Ivan Mahonin a62e15
		}
Ivan Mahonin a62e15
Ivan Mahonin a62e15
		public struct Point {
Ivan Mahonin a62e15
			public Assistance.Point position;
Ivan Mahonin a62e15
			public double pressure;
Ivan Mahonin 589f9a
			public Assistance.Point tilt;
Ivan Mahonin a62e15
Ivan Mahonin a62e15
			public double originalIndex;
Ivan Mahonin a62e15
			public double time;
Ivan Mahonin a62e15
			public double length;
Ivan Mahonin a62e15
			
Ivan Mahonin a62e15
			public bool final;
Ivan Mahonin a62e15
	
Ivan Mahonin 702257
			public Point(
Ivan Mahonin 702257
				Assistance.Point position,
Ivan Mahonin 702257
				double pressure = 0.5,
Ivan Mahonin 702257
				Assistance.Point tilt = new Assistance.Point(),
Ivan Mahonin a62e15
				double originalIndex = 0.0,
Ivan Mahonin a62e15
				double time = 0.0,
Ivan Mahonin a62e15
				double length = 0.0,
Ivan Mahonin a62e15
				bool final = false
Ivan Mahonin a62e15
			) {
Ivan Mahonin 702257
				this.position = position;
Ivan Mahonin 702257
				this.pressure = pressure;
Ivan Mahonin 702257
				this.tilt = tilt;
Ivan Mahonin a62e15
				this.originalIndex = originalIndex;
Ivan Mahonin a62e15
				this.time = time;
Ivan Mahonin a62e15
				this.length = length;
Ivan Mahonin a62e15
				this.final = final;
Ivan Mahonin a62e15
			}
Ivan Mahonin a62e15
		}
Ivan Mahonin a62e15
		
Ivan Mahonin 77e178
Ivan Mahonin 61bedf
		private static long lastId;
Ivan Mahonin 77e178
		
Ivan Mahonin 61bedf
		public readonly long id;
Ivan Mahonin c66393
		public readonly Gdk.Device device;
Ivan Mahonin 61bedf
		public readonly long touchId;
Ivan Mahonin 702257
		public readonly List<Point> points = new List<Point>();
Ivan Mahonin a62e15
		public readonly KeyHistory<Gdk.Key>.Holder keyHistory;
Ivan Mahonin a62e15
		public readonly KeyHistory<uint>.Holder buttonHistory;
Ivan Mahonin cfceb0
Ivan Mahonin a62e15
		public readonly Modifier modifier;
Ivan Mahonin a62e15
		
Ivan Mahonin a62e15
		public Handler handler;
Ivan Mahonin a62e15
		public int wayPointsRemoved;
Ivan Mahonin a62e15
		public int wayPointsAdded;
Ivan Mahonin 77c1c7
Ivan Mahonin a62e15
		public Track(
Ivan Mahonin 61bedf
			Gdk.Device device = null,
Ivan Mahonin 61bedf
			long touchId = 0,
Ivan Mahonin 61bedf
			KeyHistory<Gdk.Key>.Holder keyHistory = null,
Ivan Mahonin 61bedf
			KeyHistory<uint>.Holder buttonHistory = null
Ivan Mahonin a62e15
		) {
Ivan Mahonin 61bedf
			this.id = ++lastId;
Ivan Mahonin c66393
			this.device = device;
Ivan Mahonin 61bedf
			this.touchId = touchId;
Ivan Mahonin a62e15
			this.keyHistory = keyHistory;
Ivan Mahonin a62e15
			this.buttonHistory = buttonHistory;
Ivan Mahonin c66393
		}
Ivan Mahonin a62e15
		
Ivan Mahonin 61bedf
		public Track(Modifier modifier):
Ivan Mahonin a62e15
			this( modifier.original.device,
Ivan Mahonin 589f9a
				  modifier.original.touchId,
Ivan Mahonin a62e15
				  modifier.original.keyHistory.offset( modifier.timeOffset ),
Ivan Mahonin 61bedf
				  modifier.original.buttonHistory.offset( modifier.timeOffset ) )
Ivan Mahonin a62e15
			{ this.modifier = modifier; }
Ivan Mahonin 77c1c7
Ivan Mahonin a62e15
		public Track original
Ivan Mahonin a62e15
			{ get { return modifier != null ? modifier.original : null; } }
Ivan Mahonin a62e15
		public double timeOffset
Ivan Mahonin a62e15
			{ get { return modifier != null ? modifier.timeOffset : 0.0; } }
Ivan Mahonin 720280
		public long ticks
Ivan Mahonin 720280
			{ get { return keyHistory.ticks; } }
Ivan Mahonin c3ebff
			
Ivan Mahonin c3ebff
		public bool isChanged
Ivan Mahonin c3ebff
			{ get { return wayPointsAdded != 0 || wayPointsRemoved != 0; } }
Ivan Mahonin 77c1c7
Ivan Mahonin a62e15
		public Track getRoot()
Ivan Mahonin a62e15
			{ return original == null ? this : original.getRoot(); }
Ivan Mahonin a62e15
		public int getLevel()
Ivan Mahonin a62e15
			{ return original == null ? 0 : original.getLevel() + 1; }
Ivan Mahonin c66393
		
Ivan Mahonin 702257
		public Point getFirst()
Ivan Mahonin 702257
			{ return getPoint(0); }
Ivan Mahonin 702257
		public Point getLast()
Ivan Mahonin 702257
			{ return getPoint(points.Count - 1); }
Ivan Mahonin a62e15
		public bool isFinished()
Ivan Mahonin 0f2bf8
			{ return points.Count > 0 && getLast().final; }
Ivan Mahonin a62e15
		
Ivan Mahonin a62e15
		public int clampIndex(int index)
Ivan Mahonin a62e15
			{ return Math.Min(Math.Max(index, 0), points.Count - 1); }
Ivan Mahonin a62e15
		public int floorIndex(double index, out double frac) {
Ivan Mahonin a62e15
			int i = (int)Math.Floor(index + Geometry.precision);
Ivan Mahonin a62e15
			if (i > points.Count - 1)
Ivan Mahonin a62e15
				{ frac = 0.0; return points.Count - 1; }
Ivan Mahonin a62e15
			if (i < 0)
Ivan Mahonin a62e15
				{ frac = 0.0; return 0; }
Ivan Mahonin a62e15
			frac = Math.Max(0.0, index - (double)i);
Ivan Mahonin a62e15
			return i;
Ivan Mahonin 72b17c
		}
Ivan Mahonin 1cdf17
		public int floorIndexNoClamp(double index)
Ivan Mahonin 1cdf17
			{ return (int)Math.Floor(index + Geometry.precision); }
Ivan Mahonin a62e15
		public int floorIndex(double index)
Ivan Mahonin 1cdf17
			{ return clampIndex(floorIndexNoClamp(index)); }
Ivan Mahonin 1cdf17
		public int ceilIndexNoClamp(double index)
Ivan Mahonin 1cdf17
			{ return (int)Math.Ceiling(index - Geometry.precision); }
Ivan Mahonin a62e15
		public int ceilIndex(double index)
Ivan Mahonin 1cdf17
			{ return clampIndex(ceilIndexNoClamp(index)); }
Ivan Mahonin a62e15
		
Ivan Mahonin 702257
		public Point getPoint(int index) {
Ivan Mahonin a62e15
			index = clampIndex(index);
Ivan Mahonin 702257
			return index < 0 ? new Point() : points[index];
Ivan Mahonin 77c1c7
		}
Ivan Mahonin 702257
		public Point floorPoint(double index, out double frac)
Ivan Mahonin 702257
			{ return getPoint(floorIndex(index, out frac)); }
Ivan Mahonin 702257
		public Point floorPoint(double index)
Ivan Mahonin 702257
			{ return getPoint(floorIndex(index)); }
Ivan Mahonin 702257
		public Point ceilPoint(double index)
Ivan Mahonin 702257
			{ return getPoint(ceilIndex(index)); }
Ivan Mahonin 77c1c7
		
Ivan Mahonin 702257
		private delegate double PointFieldGetter(Point p);
Ivan Mahonin 702257
		private double binarySearch(double value, PointFieldGetter getter) {
Ivan Mahonin a62e15
			// points[a].value <= value < points[b].value
Ivan Mahonin 77c1c7
			
Ivan Mahonin a62e15
			if (points.Count <= 0) return 0.0;
Ivan Mahonin a62e15
			int a = 0;
Ivan Mahonin a62e15
			double aa = getter(points[a]);
Ivan Mahonin 0f2bf8
			if (Geometry.isLess(value, aa)) return 0.0;
Ivan Mahonin a62e15
Ivan Mahonin a62e15
			int b = points.Count - 1;
Ivan Mahonin a62e15
			double bb = getter(points[b]);
Ivan Mahonin a62e15
			if (Geometry.isGreaterOrEqual(value, bb)) return (double)b;
Ivan Mahonin 77c1c7
			
Ivan Mahonin a62e15
			while(true) {
Ivan Mahonin a62e15
				int c = (a + b)/2;
Ivan Mahonin a62e15
				if (a == c) break;
Ivan Mahonin a62e15
				double cc = getter(points[c]);
Ivan Mahonin a62e15
				if (Geometry.isLess(value, cc))
Ivan Mahonin a62e15
					{ b = c; bb = cc; } else { a = c; aa = cc; }
Ivan Mahonin 77c1c7
			}
Ivan Mahonin a62e15
Ivan Mahonin 1cdf17
			return Geometry.isLess(aa, bb) ? (double)a + (value - aa)/(bb - aa) : (double)a;
Ivan Mahonin a62e15
		}
Ivan Mahonin 77c1c7
			
Ivan Mahonin a62e15
		public double indexByOriginalIndex(double originalIndex)
Ivan Mahonin 702257
			{ return binarySearch(originalIndex, delegate(Point p) { return p.originalIndex; }); }
Ivan Mahonin a62e15
		public double indexByTime(double time)
Ivan Mahonin 702257
			{ return binarySearch(time, delegate(Point p) { return p.time; }); }
Ivan Mahonin a62e15
		public double indexByLength(double length)
Ivan Mahonin 702257
			{ return binarySearch(length, delegate(Point p) { return p.length; }); }
Ivan Mahonin a62e15
		
Ivan Mahonin a62e15
		public double originalIndexByIndex(double index) {
Ivan Mahonin a62e15
			double frac;
Ivan Mahonin 702257
			Point p0 = floorPoint(index, out frac), p1 = ceilPoint(index);
Ivan Mahonin a62e15
			return Geometry.interpolationLinear(p0.originalIndex, p1.originalIndex, frac);
Ivan Mahonin a62e15
		}
Ivan Mahonin a62e15
		public double timeByIndex(double index) {
Ivan Mahonin a62e15
			double frac;
Ivan Mahonin 702257
			Point p0 = floorPoint(index, out frac), p1 = ceilPoint(index);
Ivan Mahonin a62e15
			return Geometry.interpolationLinear(p0.time, p1.time, frac);
Ivan Mahonin a62e15
		}
Ivan Mahonin a62e15
		public double lengthByIndex(double index) {
Ivan Mahonin a62e15
			double frac;
Ivan Mahonin 702257
			Point p0 = floorPoint(index, out frac), p1 = ceilPoint(index);
Ivan Mahonin a62e15
			return Geometry.interpolationLinear(p0.length, p1.length, frac);
Ivan Mahonin 77c1c7
		}
Ivan Mahonin cfceb0
Ivan Mahonin 702257
		public Point calcPoint(double index) {
Ivan Mahonin a62e15
			return modifier == null
Ivan Mahonin 702257
			     ? interpolateLinear(index)
Ivan Mahonin 702257
			     : modifier.calcPoint( originalIndexByIndex(index) );
Ivan Mahonin a62e15
		}
Ivan Mahonin a62e15
		
Ivan Mahonin 702257
		public Point interpolateLinear(double index) {
Ivan Mahonin a62e15
			double frac;
Ivan Mahonin 702257
			Point p0 = floorPoint(index, out frac);
Ivan Mahonin 702257
			Point p1 = ceilPoint(index);
Ivan Mahonin 702257
			return interpolateLinear(p0, p1, frac);
Ivan Mahonin a62e15
		}
Ivan Mahonin a62e15
Ivan Mahonin 702257
		public static Point interpolateLinear(Point p0, Point p1, double l) {
Ivan Mahonin a62e15
			if (l <= Geometry.precision) return p0;
Ivan Mahonin a62e15
			if (l >= 1.0 - Geometry.precision) return p1;
Ivan Mahonin 702257
			return new Point(
Ivan Mahonin 702257
				Geometry.interpolationLinear(p0.position, p1.position, l),
Ivan Mahonin 702257
				Geometry.interpolationLinear(p0.pressure, p1.pressure, l),
Ivan Mahonin 702257
				Geometry.interpolationLinear(p0.tilt, p1.tilt, l),
Ivan Mahonin a62e15
				Geometry.interpolationLinear(p0.originalIndex, p1.originalIndex, l),
Ivan Mahonin a62e15
				Geometry.interpolationLinear(p0.time, p1.time, l),
Ivan Mahonin 702257
				Geometry.interpolationLinear(p0.length, p1.length, l) );
Ivan Mahonin cfceb0
		}
Ivan Mahonin 7bbf70
		
Ivan Mahonin 7bbf70
		public void print() {
Ivan Mahonin 702257
			foreach(Point wp in points)
Ivan Mahonin 7bbf70
				Console.Write(
Ivan Mahonin 7bbf70
					"{2:f1}, ",
Ivan Mahonin 702257
					wp.position.x,
Ivan Mahonin 702257
					wp.position.y,
Ivan Mahonin 7bbf70
					wp.originalIndex );
Ivan Mahonin 7bbf70
			Console.WriteLine();
Ivan Mahonin 7bbf70
		}
Ivan Mahonin cfceb0
	}
Ivan Mahonin cfceb0
}
Ivan Mahonin cfceb0