private void FrameSelection(bool allKeys) { // Get min max value of all curves and keys. Vector2 min = new Vector2(Single.MaxValue, Single.MaxValue); Vector2 max = new Vector2(Single.MinValue, Single.MinValue); bool needToDefault = true; foreach (EditCurve curve in curves) { if (!allKeys && curve.Visible == false) { continue; } for (int idx = 0; idx < curve.Keys.Count; ++idx) { EditCurveKey key = curve.Keys[idx]; if (!allKeys && key.Selection == EditCurveSelections.None) { continue; } Vector2 pos = new Vector2(key.Position, key.Value); min = Vector2.Min(min, pos); max = Vector2.Max(max, pos); // Sample few point for more aculate result. if (idx < curve.Keys.Count - 1) { float nextPosition = curve.Keys[idx + 1].Position; const int sampleCount = 4; // at 0 is already sampled and 1 will be sampled in next loop. float dt = 1.0f / (float)(sampleCount + 2); float nt = dt; for (int i = 0; i < sampleCount; ++i, nt += dt) { float t = MathHelper.Lerp(key.Position, nextPosition, nt); pos = new Vector2(t, curve.Evaluate(t)); min = Vector2.Min(min, pos); max = Vector2.Max(max, pos); } } needToDefault = false; } } if (needToDefault) { min = -Vector2.One; max = Vector2.One; } if (curveView.Frame(min, max)) { RequestRender(); } }
/// <summary> /// Mark modified key. /// </summary> private void MarkModify(EditCurveKey key) { // Clone and save current EditCurveKey to modified keys. if (modifiedKeys != null && !modifiedKeys.ContainsKey(key.Id)) { modifiedKeys.Add(key.Id, key.Clone()); dirty = true; } }
public EditCurveKeyAddRemoveCommand(EditCurve curve, EditCurveKey addKey, EditCurveKeySelection selection) { this.curve = curve; this.addKey = true; this.selection = selection.Clone(); keys = new List <EditCurveKey>(); keys.Add(addKey.Clone()); }
/// <summary> /// Returns selected key list. /// </summary> /// <returns></returns> public EditCurveKey[] GetSelectedKeys() { EditCurveKey[] keys = new EditCurveKey[selectedKeys.Count]; int idx = 0; foreach (EditCurveKey key in selectedKeys.Values) { keys[idx++] = key; } return(keys); }
private void AddKeys() { foreach (EditCurveKey savedKey in keys) { EditCurveKey addingKey = savedKey.Clone(); curve.Keys.Add(addingKey); // Removing key requires re-compute neighbor keys tangents. curve.ComputeTangents(curve.Keys.IndexOf(addingKey)); } curve.ApplySelection(new EditCurveKeySelection(keys), false); }
/// <summary> /// /// </summary> /// <param name="key"></param> /// <param name="continuity"></param> private void SetKeyContinuity(EditCurveKey key, CurveContinuity continuity) { if (key.Continuity != continuity) { MarkModify(key); key.Continuity = continuity; if (continuity == CurveContinuity.Step) { key.TangentIn = key.TangentOut = 0; key.TangentInType = key.TangentInType = EditCurveTangent.Flat; } } }
private void DrawTangents(Graphics g, EditCurve curve) { System.Drawing.Color[] colors = new System.Drawing.Color[] { System.Drawing.Color.Yellow, System.Drawing.Color.Brown }; float len = 50.0f; Vector2 pt1 = new Vector2(); EditCurveSelections tangentSelection = EditCurveSelections.Key | EditCurveSelections.TangentIn | EditCurveSelections.TangentOut; for (int i = 0; i < curve.Keys.Count; ++i) { EditCurveKey editKey = curve.Keys[i]; CurveKey key = editKey.OriginalKey; EditCurveSelections selection = editKey.Selection; bool isSelecting = (selection & tangentSelection) != 0; if (((isSelecting && curve.Editable) || curveTangentsViewMode == EditCurveView.Always) && key.Continuity == CurveContinuity.Smooth) { pt1 = curveView.ToPixelCoordinate(key.Position, key.Value); int colIdx = 0; float screen_tangent; // tan-in. colIdx = (selection & EditCurveSelections.TangentIn) != 0 ? 0 : 1; screen_tangent = curveView.UnitToScreenTangentAngle( key.TangentIn / curve.GetDistanceOfKeys(i, 0)); DrawArrow(g, pt1, (float)Math.PI + (float)Math.Atan(screen_tangent), len, colors[colIdx]); // tan-out. colIdx = (selection & EditCurveSelections.TangentOut) != 0 ? 0 : 1; screen_tangent = curveView.UnitToScreenTangentAngle( key.TangentOut / curve.GetDistanceOfKeys(i, 1)); DrawArrow(g, pt1, (float)Math.Atan(screen_tangent), len, colors[colIdx]); } } }
/// <summary> /// Compute specfied index key tangents. /// </summary> /// <param name="idx"></param> public void ComputeTangents(int keyIndex) { if (keyIndex < 0 || keyIndex > keys.Count || keyIndex > Int32.MaxValue - 2) { throw new ArgumentOutOfRangeException("keyIndex"); } // Compute neighbors tangents too. for (int i = keyIndex - 1; i < keyIndex + 2; ++i) { if (i >= 0 && i < keys.Count) { EditCurveKey key = keys[i]; MarkModify(key); float tangentInValue = key.TangentIn; float tangentOutValue = key.TangentOut; CurveTangent tangentIn = Convert(key.TangentInType); CurveTangent tangentOut = Convert(key.TangentOutType); OriginalCurve.ComputeTangent(i, tangentIn, tangentOut); if (Single.IsNaN(key.TangentIn)) { key.TangentIn = 0.0f; } if (Single.IsNaN(key.TangentOut)) { key.TangentOut = 0.0f; } // Restore original value if EditCurveTanget is fixed. if (key.TangentInType == EditCurveTangent.Fixed) { key.TangentIn = tangentInValue; } if (key.TangentOutType == EditCurveTangent.Fixed) { key.TangentOut = tangentOutValue; } } } }
/// <summary> /// Apply given key values. /// </summary> /// <param name="newKeyValues"></param> public void ApplyKeyValues(ICollection <EditCurveKey> newKeyValues) { foreach (EditCurveKey newKeyValue in newKeyValues) { EditCurveKey key = newKeyValue.Clone(); // Update key value. keys.Remove(keys.GetValue(key.Id)); keys.Add(key); // Also, update key values if that key is selected. if (selectedKeys.ContainsKey(key.Id)) { selectedKeys.Remove(key.Id); selectedKeys.Add(key.Id, key); } dirty = true; } }
/// <summary> /// Add new key at given position. /// </summary> /// <param name="pos"></param> public void AddKey(Vector2 pos) { EnsureUpdating("AddKey"); // Create new key. EditCurveKey key = new EditCurveKey(EditCurveKey.GenerateUniqueId(), new CurveKey(pos.X, pos.Y)); key.Selection = EditCurveSelections.Key; // Generate add key command and execute it. EditCurveKeyAddRemoveCommand command = new EditCurveKeyAddRemoveCommand(this, key, selection); command.Execute(); if (commandHistory != null) { commandHistory.Add(command); } }
/// <summary> /// Apply key selection. /// </summary> /// <param name="newSelection"></param> /// <param name="generateCommand"></param> public void ApplySelection(EditCurveKeySelection newSelection, bool generateCommand) { // Re-create selected keys and store selection information from // new selection. selectedKeys.Clear();; foreach (long id in newSelection.Keys) { EditCurveKey key = keys.GetValue(id); key.Selection = newSelection[id]; selectedKeys.Add(key.Id, key); } // Clear de-selected keys selection information. foreach (long id in selection.Keys) { if (!newSelection.ContainsKey(id)) { EditCurveKey key; if (keys.TryGetValue(id, out key)) { key.Selection = EditCurveSelections.None; } } } // Invoke selection change event. if (generateCommand == true && !newSelection.Equals(selection) && commandHistory != null) { commandHistory.Add(new SelectCommand(this, newSelection, selection)); } // Update selection. selection = newSelection; }
/// <summary> /// Draw actual part of curve. /// </summary> /// <param name="g"></param> /// <param name="pen"></param> /// <param name="curve"></param> /// <param name="t0"></param> /// <param name="t1"></param> /// <param name="step"></param> private void DrawCurve(Graphics g, Pen pen, EditCurve curve, double t0, double t1, double step) { Vector2[] p = new Vector2[2] { new Vector2(), new Vector2() }; // Search key and next key that includes t0 position. int keyIndex = 0; EditCurveKey key = null, nextKey = null; for (; keyIndex < curve.Keys.Count; ++keyIndex) { key = nextKey; nextKey = curve.Keys[keyIndex]; if (nextKey.Position > t0) { break; } } int pIdx = 0; p[pIdx] = curveView.ToPixelCoordinate((float)t0, curve.Evaluate((float)t0)); for (double t = t0; t < t1;) { double nextT = t1 + step; if (nextKey != null) { nextT = Math.Min(t1, nextKey.Position); } // Draw current key and next key section. if (key.Continuity == CurveContinuity.Smooth) { while (t < nextT) { // If this line crosses next key position, draw line from // current position to next key position. t = (t <nextT && t + step> nextT)? nextT: t + step; pIdx = (pIdx + 1) & 1; p[pIdx] = curveView.ToPixelCoordinate( (float)t, curve.Evaluate((float)t)); DrawLine(g, pen, p[0], p[1]); } } else { // Step case, // Draw, horizontal line. pIdx = (pIdx + 1) & 1; p[pIdx] = curveView.ToPixelCoordinate(nextKey.Position, key.Value); DrawLine(g, pen, p[0], p[1]); // Draw vertical line. pIdx = (pIdx + 1) & 1; p[pIdx] = curveView.ToPixelCoordinate( nextKey.Position, nextKey.Value); DrawLine(g, pen, p[0], p[1]); t = nextT; } // Advance to next key. key = nextKey; nextKey = (++keyIndex < curve.Keys.Count) ? curve.Keys[keyIndex] : null; } }