/// <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();
        }
Exemplo n.º 4
0
            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);
 }