diff --git a/mono/Assistance/Guideline.cs b/mono/Assistance/Guideline.cs index bc34af4..375f9b3 100644 --- a/mono/Assistance/Guideline.cs +++ b/mono/Assistance/Guideline.cs @@ -19,13 +19,13 @@ namespace Assistance { { draw(context, false); } public double calcTrackWeight(Track track) { - if (track.points.Count < 1) + if (track.count < 1) return double.PositiveInfinity; double sumWeight = 0.0; double sumLength = 0.0; double sumDeviation = 0.0; - Point prev = track.points[0].position; + Point prev = track.getFirst().position; foreach(Track.Point tp in track.points) { Point p = tp.position; double length = (p - prev).len(); diff --git a/mono/Assistance/InputManager.cs b/mono/Assistance/InputManager.cs index f210226..4e3b937 100644 --- a/mono/Assistance/InputManager.cs +++ b/mono/Assistance/InputManager.cs @@ -107,8 +107,8 @@ namespace Assistance { TrackHandler handler = (TrackHandler)track.handler; handler.keys.RemoveRange(level, keyPoints.Count - level); int cnt = handler.keys[keyIndex]; - track.wayPointsRemoved = 0; - track.wayPointsAdded = track.points.Count - cnt; + track.resetRemoved(); + track.forceAdded(track.count - cnt); } for(int i = level; i < keyPoints.Count; ++i) keyPoints[i].available = false; keyPoints.RemoveRange(level, keyPoints.Count - level); @@ -139,8 +139,8 @@ namespace Assistance { foreach(Track track in subTracks) { TrackHandler handler = (TrackHandler)track.handler; if (resend) { - track.wayPointsRemoved = 0; - track.wayPointsAdded = track.points.Count - handler.keys[keyPointsSent]; + track.resetRemoved(); + track.forceAdded(track.count - handler.keys[keyPointsSent]); } handler.keys.RemoveRange(level, handler.keys.Count - level); } @@ -179,8 +179,8 @@ namespace Assistance { // rollback int rollbackIndex = keyPoints.Count; foreach(Track track in subTracks) { - if (track.wayPointsRemoved > 0) { - int count = track.points.Count - track.wayPointsAdded; + if (track.wasRemoved) { + int count = track.count - track.pointsAdded; TrackHandler handler = (TrackHandler)track.handler; while(rollbackIndex > 0 && (rollbackIndex >= keyPoints.Count || handler.keys[rollbackIndex] > count)) --rollbackIndex; @@ -198,10 +198,8 @@ namespace Assistance { // send to tool if (keyPointsSent == keyPoints.Count && subTracks.Count > 0) tool.paintTracks(subTracks); - foreach(Track track in subTracks) { - track.wayPointsRemoved = 0; - track.wayPointsAdded = 0; - } + foreach(Track track in subTracks) + track.resetCounters(); // is paint finished? if (newKeyPoint.isFree) { @@ -217,7 +215,7 @@ namespace Assistance { if (tool.paintPush()) ++keyPointsSent; keyPoints.Add(newKeyPoint); foreach(Track track in subTracks) - ((TrackHandler)track.handler).keys.Add(track.points.Count); + ((TrackHandler)track.handler).keys.Add(track.count); } } @@ -271,30 +269,20 @@ namespace Assistance { } private void addTrackPoint(Track track, Point position, double pressure, Point tilt, double time, bool final) { - // fix time - if (track.points.Count > 0) - time = Math.Max(time, track.getLast().time + Timer.step); - - // calc length - double length = track.points.Count > 0 - ? (position - track.getLast().position).len() + track.getLast().length - : 0.0; - // add - track.points.Add( new Track.Point( + track.add( new Track.Point( position, pressure, tilt, - (double)track.points.Count, + (double)track.count, time, - length, + 0.0, final )); - ++track.wayPointsAdded; } private void touchTracks(bool finish = false) { foreach(Track track in tracks[0]) { - if (!track.isFinished() && track.points.Count > 0) { + if (!track.isFinished() && !track.isEmpty) { Track.Point p = track.getLast(); addTrackPoint(track, p.position, p.pressure, p.tilt, p.time, finish); } @@ -435,21 +423,21 @@ namespace Assistance { TrackHandler handler = (TrackHandler)track.handler; int start = handler.keys[keyPointsSent] - 1; if (start < 0) start = 0; - if (start < track.points.Count) { + if (start < track.count) { Drawing.Color color = penPreview.color; int level = keyPointsSent; color.apply(context); - context.MoveTo(track.points[start].position.x, track.points[start].position.y); - for(int i = start + 1; i < track.points.Count; ++i) { + context.MoveTo(track[start].position.x, track[start].position.y); + for(int i = start + 1; i < track.count; ++i) { while(level < handler.keys.Count && handler.keys[level] <= i) { context.Stroke(); - context.MoveTo(track.points[i-1].position.x, track.points[i-1].position.y); + context.MoveTo(track[i-1].position.x, track[i-1].position.y); color.a *= levelAlpha; color.apply(context); ++level; } - context.LineTo(track.points[i].position.x, track.points[i].position.y); + context.LineTo(track[i].position.x, track[i].position.y); } } } diff --git a/mono/Assistance/InputModifierAssistants.cs b/mono/Assistance/InputModifierAssistants.cs index 25ad889..e075c25 100644 --- a/mono/Assistance/InputModifierAssistants.cs +++ b/mono/Assistance/InputModifierAssistants.cs @@ -28,12 +28,12 @@ namespace Assistance { Modifier modifier; if (track.handler == null) { - if (track.points.Count == 0) + if (track.isEmpty) return; track.handler = new Track.Handler(this, track); modifier = new Modifier(track.handler); - workarea.getGuidelines(modifier.guidelines, track.points[0].position); + workarea.getGuidelines(modifier.guidelines, track.getFirst().position); subTrack = new Track(modifier); track.handler.tracks.Add(subTrack); @@ -49,18 +49,15 @@ namespace Assistance { modifier = (Modifier)subTrack.modifier; outTracks.Add(subTrack); - if (!track.isChanged) + if (!track.wasChanged) return; // remove points - int start = track.points.Count - track.wayPointsAdded; + int start = track.count - track.pointsAdded; if (start < 0) start = 0; - if (subTrack.points.Count < start) { - subTrack.wayPointsRemoved += subTrack.points.Count - start; - subTrack.points.RemoveRange(start, subTrack.points.Count - start); - } + subTrack.truncate(start); - bool trackIsLong = track.points.Count > 0 && (track.getLast().length >= Guideline.maxLenght || track.isFinished()); + bool trackIsLong = !track.isEmpty && (track.getLast().length >= Guideline.maxLenght || track.isFinished()); if (!trackIsLong && modifier.holder != null && !modifier.holder.isHolded && modifier.holder.available) modifier.holder.reuse(); @@ -71,20 +68,20 @@ namespace Assistance { modifier.guidelines[ modifier.guidelines.IndexOf(guideline) ] = modifier.guidelines[0]; modifier.guidelines[0] = guideline; start = 0; - subTrack.wayPointsRemoved += subTrack.points.Count; - subTrack.points.Clear(); + subTrack.truncate(0); } if (trackIsLong) modifier.holder.release(); } // add points - for(int i = start; i < track.points.Count; ++i) - subTrack.points.Add(modifier.calcPoint(i)); - subTrack.wayPointsAdded = subTrack.points.Count - start; + for(int i = start; i < track.count; ++i) { + double di = (double)i; + Track.Point p = modifier.calcPoint(di); + subTrack.add(p); + } - track.wayPointsRemoved = 0; - track.wayPointsAdded = 0; + track.resetCounters(); } public override void drawHover(Cairo.Context context, Point hover) { @@ -97,7 +94,7 @@ namespace Assistance { public override void drawTrack(Cairo.Context context, Track track) { if (track.handler == null) return; Track subTrack = track.handler.tracks[0]; - if (subTrack.points.Count > 0) + if (!subTrack.isEmpty) drawHover(context, subTrack.getLast().position); } } diff --git a/mono/Assistance/InputModifierSegmentation.cs b/mono/Assistance/InputModifierSegmentation.cs index 3cb4fea..5ca0874 100644 --- a/mono/Assistance/InputModifierSegmentation.cs +++ b/mono/Assistance/InputModifierSegmentation.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace Assistance { public class InputModifierSegmentation: InputManager.Modifier { - public static readonly int maxRecursion = 8; + public static readonly int maxRecursion = 10; public readonly double precision; public readonly double precisionSqr; @@ -14,15 +14,17 @@ namespace Assistance { } public void addSegments(Track track, Track.Point p0, Track.Point p1, int level = 0) { - if (level >= maxRecursion || (p1.position - p0.position).lenSqr() <= precisionSqr) - { track.points.Add(p1); return; } + if (level >= maxRecursion || (p1.position - p0.position).lenSqr() <= precisionSqr) { + track.add(p1); + return; + } Track.Point p = track.modifier.calcPoint(0.5*(p0.originalIndex + p1.originalIndex)); addSegments(track, p0, p, level + 1); addSegments(track, p, p1, level + 1); } public override void modify(Track track, InputManager.KeyPoint keyPoint, List outTracks) { - if (track.handler == null) { + if (track.handler == null) { track.handler = new Track.Handler(this, track); track.handler.tracks.Add(new Track( new Track.Modifier(track.handler) )); } @@ -30,35 +32,24 @@ namespace Assistance { Track subTrack = track.handler.tracks[0]; outTracks.Add(subTrack); - if (!track.isChanged) + if (!track.wasChanged) return; // remove points - int start = track.points.Count - track.wayPointsAdded; + int start = track.count - track.pointsAdded; if (start < 0) start = 0; - int subStart = subTrack.floorIndex(subTrack.indexByOriginalIndex(start)); - if (subStart < 0) subStart = 0; - if (subStart < subTrack.points.Count && subTrack.points[subStart].originalIndex + Geometry.precision < start) - ++subStart; - - while(subStart > 0 && subTrack.points[subStart-1].originalIndex + Geometry.precision >= start) - --subStart; - if (subStart < subTrack.points.Count) { - subTrack.wayPointsRemoved += subTrack.points.Count - subStart; - subTrack.points.RemoveRange(subStart, subTrack.points.Count - subStart); - } + int subStart = subTrack.floorIndex(subTrack.indexByOriginalIndex(start-1)) + 1; + subTrack.truncate(subStart); // add points Track.Point p0 = subTrack.modifier.calcPoint(start - 1); - for(int i = start; i < track.points.Count; ++i) { + for(int i = start; i < track.count; ++i) { Track.Point p1 = subTrack.modifier.calcPoint(i); addSegments(subTrack, p0, p1); p0 = p1; } - subTrack.wayPointsAdded += subTrack.points.Count - subStart; - - track.wayPointsRemoved = 0; - track.wayPointsAdded = 0; + + track.resetCounters(); } } } diff --git a/mono/Assistance/InputModifierTangents.cs b/mono/Assistance/InputModifierTangents.cs index 1846650..c30f2b7 100644 --- a/mono/Assistance/InputModifierTangents.cs +++ b/mono/Assistance/InputModifierTangents.cs @@ -32,10 +32,10 @@ namespace Assistance { int i1 = original.ceilIndex(originalIndex); Track.Point p = i0 < 0 ? new Track.Point() : interpolateSpline( - original.points[i0], - original.points[i1], - tangents[i0], - tangents[i1], + original[i0], + original[i1], + i0 < tangents.Count ? tangents[i0] : new Tangent(), + i1 < tangents.Count ? tangents[i1] : new Tangent(), frac ); p.originalIndex = originalIndex; return p; @@ -64,27 +64,23 @@ namespace Assistance { Modifier modifier = (Modifier)subTrack.modifier; outTracks.Add(subTrack); - if ( !track.isChanged - && track.points.Count == subTrack.points.Count - && track.points.Count == modifier.tangents.Count ) + if ( !track.wasChanged + && track.count == subTrack.count + && track.count == modifier.tangents.Count ) return; - if (!track.isChanged && subTrack.points.Count == track.points.Count - 1) { + if (!track.wasChanged && subTrack.count == track.count - 1) { // add temporary point modifier.tangents.Add(new Tangent()); - subTrack.points.Add(track.getLast()); - ++subTrack.wayPointsAdded; + subTrack.add(track.getLast()); } else { // apply permanent changes // remove points - int start = track.points.Count - track.wayPointsAdded; + int start = track.count - track.pointsAdded; if (start < 0) start = 0; if (start > 1) --start; - if (start < subTrack.points.Count) { - subTrack.wayPointsRemoved += subTrack.points.Count - start; - subTrack.points.RemoveRange(start, subTrack.points.Count - start); - } + subTrack.truncate(start); if (start < modifier.tangents.Count) modifier.tangents.RemoveRange(start, modifier.tangents.Count - start); @@ -92,16 +88,16 @@ namespace Assistance { int index = start; if (index == 0) { modifier.tangents.Add(new Tangent()); - subTrack.points.Add(track.getLast()); + subTrack.add(track.getLast()); ++index; } // add points with tangents - if (track.points.Count > 2) { - while(index < track.points.Count - 1) { - Track.Point p0 = track.points[index-1]; - Track.Point p1 = track.points[index]; - Track.Point p2 = track.points[index+1]; + if (track.count > 2) { + while(index < track.count) { + Track.Point p0 = track[index-1]; + Track.Point p1 = track[index]; + Track.Point p2 = track[index+1]; double dt = p2.time - p0.time; double k = dt > Geometry.precision ? (p1.time - p0.time)/dt : 0.0; Tangent tangent = new Tangent( @@ -109,14 +105,12 @@ namespace Assistance { (p2.pressure - p0.pressure)*k, (p2.tilt - p0.tilt)*k ); modifier.tangents.Add(tangent); - subTrack.points.Add(p1); + subTrack.add(p1); ++index; } } - track.wayPointsRemoved = 0; - track.wayPointsAdded = 0; - subTrack.wayPointsAdded += index - start; + track.resetCounters(); // release previous key point if (modifier.holder != null) { @@ -127,8 +121,7 @@ namespace Assistance { if (track.isFinished()) { // finish modifier.tangents.Add(new Tangent()); - subTrack.points.Add(track.getLast()); - ++subTrack.wayPointsAdded; + subTrack.add(track.getLast()); } else { // save key point modifier.holder = keyPoint.hold(); diff --git a/mono/Assistance/ModifierSnowflake.cs b/mono/Assistance/ModifierSnowflake.cs index 76fbd58..b676534 100644 --- a/mono/Assistance/ModifierSnowflake.cs +++ b/mono/Assistance/ModifierSnowflake.cs @@ -63,26 +63,21 @@ namespace Assistance { } outTracks.AddRange(track.handler.tracks); - if (!track.isChanged) + if (!track.wasChanged) return; - int start = track.points.Count - track.wayPointsAdded; + int start = track.count - track.pointsAdded; if (start < 0) start = 0; foreach(Track subTrack in track.handler.tracks) { // remove points - if (start < subTrack.points.Count) { - subTrack.wayPointsRemoved += subTrack.points.Count - start; - subTrack.points.RemoveRange(start, subTrack.points.Count - start); - } + subTrack.truncate(start); // add points - for(int i = start; i < track.points.Count; ++i) - subTrack.points.Add( subTrack.modifier.calcPoint(i) ); - subTrack.wayPointsAdded += subTrack.points.Count - start; + for(int i = start; i < track.count; ++i) + subTrack.add( subTrack.modifier.calcPoint(i) ); } - track.wayPointsRemoved = 0; - track.wayPointsAdded = 0; + track.resetCounters(); } } } diff --git a/mono/Assistance/ModifierSpiro.cs b/mono/Assistance/ModifierSpiro.cs index 199106f..116f3d7 100644 --- a/mono/Assistance/ModifierSpiro.cs +++ b/mono/Assistance/ModifierSpiro.cs @@ -16,26 +16,30 @@ namespace Assistance { public double radius; public double speed; - public Modifier(Track.Handler handler, double angle, double radius, double speed = 1.0): + public Modifier(Track.Handler handler, double angle, double radius, double speed = 0.25): base(handler) { this.angle = angle; this.radius = radius; this.speed = speed; } public override Track.Point calcPoint(double originalIndex) { Track.Point p = base.calcPoint(originalIndex); - double frac; - int i0 = original.floorIndex(originalIndex, out frac); - int i1 = original.ceilIndex(originalIndex); - if (i0 < 0) return p; - - Handler handler = (Handler)this.handler; - double angle = this.angle + speed*Geometry.interpolationLinear( - handler.angles[i0], handler.angles[i1], frac); - double radius = 2.0*this.radius*p.pressure; - double s = Math.Sin(angle); - double c = Math.Cos(angle); - - p.position += new Point(c, s)*radius; - p.pressure *= 0.5*(1.0 + c); + if (p.length > 2.0) { + double frac; + int i0 = original.floorIndex(originalIndex, out frac); + int i1 = original.ceilIndex(originalIndex); + if (i0 < 0) return p; + + Handler handler = (Handler)this.handler; + double angle = this.angle + speed*Geometry.interpolationLinear( + handler.angles[i0], handler.angles[i1], frac); + double radius = 2.0*this.radius*p.pressure; + + Point tangent = original.calcTangent(originalIndex, Math.Abs(2.0*this.radius/speed)); + p.position += tangent.rotate(angle)*radius; + p.pressure *= 0.5*(1.0 + Math.Cos(angle)); + } else { + p.pressure = 0.0; + } + return p; } } @@ -59,12 +63,12 @@ namespace Assistance { } outTracks.AddRange(track.handler.tracks); - if (!track.isChanged) + if (!track.wasChanged) return; Handler handler = (Handler)track.handler; - int start = track.points.Count - track.wayPointsAdded; + int start = track.count - track.pointsAdded; if (start < 0) start = 0; // remove angles @@ -72,11 +76,11 @@ namespace Assistance { handler.angles.RemoveRange(start, handler.angles.Count - start); // add angles - for(int i = start; i < track.points.Count; ++i) { + for(int i = start; i < track.count; ++i) { if (i > 0) { - double dl = track.points[i].length - track.points[i-1].length; - double da = track.points[i].pressure > Geometry.precision - ? 0.25*dl/(2.0*radius*track.points[i].pressure) : 0.0; + double dl = track[i].length - track[i-1].length; + double da = track[i].pressure > Geometry.precision + ? dl/(2.0*radius*track[i].pressure) : 0.0; handler.angles.Add(handler.angles[i-1] + da); } else { handler.angles.Add(0.0); @@ -88,16 +92,12 @@ namespace Assistance { // remove points int subStart = subTrack.floorIndex(subTrack.indexByOriginalIndex(start)); if (subStart < 0) subStart = 0; - if (subStart < subTrack.points.Count && subTrack.points[subStart].originalIndex + Geometry.precision < start) + if (subStart < subTrack.count && subTrack[subStart].originalIndex + Geometry.precision < start) ++subStart; - - if (subStart < subTrack.points.Count) { - subTrack.wayPointsRemoved += subTrack.points.Count - subStart; - subTrack.points.RemoveRange(subStart, subTrack.points.Count - subStart); - } + subTrack.truncate(subStart); // add points - for(int i = start; i < track.points.Count; ++i) { + for(int i = start; i < track.count; ++i) { if (i > 0) { double prevAngle = handler.angles[i-1]; double nextAngle = handler.angles[i]; @@ -105,16 +105,14 @@ namespace Assistance { double step = segmentSize/Math.Abs(nextAngle - prevAngle); double end = 1.0 - 0.5*step; for(double frac = step; frac < end; frac += step) - subTrack.points.Add( subTrack.modifier.calcPoint((double)i - 1.0 + frac) ); + subTrack.add( subTrack.modifier.calcPoint((double)i - 1.0 + frac) ); } } - subTrack.points.Add( subTrack.modifier.calcPoint(i) ); + subTrack.add( subTrack.modifier.calcPoint(i) ); } - subTrack.wayPointsAdded += subTrack.points.Count - subStart; } - track.wayPointsRemoved = 0; - track.wayPointsAdded = 0; + track.resetCounters(); } } } diff --git a/mono/Assistance/ToolFull.cs b/mono/Assistance/ToolFull.cs index 0ca178f..f055fa0 100644 --- a/mono/Assistance/ToolFull.cs +++ b/mono/Assistance/ToolFull.cs @@ -52,9 +52,9 @@ namespace Assistance { long minTicks = 0; double minTimeOffset = 0.0; foreach(Track t in tracks) { - if (t.wayPointsAdded > 0) { + if (t.pointsAdded > 0) { long ticks = t.ticks; - double timeOffset = t.timeOffset + t.points[t.points.Count - t.wayPointsAdded].time; + double timeOffset = t.timeOffset + t[t.count - t.pointsAdded].time; if (track == null || (ticks - minTicks)*Timer.frequency + timeOffset - minTimeOffset < 0.0) { track = t; minTicks = ticks; @@ -63,8 +63,8 @@ namespace Assistance { } } if (track == null) break; - paintPoint(surface, track.points[track.points.Count - track.wayPointsAdded]); - --track.wayPointsAdded; + paintPoint(surface, track[track.count - track.pointsAdded]); + track.forceAdded(track.pointsAdded - 1); } } diff --git a/mono/Assistance/Track.cs b/mono/Assistance/Track.cs index fdff864..562d951 100644 --- a/mono/Assistance/Track.cs +++ b/mono/Assistance/Track.cs @@ -65,19 +65,19 @@ namespace Assistance { private static long lastId; + private readonly List privatePoints = new List(); + private int privatePointsRemoved; + private int privatePointsAdded; public readonly long id; public readonly Gdk.Device device; public readonly long touchId; - public readonly List points = new List(); public readonly KeyHistory.Holder keyHistory; public readonly KeyHistory.Holder buttonHistory; public readonly Modifier modifier; public Handler handler; - public int wayPointsRemoved; - public int wayPointsAdded; public Track( Gdk.Device device = null, @@ -106,8 +106,59 @@ namespace Assistance { public long ticks { get { return keyHistory.ticks; } } - public bool isChanged - { get { return wayPointsAdded != 0 || wayPointsRemoved != 0; } } + public int pointsAdded + { get { return privatePointsAdded; } } + public int pointsRemoved + { get { return privatePointsRemoved; } } + public void resetRemoved() + { privatePointsRemoved = 0; } + public void resetAdded() + { privatePointsAdded = 0; } + public void resetCounters() + { resetRemoved(); resetAdded(); } + public void forceRemoved(int pointsRemoved) + { privatePointsRemoved = pointsRemoved; } + public void forceAdded(int pointsAdded) + { privatePointsAdded = pointsAdded; } + + public bool wasRemoved + { get { return pointsRemoved > 0; } } + public bool wasAdded + { get { return pointsAdded > 0; } } + public bool wasChanged + { get { return wasRemoved || wasAdded; } } + + public bool isEmpty + { get { return count == 0; } } + public int count + { get { return privatePoints.Count; } } + public void remove(int count = 1) { + if (count > this.count) count = this.count; + if (count <= 0) return; + privatePoints.RemoveRange(this.count - count, count); + privatePointsRemoved += count; + } + public void truncate(int count) + { remove(this.count - count); } + public void add(Point p) { + if (!isEmpty) { + Point previous = getLast(); + // fix originalIndex + if (p.originalIndex < previous.originalIndex) + p.originalIndex = previous.originalIndex; + // fix time + p.time = Math.Max(p.time, previous.time + Timer.step); + // calculate length + p.length = previous.length + (p.position - previous.position).len(); + } + privatePoints.Add(p); + ++privatePointsAdded; + } + + public Point this[int index] + { get { return getPoint(index); } } + public IEnumerable points + { get { return privatePoints; } } public Track getRoot() { return original == null ? this : original.getRoot(); } @@ -117,16 +168,16 @@ namespace Assistance { public Point getFirst() { return getPoint(0); } public Point getLast() - { return getPoint(points.Count - 1); } + { return getPoint(count - 1); } public bool isFinished() - { return points.Count > 0 && getLast().final; } + { return count > 0 && getLast().final; } public int clampIndex(int index) - { return Math.Min(Math.Max(index, 0), points.Count - 1); } + { return Math.Min(Math.Max(index, 0), count - 1); } public int floorIndex(double index, out double frac) { int i = (int)Math.Floor(index + Geometry.precision); - if (i > points.Count - 1) - { frac = 0.0; return points.Count - 1; } + if (i > count - 1) + { frac = 0.0; return count - 1; } if (i < 0) { frac = 0.0; return 0; } frac = Math.Max(0.0, index - (double)i); @@ -143,7 +194,7 @@ namespace Assistance { public Point getPoint(int index) { index = clampIndex(index); - return index < 0 ? new Point() : points[index]; + return index < 0 ? new Point() : privatePoints[index]; } public Point floorPoint(double index, out double frac) { return getPoint(floorIndex(index, out frac)); } @@ -156,24 +207,24 @@ namespace Assistance { private double binarySearch(double value, PointFieldGetter getter) { // points[a].value <= value < points[b].value - if (points.Count <= 0) return 0.0; + if (isEmpty) return 0.0; int a = 0; - double aa = getter(points[a]); - if (Geometry.isLess(value, aa)) return 0.0; + double aa = getter(privatePoints[a]); + if (value - aa <= 0.5*Geometry.precision) return (double)a; - int b = points.Count - 1; - double bb = getter(points[b]); - if (Geometry.isGreaterOrEqual(value, bb)) return (double)b; + int b = count - 1; + double bb = getter(privatePoints[b]); + if (bb - value <= 0.5*Geometry.precision) return (double)b; while(true) { int c = (a + b)/2; if (a == c) break; - double cc = getter(points[c]); - if (Geometry.isLess(value, cc)) + double cc = getter(privatePoints[c]); + if (cc - value > 0.5*Geometry.precision) { b = c; bb = cc; } else { a = c; aa = cc; } } - return Geometry.isLess(aa, bb) ? (double)a + (value - aa)/(bb - aa) : (double)a; + return bb - aa >= 0.5*Geometry.precision ? (double)a + (value - aa)/(bb - aa) : (double)a; } public double indexByOriginalIndex(double originalIndex) @@ -205,6 +256,16 @@ namespace Assistance { : modifier.calcPoint( originalIndexByIndex(index) ); } + public Assistance.Point calcTangent(double index, double distance = 0.1) { + double minDistance = 10.0*Geometry.precision; + if (distance < minDistance) distance = minDistance; + Point p = calcPoint(index); + Point pp = calcPoint(indexByLength(p.length - distance)); + Assistance.Point dp = p.position - pp.position; + double lenSqr = dp.lenSqr(); + return lenSqr > Geometry.precisionSqr ? dp*Math.Sqrt(1.0/lenSqr) : new Assistance.Point(); + } + public Point interpolateLinear(double index) { double frac; Point p0 = floorPoint(index, out frac); @@ -225,7 +286,7 @@ namespace Assistance { } public void print() { - foreach(Point wp in points) + foreach(Point wp in privatePoints) Console.Write( "{2:f1}, ", wp.position.x, @@ -233,6 +294,28 @@ namespace Assistance { wp.originalIndex ); Console.WriteLine(); } + + public void verify(string message) { + bool error = false; + for(int i = 1; i < count; ++i) { + Point pp = privatePoints[i-1]; + Point p = privatePoints[i]; + if ( Geometry.isGreater(pp.originalIndex, p.originalIndex) + /*|| Geometry.isGreater(pp.length, p.length) + || Geometry.isGreater(pp.time, p.time) + || pp.final*/ ) + { + if (!error) Console.WriteLine("Track error: " + message); + error = true; + Console.WriteLine("--- index: " + (i-1) + " / " + i); + Console.WriteLine(" originalIndex: " + pp.originalIndex + " / " + p.originalIndex); + Console.WriteLine(" length: " + pp.length + " / " + p.length); + Console.WriteLine(" time: " + pp.time + " / " + p.time); + Console.WriteLine(" final: " + pp.final + " / " + p.final); + } + } + if (error) print(); + } } }