/// <summary> /// Value adjusted manually by the user. /// </summary> public void SetUserValue(PointF value) { // The context should have been set at Track() time when we landed on the video frame. if (context == null) { return; } currentValue = value; timeDifference = 0; // There are several cases. // The important point is that as long as we have tracking data the "reading" part will always pick the nearest point from the timeline. // We do not store a point position for all "non-tracked" times, this would break the trajectory when in-between tracked points. // The non-tracking value is only for when the timeline is empty. // Cases: // 1. We are actively tracking: update the timeline. // 2. We are not tracking and we never tracked this object: do not update the timeline. // 3. We are not tracking but we are on a previously tracked point: update the timeline. // In this case it doesn't make sense to force the user to re-enable tracking, we know this point is tracked. // 4. We are not tracking and we are not on a tracked point: update the timeline. // This is the tricky case, but if we don't update the timeline the move is lost. if (isTracking || trackTimeline.HasData()) { trackTimeline.Insert(context.Time, CreateTrackFrame(value, PositionningSource.Manual)); } else { nonTrackingValue = value; } }