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 {
b82ef4
		public static readonly Pen pen = new Pen("Dark Green", 3.0);
c66393
		public static readonly Pen penSpecial = new Pen("Blue", 3.0);
b82ef4
		public static readonly Pen penPreview = new Pen("Dark Green", 1.0, 0.25);
77e178
77e178
		private static long lastTouchId;
77e178
		
77e178
		public long touchId;
c66393
		public readonly Gdk.Device device;
b82ef4
		public readonly List<trackpoint> points = new List<trackpoint>();</trackpoint></trackpoint>
cfceb0
77c1c7
		private readonly List<track> parents = new List<track>();
77c1c7
		private readonly List<geometry.transformfunc> transformFuncs = new List<geometry.transformfunc>();</geometry.transformfunc></geometry.transformfunc>
77c1c7
77e178
		public static long getTouchId() { return ++lastTouchId; }
77e178
77e178
		public Track(long touchId, Gdk.Device device)
c66393
		{
77e178
			this.touchId = touchId;
c66393
			this.device = device;
c66393
		}
77c1c7
77c1c7
		public Track(Track parent, Geometry.TransformFunc transformFunc):
77e178
			this(parent.touchId, parent.device)
77c1c7
		{
77c1c7
			parents.AddRange(parent.parents);
77c1c7
			parents.Add(parent);
77c1c7
			transformFuncs.AddRange(parent.transformFuncs);
77c1c7
			transformFuncs.Add(transformFunc);
77c1c7
		}
77c1c7
77c1c7
		public Track(Track parent, Geometry.TransformFunc transformFunc, double precision):
77c1c7
			this(parent, transformFunc)
77c1c7
		{
77c1c7
			rebuild(precision);
77c1c7
		}
77c1c7
72b17c
		public Track createChild(Geometry.TransformFunc transformFunc){
77c1c7
			return new Track(this, transformFunc);
77c1c7
		}
77c1c7
77c1c7
		public Track createChildAndBuild(Geometry.TransformFunc transformFunc, double precision = 1.0) {
77c1c7
			return new Track(this, transformFunc, precision);
77c1c7
		}
c66393
		
cfceb0
		public Rectangle getBounds() {
cfceb0
			if (points.Count == 0)
cfceb0
				return new Rectangle();
b82ef4
			Rectangle bounds = new Rectangle(points[0].point);
b82ef4
			foreach(TrackPoint p in points)
b82ef4
				bounds = bounds.expand(p.point);
b82ef4
			return bounds.inflate(Math.Max(pen.width, penPreview.width) + 2.0);
cfceb0
		}
72b17c
b82ef4
		public TrackPoint transform(TrackPoint p) {
b82ef4
			p.point = Geometry.transform(transformFuncs, p.point);
b82ef4
			return p;
72b17c
		}
72b17c
				
b82ef4
		private void addSpline(
b82ef4
			TrackPoint p0, TrackPoint p1,
b82ef4
			TrackPoint t0, TrackPoint t1,
b82ef4
			TrackPoint tp0, TrackPoint tp1,
b82ef4
			double l0, double l1,
b82ef4
			double precisionSqr
b82ef4
		) {
b82ef4
			if ((tp1.point - tp0.point).lenSqr() < precisionSqr) {
77c1c7
				points.Add(tp1);
77c1c7
			} else {
77c1c7
				double l = 0.5*(l0 + l1);
c66393
				TrackPoint p = p0.spawn(
b82ef4
					Geometry.splinePoint(p0.point, p1.point, t0.point, t1.point, l),
b82ef4
					p0.time + l*(p1.time - p0.time),
b82ef4
					Geometry.splinePoint(p0.pressure, p1.pressure, t0.pressure, t1.pressure, l),
b82ef4
					Geometry.splinePoint(p0.tilt, p1.tilt, t0.tilt, t1.tilt, l) );
b82ef4
				TrackPoint tp = transform(p);
77c1c7
				addSpline(p0, p1, t0, t1, tp0, tp, l0, l, precisionSqr);
77c1c7
				addSpline(p0, p1, t0, t1, tp, tp1, l, l1, precisionSqr);
77c1c7
			}
77c1c7
		}
77c1c7
		
77c1c7
		public void rebuild(double precision = 1.0) {
77c1c7
			if (parents.Count == 0) return;
77c1c7
			
77c1c7
			points.Clear();
77c1c7
			
77c1c7
			Track root = parents[0];
77c1c7
			if (root.points.Count < 2) {
b82ef4
				foreach(TrackPoint p in root.points)
b82ef4
					points.Add( transform(p) );
77c1c7
				return;
77c1c7
			}
77c1c7
			
77c1c7
			double precisionSqr = precision * precision;
b82ef4
			TrackPoint p0 = root.points[0];
b82ef4
			TrackPoint p1 = root.points[1];
b82ef4
			TrackPoint t0 = new TrackPoint();
b82ef4
			TrackPoint tp0 = transform(p0);
77c1c7
			points.Add(tp0);
77c1c7
			for(int i = 1; i < root.points.Count; ++i) {
b82ef4
				TrackPoint p2 = root.points[i+1 < root.points.Count ? i+1 : i];
b82ef4
				TrackPoint tp1 = transform(p1);
b82ef4
				double dt = p2.time - p0.time;
b82ef4
				TrackPoint t1 = dt > Geometry.precision
b82ef4
				              ? (p2 - p0)*(p1.time - p0.time)/dt
b82ef4
				              : new TrackPoint();
77c1c7
				addSpline(p0, p1, t0, t1, tp0, tp1, 0.0, 1.0, precisionSqr);
77c1c7
77c1c7
				p0 = p1;
77c1c7
				p1 = p2;
77c1c7
				tp0 = tp1;
77c1c7
				t0 = t1;
77c1c7
			}
77c1c7
		}
cfceb0
b82ef4
		public void draw(Cairo.Context context, bool preview = false) {
6148f0
			if (preview) {
6148f0
				if (points.Count < 2)
6148f0
					return;
6148f0
				context.Save();
6148f0
				penPreview.apply(context);
6148f0
				context.MoveTo(points[0].point.x, points[0].point.y);
6148f0
				for(int i = 1; i < points.Count; ++i)
6148f0
					context.LineTo(points[i].point.x, points[i].point.y);
6148f0
				context.Stroke();
6148f0
				context.Restore();
6148f0
			} else {
6148f0
				context.Save();
6148f0
				pen.apply(context);
6148f0
				foreach(TrackPoint p in points) {
c66393
					double t = p.keyState.howLongPressed(Gdk.Key.m)
c66393
					         + p.buttonState.howLongPressed(3);
c66393
					double w = p.pressure*pen.width + 5.0*t;
c66393
					context.Arc(p.point.x, p.point.y, 2.0*w, 0.0, 2.0*Math.PI);
6148f0
					context.Fill();
6148f0
				}
6148f0
				context.Restore();
6148f0
			}
cfceb0
		}
cfceb0
	}
cfceb0
}
cfceb0