/// <summary> /// Calculates the area between, in the case of this overload, two curves. /// </summary> /// <param name="calc">The <see cref="Calculator"/> to calculate the Y-values with.</param> /// <param name="top">The curve that defines the top of the integral.</param> /// <param name="bottom">The curve that defines the bottom of the integral.</param> /// <param name="leftBound">The left bound of the integral.</param> /// <param name="rightBound">The right bound of the integral.</param> /// <returns> /// The area between the curves <paramref name="top"/> and <paramref name="bottom"/>. /// </returns> public static double CalculateIntegral(Calculator calc, StandardExpression top, StandardExpression bottom, double leftBound, double rightBound) { Func<Calculator, double> distanceMethod; // Optimize for anything that might be a constant here if (top.Expression.IsConstant && bottom.Expression.IsConstant) { // The integral between two constants is just a rectangle double topConstant = calc.Evaluate(top.Expression); double bottomConstant = calc.Evaluate(bottom.Expression); // Area = Width * Height return (rightBound - leftBound) * (topConstant - bottomConstant); } if (top.Expression.IsConstant) { double topConstant = calc.Evaluate(top.Expression); distanceMethod = c => topConstant - c.Evaluate(bottom.Expression); } else if (bottom.Expression.IsConstant) { double bottomConstant = calc.Evaluate(bottom.Expression); distanceMethod = c => c.Evaluate(top.Expression) - bottomConstant; } else { distanceMethod = c => c.Evaluate(top.Expression) - c.Evaluate(bottom.Expression); } return CalculateIntegral(calc, distanceMethod, leftBound, rightBound); }
public static double CalculateDerivative(Calculator calc, StandardExpression expr, double x, out double y) { calc.GraphingArgumentValue = x; double y1 = calc.Evaluate(expr.Expression); calc.GraphingArgumentValue = x + DeltaX; double y2 = calc.Evaluate(expr.Expression); y = y1; // lim h -> 0 (f(x + h) - f(x)) / h = slope of the derivative return (y2 - y1) / DeltaX; }
private static PointD RefineIntersection(Calculator calc, StandardExpression expr1, StandardExpression expr2, IList<PointD> intersectionData) { // Whether or not expr1 starts out above expr2 bool oneOnTop = intersectionData[0].Y > intersectionData[2].Y; double lo = intersectionData[0].X; double hi = intersectionData[1].X; double mid = (lo + hi) / 2; double lastMid; do { calc.GraphingArgumentValue = mid; double y1 = calc.Evaluate(expr1.Expression); double y2 = calc.Evaluate(expr2.Expression); // Unlikely, but possible if (y1 == y2) { break; } // Check to see if the current "on top" status (whether expr1 // is above expr2) is consistent with the initial "on top" status. if ((y1 > y2) == oneOnTop) { lo = mid; } else { hi = mid; } lastMid = mid; mid = (lo + hi) / 2; } while (mid != lastMid); // Recalculate the Y value against both expressions and return the average calc.GraphingArgumentValue = mid; return new PointD(mid, (calc.Evaluate(expr1.Expression) + calc.Evaluate(expr2.Expression)) / 2).CorrectForGdiLimit(); }
public ExpressionInfo(UncompiledExpression expr, CompiledDomain domain = null) { if (expr is UncompiledStandardExpression) { var stdExpr = expr as UncompiledStandardExpression; Expression = new StandardExpression(expr.Slot, expr.Type, stdExpr.Expression, domain); } else if (expr is UncompiledParametricExpression) { var paraExpr = expr as UncompiledParametricExpression; Expression = new ParametricExpression(expr.Slot, paraExpr.XExpression, paraExpr.YExpression, domain); } else { throw new ArgumentException("expr"); } OriginalUncompiled = expr; Enabled = true; }
private static PointD RefineZero(Calculator calc, StandardExpression expr, double lowerBound, double upperBound, Sign initialSign) { double lo = lowerBound; double hi = upperBound; double mid = (lo + hi) / 2; double lastMid; double y; int i = 0; do { calc.GraphingArgumentValue = mid; y = calc.Evaluate(expr.Expression); Sign currentSign = y < 0 ? Sign.Negative : Sign.Positive; if (currentSign == initialSign) { lo = mid; } else { hi = mid; } lastMid = mid; mid = (lo + hi) / 2; // The "i < 100" below is only necessary when running in release mode, without a debugger attached. // Otherwise, it goes into an infinite loop, even though mid and lastMid actually do equal eachother. // I have no idea why that is (though its probably a race condition of some kind, despite the fact // that I'm not doing any multithreading anywhere around here). i++; } while (mid != lastMid && i < 100); return new PointD(mid, y); }
private PointF EvaluateExpression(StandardExpression expr, double xValue, bool scale = true, bool round = false) { Parent.Calculator.GraphingArgumentValue = xValue; double y = Parent.Calculator.Evaluate(expr.Expression); var point = new PointD(xValue, y); return (scale ? point.ScaleUp(XScale, YScale, round) : point).AsSingle(); }
private IEnumerable<PointF> EnsureLineSpan(StandardExpression expr, IEnumerable<PointF> existingLine) { PointF left = EvaluateExpression(expr, LeftBound); PointF right = EvaluateExpression(expr, RightBound); return new[] { left }. Concat(existingLine). Concat(new[] { right }). ToArray(); }
public static double CalculateDerivative(Calculator calc, StandardExpression expr, double x) { double y; return CalculateDerivative(calc, expr, x, out y); }
/// <summary> /// Calculates the area between, in the case of this overload, a curve and a horizontal line. /// </summary> /// <param name="calc">The <see cref="Calculator"/> to calculate the Y-values with.</param> /// <param name="top">The curve that defines the top of the integral.</param> /// <param name="bottomHorizontalLine">The horizontal line that defines the bottom of the /// integral.</param> /// <param name="leftBound">The left bound of the integral.</param> /// <param name="rightBound">The right bound of the integral.</param> /// <returns> /// The area between the curve <paramref name="top"/> and the horizontal line /// <paramref name="bottomHorizontalLine"/>. /// </returns> public static double CalculateIntegral(Calculator calc, StandardExpression top, double bottomHorizontalLine, double leftBound, double rightBound) { return CalculateIntegral(calc, c => c.Evaluate(top.Expression) - bottomHorizontalLine, leftBound, rightBound); }
/// <summary> /// Calculates the area between, in the case of this overload, a horizontal line and a curve. /// </summary> /// <param name="calc">The <see cref="Calculator"/> to calculate the Y-values with.</param> /// <param name="topHorizontalLine">The horizontal line that defines the top of the /// integral.</param> /// <param name="bottom">The curve that defines the bottom of the integral</param> /// <param name="leftBound">The left bound of the integral.</param> /// <param name="rightBound">The right bound of the integral.</param> /// <returns> /// The area between the horizontal line <paramref name="topHorizontalLine"/> and the curve /// <paramref name="bottom"/>. /// </returns> public static double CalculateIntegral(Calculator calc, double topHorizontalLine, StandardExpression bottom, double leftBound, double rightBound) { return CalculateIntegral(calc, c => topHorizontalLine - c.Evaluate(bottom.Expression), leftBound, rightBound); }
/// <summary> /// Determines whether the specified <see cref="StandardExpression"/> is equal to the /// current <see cref="StandardExpression"/>. /// </summary> /// <param name="other">The <see cref="StandardExpression"/> to compare with the current /// <see cref="StandardExpression"/>.</param> /// <returns> /// true if the specified <see cref="StandardExpression"/> is equal to the current /// <see cref="StandardExpression"/>; otherwise, false. /// </returns> public bool Equals(StandardExpression other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Equals(other.Expression.OriginalExpression, Expression.OriginalExpression); }