public AnimationCurveTpl(IReadOnlyList <KeyframeTpl <T> > keyframes, CurveLoopTypes preInfinity, CurveLoopTypes postInfinity) { PreInfinity = preInfinity; PostInfinity = postInfinity; RotationOrder = RotationOrder.OrderZXY; m_curve = new KeyframeTpl <T> [keyframes.Count]; for (int i = 0; i < keyframes.Count; i++) { m_curve[i] = keyframes[i]; } }
/// <summary> /// Sets post-infinity to the given CurveLoopTypes for the selected curves</summary> /// <param name="infType">CurveLoopTypes to be set</param> public void SetPostInfinity(CurveLoopTypes infType) { if (m_selectedCurves.Length == 0) return; m_transactionContext.DoTransaction(delegate { foreach (ICurve curve in m_selectedCurves) curve.PostInfinity = infType; }, "Edit Post-Infinity".Localize()); Invalidate(); }
/// <summary> /// Evaluates point on curve</summary> /// <param name="x">X-coordinate for which y-coordinate is calculated</param> /// <returns>Y-coordinate on curve corresponding to given x-coordinate</returns> /// <remarks>Calculates y-coordinate from x-coordinate using appropriate interpolation for a curve</remarks> public float Evaluate(float x) { if (m_points.Count == 0) { return(0.0f); } if (m_points.Count == 1) { return(m_points[0].Y); } IControlPoint firstPt = m_points[0]; IControlPoint lastPt = m_points[m_points.Count - 1]; float offset = 0.0f; if (x < firstPt.X) // pre-infiniy. { CurveLoopTypes loop = m_curve.PreInfinity; if (loop == CurveLoopTypes.Constant) { return(firstPt.Y); } if (loop == CurveLoopTypes.Linear) { return(firstPt.Y - ((firstPt.TangentIn.Y / firstPt.TangentIn.X) * (firstPt.X - x))); } float firstX = firstPt.X; float lastX = lastPt.X; float rangeX = lastX - firstX; float numcycle = (int)((firstX - x) / rangeX); float nx = ((firstX - x) - numcycle * rangeX); if (loop == CurveLoopTypes.Cycle) { x = lastX - nx; } else if (loop == CurveLoopTypes.CycleWithOffset) { x = lastX - nx; offset = -((numcycle + 1) * (lastPt.Y - firstPt.Y)); } else if (loop == CurveLoopTypes.Oscillate) { x = (((int)numcycle & 1) == 0) ? firstX + nx : lastX - nx; } } else if (x > lastPt.X) // post-infinity. { CurveLoopTypes loop = m_curve.PostInfinity; if (loop == CurveLoopTypes.Constant) { return(lastPt.Y); } if (loop == CurveLoopTypes.Linear) { return(lastPt.Y + ((lastPt.TangentOut.Y / lastPt.TangentOut.X) * (x - lastPt.X))); } float firstX = firstPt.X; float lastX = lastPt.X; float rangeX = lastX - firstX; float numcycle = (int)((x - lastX) / rangeX); float nx = (x - lastX) - numcycle * rangeX; if (loop == CurveLoopTypes.Cycle) { x = firstX + nx; } else if (loop == CurveLoopTypes.CycleWithOffset) { x = firstX + nx; offset = (numcycle + 1) * (lastPt.Y - firstPt.Y); } else if (loop == CurveLoopTypes.Oscillate) { x = (((int)numcycle & 1) == 0)? lastX - nx : firstX + nx; } } bool exactMatch; int index = FindIndex(x, out exactMatch); if (exactMatch) { return(m_points[index].Y + offset); } IControlPoint p1 = m_points[index]; IControlPoint p2 = m_points[index + 1]; if (p1.TangentOut.X == 0 && p1.TangentOut.Y == 0) {// step return(p1.Y + offset); } else if (p1.TangentOut.X == float.MaxValue && p1.TangentOut.Y == float.MaxValue) {// step-next return(p2.Y + offset); } else {// hermite eval. if (m_lastP1 != p1) { // compute coeff. ComputeHermiteCoeff(p1, p2, m_coeff); m_lastP1 = p1; } return(CubicPolyEval(p1.X, x, m_coeff) + offset); } }
/// <summary> /// Evaluates point on curve</summary> /// <param name="x">X-coordinate for which y-coordinate is calculated</param> /// <returns>Y-coordinate on curve corresponding to given x-coordinate</returns> /// <remarks>Calculates y-coordinate from x-coordinate using appropriate interpolation for a curve</remarks> public float Evaluate(float x) { if (m_points.Count == 0) { return(0.0f); } if (m_points.Count == 1) { return(m_points[0].Y); } IControlPoint firstPt = m_points[0]; IControlPoint lastPt = m_points[m_points.Count - 1]; float offset = 0.0f; if (x < firstPt.X) // pre-infiniy. { CurveLoopTypes loop = m_curve.PreInfinity; if (loop == CurveLoopTypes.Constant) { return(firstPt.Y); } if (loop == CurveLoopTypes.Linear) { IControlPoint secondPt = m_points[1]; float slope = (secondPt.Y - firstPt.Y) / (secondPt.X - firstPt.X); return(firstPt.Y - slope * (firstPt.X - x)); } float firstX = firstPt.X; float lastX = lastPt.X; float rangeX = lastX - firstX; float numcycle = (int)((firstX - x) / rangeX); float nx = ((firstX - x) - numcycle * rangeX); if (loop == CurveLoopTypes.Cycle) { x = lastX - nx; } else if (loop == CurveLoopTypes.CycleWithOffset) { x = lastX - nx; offset = -((numcycle + 1) * (lastPt.Y - firstPt.Y)); } else if (loop == CurveLoopTypes.Oscillate) { x = (((int)numcycle & 1) == 0) ? firstX + nx : lastX - nx; } } else if (x > lastPt.X) // post-infinity. { CurveLoopTypes loop = m_curve.PostInfinity; if (loop == CurveLoopTypes.Constant) { return(lastPt.Y); } if (loop == CurveLoopTypes.Linear) { IControlPoint beforeLastPt = m_points[m_points.Count - 2]; float slope = (lastPt.Y - beforeLastPt.Y) / (lastPt.X - beforeLastPt.X); return(lastPt.Y + slope * (x - lastPt.X)); } float firstX = firstPt.X; float lastX = lastPt.X; float rangeX = lastX - firstX; float numcycle = (int)((x - lastX) / rangeX); float nx = (x - lastX) - numcycle * rangeX; if (loop == CurveLoopTypes.Cycle) { x = firstX + nx; } else if (loop == CurveLoopTypes.CycleWithOffset) { x = firstX + nx; offset = (numcycle + 1) * (lastPt.Y - firstPt.Y); } else if (loop == CurveLoopTypes.Oscillate) { x = (((int)numcycle & 1) == 0)? lastX - nx : firstX + nx; } } bool exactMatch; int index = FindIndex(x, out exactMatch); if (exactMatch) { return(m_points[index].Y + offset); } IControlPoint p1 = m_points[index]; IControlPoint p2 = m_points[index + 1]; if (m_lastP1 != p1) { // compute slope and y intercept m = (p2.Y - p1.Y) / (p2.X - p1.X); b = p1.Y - m * p1.X; m_lastP1 = p1; } // y = mx + b // offset is computed from post and pre infinities. return(m * x + b + offset); }
/// <summary> /// Sets post-infinity to the given CurveLoopTypes for the selected curves</summary> /// <param name="infType">CurveLoopTypes to be set</param> public void SetPostInfinity(CurveLoopTypes infType) { if (m_editSet.Count == 0 && m_selectedCurves.Length == 0) return; IEnumerable<ICurve> curves = m_editSet.Count > 0 ? (IEnumerable<ICurve>)m_editSet : m_selectedCurves; m_transactionContext.DoTransaction(delegate { foreach (ICurve curve in curves) curve.PostInfinity = infType; }, "Edit Post-Infinity".Localize()); Invalidate(); }