From c3ebffda7cacd14021a44a16f77f9aad80225a4b Mon Sep 17 00:00:00 2001 From: Ivan Mahonin Date: Mar 02 2018 06:33:31 +0000 Subject: assistance: InputModifierInterpolation --- diff --git a/mono/Assistance/Assistance.csproj b/mono/Assistance/Assistance.csproj index e2127d1..f8b5b22 100644 --- a/mono/Assistance/Assistance.csproj +++ b/mono/Assistance/Assistance.csproj @@ -60,10 +60,11 @@ - + + diff --git a/mono/Assistance/InputManager.cs b/mono/Assistance/InputManager.cs index 059f543..99b0acf 100644 --- a/mono/Assistance/InputManager.cs +++ b/mono/Assistance/InputManager.cs @@ -7,8 +7,9 @@ namespace Assistance { public class TrackHandler: Track.Handler { public readonly List keys = new List(); - public TrackHandler(InputManager owner, Track original): - base(owner, track) { } + public TrackHandler(InputManager owner, Track original, int keysCount = 0): + base(owner, track) + { for(int i = 0; i < keysCount; ++i) keys.Add(0); } } public class KeyPoint { @@ -31,19 +32,30 @@ namespace Assistance { { get { return refCount <= 0; } } } + public class Modifier: Track.Owner { + public virtual void activate() { } + public virtual void modify(Track tracks, KeyPoint keyPoint, List outTracks) + { } + public virtual void modify(List tracks, KeyPoint keyPoint, List outTracks) + { foreach(Track track in tracks) modify(track, keyPoint, outTracks); } + public virtual void deactivate() { } + } + public readonly Workarea workarea; private readonly InputState state = new InputState(); private Tool tool; - private readonly List modifiers = new List(); + private readonly List modifiers = new List(); private readonly List tracks = new List(); - private readonly List subTracks = null; private readonly List keyPoints = new List(); private int keyPointsSent; + private List subTracks = null; + private readonly List[] subTracksBuf = new List[] { new List(), new List() }; + InputManager(Workarea workarea) { this.workarea = workarea; } @@ -106,9 +118,19 @@ namespace Assistance { while(true) { // run modifiers KeyPoint newKeyPoint = new KeyPoint(); - List subTracks = tracks; - foreach(Modifier modifier in modifiers) - subTracks = modifier.modify(subTracks); + subTracks = tracks; + int i = 0; + foreach(Modifier modifier in modifiers) { + List outTracks = subTracksBuf[i]; + modifier.modify(subTracks, keyEvent, outTracks); + subTracks = outTracks; + i = 1 - i; + } + + // create handlers + foreach(Track track in subTracks) + if (track.handler == null) + track.handler = new TrackHandler(this, track, keyPoints.Count); if (keyPoints.Count > 0) { // rollback @@ -277,15 +299,15 @@ namespace Assistance { public int getModifiersCount() { return modifiers.Count; } - public InputModifier getModifier(int index) + public Modifier getModifier(int index) { return modifiers[index]; } - public void insertModifier(int index, InputModifier modifier) { + public void insertModifier(int index, Modifier modifier) { if (this.tool != null) finishTracks(); modifiers.Insert(index, modifier); modifier.activate(); } - public void addModifier(InputModifier modifier) + public void addModifier(Modifier modifier) { insertModifier(getModifiersCount(), modifier); } public void removeModifier(int index) { @@ -293,7 +315,7 @@ namespace Assistance { modifiers[i].deactivate(); modifiers.RemoveAt(index); } - public void removeModifier(InputModifier modifier) { + public void removeModifier(Modifier modifier) { for(int i = 0; i < getModifiersCount(); ++i) if (getModifier(i) == modifier) { removeModifier(i); break; } diff --git a/mono/Assistance/InputModifier.cs b/mono/Assistance/InputModifier.cs deleted file mode 100644 index 23b1f56..0000000 --- a/mono/Assistance/InputModifier.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Assistance { - public interface InputModifier { - void activate(); - List modify(List tracks); - void deactivate(); - } -} - diff --git a/mono/Assistance/InputModifierInterpolation.cs b/mono/Assistance/InputModifierInterpolation.cs new file mode 100644 index 0000000..f526038 --- /dev/null +++ b/mono/Assistance/InputModifierInterpolation.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; + +namespace Assistance { + public class InputModifierInterpolation: InputManager.Modifier { + public readonly double precision; + public readonly double precisionSqr; + + public InputModifierInterpolation(double precision = 0.0) { + this.precision = precision; + this.precisionSqr = precision*precision; + } + + public void addSegment(Track track, Track.WayPoint p0, Track.WayPoint p1) { + if ((p1.point.position - p0.point.position).lenSqr() <= precisionSqr) + { track.points.Add(p1); return; } + Track.WayPoint p = track.modifier.calcWayPoint(0.5*(p0.originalIndex + p1.originalIndex)); + addSegment(track, p0, p); + addSegment(track, p, p1); + } + + public override List modify(Track track, InputManager.KeyPoint keyPoint, List outTracks) { + if (track.handler == null) { + track.handler = new Track.Handler(this, track); + track.handler.tracks.Add(new Track( new Track.Modifier(track.handler) )); + } + + Track subTrack = track.handler.tracks[0]; + Modifier modifier = (Modifier)subTrack.modifier; + outTracks.Add(subTrack); + + if (!track.isChanged) + return; + + // remove points + int start = track.points.Count - track.wayPointsAdded; + if (start < 0) start = 0; + int subStart = subTrack.floorIndex(subTrack.indexByOriginalIndex(start)); + if (subTrack.points.Count < subStart) { + subTrack.points.RemoveRange(start, subTrack.points.Count - subStart); + subTrack.wayPointsRemoved += subTrack.points.Count - subStart; + } + + // add points + Track.WayPoint p0 = track.getWayPoint(start - 1); + for(int i = start; i < track.points.Count; ++i) { + Track.WayPoint p1 = track.points[i]; + addSegment(subTrack, p0, p1); + p0 = p1; + } + subTrack.wayPointsAdded += subTrack.points.Count - subStart; + } + } +} + diff --git a/mono/Assistance/InputModifierTangents.cs b/mono/Assistance/InputModifierTangents.cs new file mode 100644 index 0000000..dba5aaf --- /dev/null +++ b/mono/Assistance/InputModifierTangents.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; + +namespace Assistance { + public class InputModifierTangents: InputManager.Modifier { + public class Modifier: Track.Modifier { + public Modifier(Handler handler): + base(handler) { } + + public InputManager.KeyPoint.Holder holder = null; + public readonly List tangents = new List(); + + public override Track.WayPoint calcWayPoint(double originalIndex) { + double frac; + int i0 = original.floorIndex(originalIndex, out frac); + int i1 = original.ceilIndex(originalIndex); + Track.WayPoint p0 = original.getWayPoint(i0); + Track.WayPoint p1 = original.getWayPoint(i1); + p0.tangent = tangents[i0]; + p1.tangent = tangents[i1]; + return Track.interpolate(p0, p1, frac); + } + } + + public override List modify(Track track, InputManager.KeyPoint keyPoint, List outTracks) { + if (track.handler == null) { + track.handler = new Track.Handler(this, track); + track.handler.tracks.Add(new Track( new Modifier(track.handler) )); + } + + Track subTrack = track.handler.tracks[0]; + Modifier modifier = (Modifier)subTrack.modifier; + outTracks.Add(subTrack); + + if ( !track.isChanged + && track.points.Count == subTrack.points.Count + && track.points.Count == modifier.tangents.Count ) + return; + + if (!track.isChanged && subTrack.points.Count == track.points.Count - 1) { + // add temporary point + modifier.tangents.Add(new Track.Point()); + subTrack.points.Add(track.getLast()); + ++subTrack.wayPointsAdded; + } else { + // apply permanent changes + + // remove points + int start = track.points.Count - track.wayPointsAdded; + if (start < 0) start = 0; + if (start > 1) --start; + if (subTrack.points.Count < start) { + subTrack.points.RemoveRange(start, subTrack.points.Count - start); + subTrack.wayPointsRemoved += subTrack.points.Count - start; + } + if (modifier.tangents.Count < start) + modifier.tangents.RemoveRange(start, modifier.tangents.Count - start); + + // add first point + int index = start; + if (index == 0) { + modifier.tangents.Add(new Track.Point()); + subTrack.points.Add(track.getLast()); + ++index; + } + + // add points with tangents + if (track.points.Count > 2) { + while(index < track.points.Count - 1) { + Track.WayPoint p = track.points[index]; + double t0 = track.points[index-1].time; + double t2 = track.points[index+1].time; + double dt = t2 - t0; + p.tangent = dt > Geometry.precision + ? (track.points[index+1].point - track.points[index-1].point)*(p.time - t0)/dt + : new Track.Point(); + modifier.tangents.Add(p.tangent); + subTrack.points.Add(p); + ++index; + } + } + + track.wayPointsRemoved = 0; + track.wayPointsAdded = 0; + subTrack.wayPointsAdded += index - start; + + // release previous key point + if (modifier.holder) modifier.holder.Dispose(); + + if (track.isFinished) { + // finish + modifier.tangents.Add(new Track.Point()); + subTrack.points.Add(track.getLast()); + ++subTrack.wayPointsAdded; + } else { + // save key point + modifier.holder = keyPoint.hold(); + } + } + } + } +} + diff --git a/mono/Assistance/Track.cs b/mono/Assistance/Track.cs index ef36955..79dea64 100644 --- a/mono/Assistance/Track.cs +++ b/mono/Assistance/Track.cs @@ -26,7 +26,7 @@ namespace Assistance { { get { return handler.owner; } } public Track original { get { return handler.original; } } - public TrackPoint calcWayPoint(double originalIndex) + public virtual WayPoint calcWayPoint(double originalIndex) { return original.calcWayPoint(originalIndex); } } @@ -137,6 +137,9 @@ namespace Assistance { { get { return modifier != null ? modifier.original : null; } } public double timeOffset { get { return modifier != null ? modifier.timeOffset : 0.0; } } + + public bool isChanged + { get { return wayPointsAdded != 0 || wayPointsRemoved != 0; } } public Track getRoot() { return original == null ? this : original.getRoot(); }