public static void RemoveInvalid(List <SnapOffsetInfo> infos) { float smallestDist = float.MaxValue; for (int i = 0; i < infos.Count; i++) { SnapOffsetInfo info = infos[i]; if (info.m_dist < smallestDist) { smallestDist = info.m_dist; } } int nextValid = 0; for (int i = 0; i < infos.Count; i++) { SnapOffsetInfo info = infos[i]; // if smallestDist is still MaxValue, then adding the tolerance has no effect if (info.m_dist < smallestDist + 0.0001f) { infos[nextValid++] = info; } } infos.RemoveRange(nextValid, infos.Count - nextValid); }
/// <summary> /// Gets the offset from one of the world snap points to the closest non-selected object's edge</summary> /// <param name="movingPoints">The x-coordinates to snap "from", in world coordinates</param> /// <param name="options">The options to control the behavior. If null, the defaults are used.</param> /// <returns>The value to be added, to GetDragOffset().X, for example. Is in world coordinates.</returns> private float GetSnapOffset(IEnumerable <float> movingPoints, TimelineControl.SnapOptions options) { //we want to recalculate m_snapInfo and reflect changes to the snap-to lines m_snapInfo.Clear(); m_owner.Invalidate(); if (options == null) { options = new TimelineControl.SnapOptions(); } // Check for user-forced snapping and no-snapping. if (options.CheckModifierKeys) { Keys modKeys = Control.ModifierKeys; if (s_deactivatorKeys != Keys.None && (modKeys & s_deactivatorKeys) == s_deactivatorKeys) { return(0.0f); } if (s_activatorKeys != Keys.None && (modKeys & s_activatorKeys) != s_activatorKeys) { return(0.0f); } } // Prepare helper object on each moving point. foreach (float snapping in movingPoints) { m_snapInfo.Add(new SnapOffsetInfo(snapping)); } if (m_snapInfo.Count == 0) { return(0.0f); } // Find the closest IEvent. float worldSnapTolerance = GdiUtil.InverseTransformVector(m_owner.Transform, s_snapTolerance); List <TimelinePath> events = new List <TimelinePath>( TimelineControl.GetObjects <IEvent>(m_owner.Timeline)); // Allow for snapping to a scrubber manipulator. if (m_scrubber != null && options.IncludeScrubber) { events.Add(new TimelinePath(m_scrubber)); } foreach (TimelinePath path in events) { if (options.IncludeSelected || !m_owner.Selection.SelectionContains(path)) { IEvent snapToEvent = (IEvent)path.Last; if (options.Filter == null || options.Filter(snapToEvent, options)) { Matrix localToWorld = TimelineControl.CalculateLocalToWorld(path); float start, length; GetEventDimensions(snapToEvent, localToWorld, out start, out length); foreach (SnapOffsetInfo info in m_snapInfo) { info.Update(start, snapToEvent, worldSnapTolerance); if (length > 0) { info.Update(start + length, snapToEvent, worldSnapTolerance); } } } } } // Keep only the shortest distance snap-to points. Could be multiple in case of tie. SnapOffsetInfo.RemoveInvalid(m_snapInfo); if (m_snapInfo.Count == 0) { return(0.0f); } SnapOffsetInfo topInfo = m_snapInfo[0]; return(topInfo.Offset); }