Blame mono/Assistance/ModifierSpiro.cs

1cdf17
using System;
1cdf17
using System.Collections.Generic;
1cdf17
1cdf17
namespace Assistance {
1cdf17
	public class ModifierSpiro: Modifier {
7bbf70
		public static readonly double segmentSize = Math.PI/180.0*10.0;
1cdf17
	
1cdf17
		public class Handler: Track.Handler {
1cdf17
			public readonly List<double> angles = new List<double>();</double></double>
1cdf17
			public Handler(ModifierSpiro owner, Track original):
1cdf17
				base(owner, original) { }
1cdf17
		}
1cdf17
		
1cdf17
		public class Modifier: Track.Modifier {
1cdf17
			public double angle;
1cdf17
			public double radius;
702257
			public double speed;
1cdf17
		
72d2fd
			public Modifier(Track.Handler handler, double angle, double radius, double speed = 0.25):
702257
				base(handler) { this.angle = angle; this.radius = radius; this.speed = speed; }
702257
702257
			public override Track.Point calcPoint(double originalIndex) {
702257
				Track.Point p = base.calcPoint(originalIndex);
1cdf17
				
72d2fd
				if (p.length > 2.0) {
72d2fd
					double frac;
72d2fd
					int i0 = original.floorIndex(originalIndex, out frac);
72d2fd
					int i1 = original.ceilIndex(originalIndex);
72d2fd
					if (i0 < 0) return p;
72d2fd
	
72d2fd
					Handler handler = (Handler)this.handler;
72d2fd
					double angle = this.angle + speed*Geometry.interpolationLinear(
72d2fd
						handler.angles[i0], handler.angles[i1], frac);
72d2fd
					double radius = 2.0*this.radius*p.pressure;
72d2fd
					
72d2fd
					Point tangent = original.calcTangent(originalIndex, Math.Abs(2.0*this.radius/speed));
72d2fd
					p.position += tangent.rotate(angle)*radius;
72d2fd
					p.pressure *= 0.5*(1.0 + Math.Cos(angle));
72d2fd
				} else {
72d2fd
					p.pressure = 0.0;
72d2fd
				}
72d2fd
				
1cdf17
				return p;
1cdf17
			}
1cdf17
		}
1cdf17
1cdf17
1cdf17
		public ActivePoint center;
1cdf17
		public int count;
1cdf17
		public double radius;
1cdf17
1cdf17
		public ModifierSpiro(Document document, Point center, int count = 3, double radius = 10.0): base(document) {
1cdf17
			this.center = new ActivePoint(this, ActivePoint.Type.CircleCross, center);
1cdf17
			this.count = count;
1cdf17
			this.radius = radius;
1cdf17
		}
1cdf17
1cdf17
		public override void modify(Track track, InputManager.KeyPoint keyPoint, List<track> outTracks) {
1cdf17
			if (track.handler == null) {
1cdf17
				track.handler = new Handler(this, track);
1cdf17
				for(int i = 0; i < count; ++i)
1cdf17
					track.handler.tracks.Add(new Track( new Modifier(track.handler, i*2.0*Math.PI/(double)count, radius) ));
1cdf17
			}
1cdf17
			
1cdf17
			outTracks.AddRange(track.handler.tracks);
72d2fd
			if (!track.wasChanged)
1cdf17
				return;
1cdf17
			
1cdf17
			Handler handler = (Handler)track.handler;
1cdf17
			
72d2fd
			int start = track.count - track.pointsAdded;
1cdf17
			if (start < 0) start = 0;
1cdf17
			
1cdf17
			// remove angles
1cdf17
			if (start < handler.angles.Count)
1cdf17
				handler.angles.RemoveRange(start, handler.angles.Count - start);
1cdf17
			
1cdf17
			// add angles
72d2fd
			for(int i = start; i < track.count; ++i) {
1cdf17
				if (i > 0) {
72d2fd
					double dl = track[i].length - track[i-1].length;
72d2fd
					double da = track[i].pressure > Geometry.precision
72d2fd
					          ? dl/(2.0*radius*track[i].pressure) : 0.0;
1cdf17
					handler.angles.Add(handler.angles[i-1] + da);
1cdf17
				} else {
1cdf17
					handler.angles.Add(0.0);
1cdf17
				}
1cdf17
			}
1cdf17
			
1cdf17
			// process sub-tracks
1cdf17
			foreach(Track subTrack in track.handler.tracks) {
1cdf17
				// remove points
7bbf70
				int subStart = subTrack.floorIndex(subTrack.indexByOriginalIndex(start));
1cdf17
				if (subStart < 0) subStart = 0;
72d2fd
				if (subStart < subTrack.count && subTrack[subStart].originalIndex + Geometry.precision < start)
7bbf70
					++subStart;
72d2fd
				subTrack.truncate(subStart);
1cdf17
				
1cdf17
				// add points
72d2fd
				for(int i = start; i < track.count; ++i) {
7bbf70
					if (i > 0) {
1cdf17
						double prevAngle = handler.angles[i-1];
1cdf17
						double nextAngle = handler.angles[i];
1cdf17
						if (Math.Abs(nextAngle - prevAngle) > 1.5*segmentSize) {
7bbf70
							double step = segmentSize/Math.Abs(nextAngle - prevAngle);
1cdf17
							double end = 1.0 - 0.5*step;
1cdf17
							for(double frac = step; frac < end; frac += step)
72d2fd
								subTrack.add( subTrack.modifier.calcPoint((double)i - 1.0 + frac) );
1cdf17
						}
1cdf17
					}
72d2fd
					subTrack.add( subTrack.modifier.calcPoint(i) );
1cdf17
				}
1cdf17
			}
1cdf17
			
72d2fd
			track.resetCounters();
1cdf17
		}
1cdf17
	}
1cdf17
}
1cdf17