using System; using System.Collections.Generic; namespace Assistance { public class ModifierSpiro: Modifier { public static readonly double segmentSize = 0.25*Math.PI; public class Handler: Track.Handler { public readonly List angles = new List(); public Handler(ModifierSpiro owner, Track original): base(owner, original) { } } public class Modifier: Track.Modifier { public double angle; public double radius; public Modifier(Track.Handler handler, double angle, double radius): base(handler) { this.angle = angle; this.radius = radius; } public override Track.WayPoint calcWayPoint(double originalIndex) { Track.WayPoint p = original.calcWayPoint(originalIndex); Handler handler = (Handler)this.handler; double frac; int i = original.floorIndex(originalIndex, out frac); double angle = i < 0 ? 0 : frac <= Geometry.precision ? handler.angles[i] : handler.angles[i]*(1.0 - frac) + handler.angles[i + 1]*frac; angle += this.angle; double radius = 2.0*this.radius*p.point.pressure; double s = Math.Sin(angle); double c = Math.Cos(angle); p.point.position += new Point(c, s)*radius; p.tangent.position = new Point(-s, c); return p; } } public ActivePoint center; public int count; public double radius; public ModifierSpiro(Document document, Point center, int count = 3, double radius = 10.0): base(document) { this.center = new ActivePoint(this, ActivePoint.Type.CircleCross, center); this.count = count; this.radius = radius; } public override void modify(Track track, InputManager.KeyPoint keyPoint, List outTracks) { if (track.handler == null) { track.handler = new Handler(this, track); for(int i = 0; i < count; ++i) track.handler.tracks.Add(new Track( new Modifier(track.handler, i*2.0*Math.PI/(double)count, radius) )); } outTracks.AddRange(track.handler.tracks); if (!track.isChanged) return; Handler handler = (Handler)track.handler; int start = track.points.Count - track.wayPointsAdded; if (start < 0) start = 0; // remove angles if (start < handler.angles.Count) handler.angles.RemoveRange(start, handler.angles.Count - start); // add angles for(int i = start; i < track.points.Count; ++i) { if (i > 0) { double dl = track.points[i].length - track.points[i-1].length; double da = 0.25*dl/(2.0*radius*track.points[i].point.pressure); handler.angles.Add(handler.angles[i-1] + da); } else { handler.angles.Add(0.0); } } // process sub-tracks foreach(Track subTrack in track.handler.tracks) { // remove points int subStart = start;//subTrack.floorIndexNoClamp(subTrack.indexByOriginalIndex(start)); if (subStart < 0) subStart = 0; if (subStart < subTrack.points.Count) { subTrack.wayPointsRemoved += subTrack.points.Count - subStart; subTrack.points.RemoveRange(subStart, subTrack.points.Count - subStart); } // add points for(int i = start; i < track.points.Count; ++i) { if (false && i > 0) { double prevAngle = handler.angles[i-1]; double nextAngle = handler.angles[i]; if (Math.Abs(nextAngle - prevAngle) > 1.5*segmentSize) { double step = segmentSize/(nextAngle - prevAngle); double end = 1.0 - 0.5*step; for(double frac = step; frac < end; frac += step) subTrack.points.Add( subTrack.modifier.calcWayPoint((double)i - 1.0 + frac) ); } } subTrack.points.Add( subTrack.modifier.calcWayPoint(i) ); } subTrack.wayPointsAdded += subTrack.points.Count - subStart; } track.wayPointsRemoved = 0; track.wayPointsAdded = 0; } } }