|
|
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 |
|