public CalculateMinMax(Calculator calc, IEnumerable<Expression> criteria, bool isMax)
        {
            InitializeComponent();

            _calc = calc;

            string operationType = isMax ? "maximum" : "minimum";

            Text = string.Format(Text, operationType);
            instructions.Text = string.Format(instructions.Text, operationType);

            var buttons = from expr in criteria
                          select new RadioButton
                                 {
                                     Text = expr.ToString(),
                                     Tag = expr,
                                     AutoSize = true
                                 };

            _checkables = buttons.ToArray();

            if (_checkables.Length == 0)
            {
                throw new ArgumentException("Must contain at least one expression.", "criteria");
            }

            _checkables[0].Checked = true;
            flowLayoutPanel1.Controls.AddRange(_checkables);

            OnManualBoundsRadioCheckedChanged(null, null);
        }
        /// <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 List<IntersectionInfo> CalculateIntersections(Calculator calc, IList<CalculatedLine> exprs)
        {
            // Find each possible pair of each line with no repeats
            // Asked how to do this in LINQ here: "http://stackoverflow.com/questions/3479980"
            var range = Enumerable.Range(0, exprs.Count).ToArray();
            var pairs = from i in range
                        from second in range.Skip(i + 1)
                        select new
                               {
                                   First = exprs[i],
                                   Second = exprs[second]
                               };

            // Calculate and refine each intersection in each pair
            var intrs = from pair in pairs.AsParallel().AsOrdered()
                        let unrefined = FindRoughIntersections(pair.First, pair.Second)
                        select from intersection in unrefined
                               let refined = RefineIntersection(new Calculator(calc),
                                                                (StandardExpression)pair.First.Expression,
                                                                (StandardExpression)pair.Second.Expression,
                                                                intersection)
                               select new IntersectionInfo(pair.First.Expression.ToString(),
                                                           pair.Second.Expression.ToString(),
                                                           refined);

            return intrs.SelectMany(p => p).Distinct().ToList();
        }
        private void OnLoad(object sender, EventArgs e)
        {
            Application.Idle += OnApplicationIdle;

            GL.ClearColor(Color.CornflowerBlue);
            GL.Enable(EnableCap.DepthTest);

            SetupViewport();

            Context.VSync = true;

            _window = new Window3D(-50, 50, -50, 50, -50, 50);

            Calculator calc = new Calculator();
            CompiledExpression expr = ExpressionCompiler.CompileInfix("sin(x)+cos(y)", false);

            var mesh = LineCalculator3D.Calculate(calc, expr, _window, 0.5F);

            // Vertices
            GL.GenBuffers(1, out _bufferInfo.VertexId);
            GL.BindBuffer(BufferTarget.ArrayBuffer, _bufferInfo.VertexId);
            GL.BufferData(BufferTarget.ArrayBuffer, mesh.VertexArraySize, mesh.Vertices, BufferUsageHint.StaticDraw);

            // Indices
            GL.GenBuffers(1, out _bufferInfo.IndexId);
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, _bufferInfo.IndexId);
            GL.BufferData(BufferTarget.ElementArrayBuffer, mesh.IndexArraySize, mesh.Indices, BufferUsageHint.StaticDraw);

            // Colors
            GL.GenBuffers(1, out _bufferInfo.ColorId);
            GL.BindBuffer(BufferTarget.ArrayBuffer, _bufferInfo.ColorId);
            GL.BufferData(BufferTarget.ArrayBuffer, mesh.ColorArraySize, mesh.Colors, BufferUsageHint.StaticDraw);

            _bufferInfo.IndexCount = mesh.Indices.Length;
        }
        /// <summary>
        /// Initializes a new instance of the Calculator class using data from another <see cref="Calculator"/>
        /// instance.
        /// </summary>
        /// <param name="calcToCopy">The <see cref="Calculator"/> instance to copy data from into this new
        /// instance.</param>
        public Calculator(Calculator calcToCopy)
        {
            // Copy the dictionaries into a new instance
            _arguments = calcToCopy._arguments.ToDictionary(pair => pair.Key,
                                                      pair => pair.Value);

            _funcs = calcToCopy._funcs.ToDictionary(pair => pair.Key,
                                              pair => pair.Value);
        }
        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;
        }
        public static CompiledDomain CompileDomain(Calculator calc, IList<Constraint> domain)
        {
            // Signature: bool Domain(CompiledExpression[] leftRightExprs, Calculator calc)
            DynamicMethod method = GetDomainDynamicMethod();
            ILGenerator il = method.GetILGenerator();

            if (domain == null || domain.Count == 0)
            {
                return EmptyDomain;
            }

            List<CompiledExpression> expressions = new List<CompiledExpression>();
            foreach (Constraint constraint in domain)
            {
                CompiledExpression left = ExpressionCompiler.CompileInfix(constraint.LeftValue);
                CompiledExpression right = ExpressionCompiler.CompileInfix(constraint.RightValue);

                Label success = il.DefineLabel();

                PushExpressionValue(il, left, expressions, calc);
                PushExpressionValue(il, right, expressions, calc);

                // Check for the equality to be true
                OpCode op = GetOpCodeFromEquality(constraint.Equality);
                if (op == default(OpCode))
                {
                    // Not equal to
                    il.Emit(OpCodes.Ceq);
                    il.Emit(OpCodes.Brfalse, success);
                }
                else
                {
                    il.Emit(op, success);
                }

                // Left side was not true, return false
                il.Emit(OpCodes.Ldc_I4_0); // Push 0 (represents false)
                il.Emit(OpCodes.Ret); // Return

                // Left side was true, test the right side now
                il.MarkLabel(success);
            }

            // Left and right (if there was a right side) were right, return true
            il.Emit(OpCodes.Ldc_I4_1); // Push 1 (represents true)
            il.Emit(OpCodes.Ret); // Return

            return new CompiledDomain(method, expressions.ToArray(), domain);
        }
        private static PointD FindMostSignificant(Calculator calc, CalculatedLine line, double leftBound, double rightBound, Mode mode)
        {
            if (line.Expression.Type != ExpressionType.Linear)
            {
                throw new ArgumentException("The line must be a linear one.");
            }

            if (line.PointData.Count == 0)
            {
                throw new ArgumentException("The calculated line must contain at least one line segment.");
            }

            RoughSignificant roughMax = GetRoughSignificant(line, calc, leftBound, rightBound, mode);
            return RefineSignificant(calc, line, roughMax, mode);
        }
        /// <summary>
        /// Initializes a new instance of the Graph class.
        /// </summary>
        public Graph()
        {
            _drawHelper = new GraphDrawingHelper(this);
            _integralDrawHelper = new IntegralDrawingHelper(this);

            _resolution = 1;
            _window = Window.Standard;

            Calculator = new Calculator();

            _zoom = new ZoomMouseAdapter(this);
            _zoom.Zoom +=
                delegate(object sender, GenericEventArgs<Window> e)
                {
                    Window = e.Data;

                    RestoreDefaultAdapter();

                    var handler = WindowChanged;
                    if (handler != null)
                    {
                        handler(this, EventArgs.Empty);
                    }
                };

            _xRange = new XRangeMouseAdapter(this);
            _xRange.XRangeCreated +=
                delegate(object sender, XRangeCreatedEventArgs e)
                {
                    RestoreDefaultAdapter();

                    var handler = XRangeCreated;
                    if (handler != null)
                    {
                        handler(this, e);
                    }
                };

            _dragging = new DraggingMouseAdapter(this);
            _current = _dragging;

            // Prevents flickering
            DoubleBuffered = true;

            ResizeRedraw = true;
        }
        public static double CalculateDerivative(Calculator calc, ParametricExpression expr, double t, out PointD result)
        {
            calc.GraphingArgumentValue = t;
            double x1 = calc.Evaluate(expr.XExpression);
            double y1 = calc.Evaluate(expr.YExpression);

            calc.GraphingArgumentValue = t + DeltaX;
            double x2 = calc.Evaluate(expr.XExpression);
            double y2 = calc.Evaluate(expr.YExpression);

            double fPrime1 = (x2 - x1) / DeltaX;
            double fPrime2 = (y2 - y1) / DeltaX;

            result = new PointD(x1, y1);

            return fPrime2 / fPrime1;
        }
        public SelectValue(Calculator calc, IEnumerable<Expression> criteria)
        {
            InitializeComponent();

            _calc = calc;

            foreach (Expression expr in criteria)
            {
                listboxLines.Items.Add(expr);
                _exprs.Add(expr);
            }

            if (listboxLines.Items.Count == 0)
            {
                throw new Exception();
            }

            listboxLines.SelectedIndex = 0;
        }
        private static PointD[] CalculateLine(Calculator calc, CalculatedLine line, double end, ref double pos)
        {
            if (pos > end)
            {
                throw new ArgumentException("The current position is greater than the end.");
            }

            int i = 0;
            var filled = new PointD[(int)Math.Round(Math.Abs(end - pos) / line.Increment)];
            while (end - pos > 1E-10 || pos < end)
            {
                calc.GraphingArgumentValue = pos;
                filled[i++] = new PointD(pos * line.XScale,
                                         calc.Evaluate(((StandardExpression)line.Expression).Expression) * line.YScale);

                pos += line.Increment;
            }

            return filled;
        }
        public CalculateIntegral(Calculator calc, IEnumerable<StandardExpression> exprs)
        {
            InitializeComponent();

            _calc = calc;
            _exprs = new List<StandardExpression>();

            foreach (var expr in exprs)
            {
                listboxDefiniteIntegralList.Items.Add(expr);
                _exprs.Add(expr);
            }

            OnRadioButtonCheckedChanged(null, EventArgs.Empty);

            if (listboxDefiniteIntegralList.Items.Count > 0)
            {
                listboxDefiniteIntegralList.SelectedIndex = 0;
                textboxLeftBound.Select();
            }
        }
        /// <summary>
        /// Finds every point on the specified line where that line crosses the X axis.
        /// </summary>
        /// <param name="calc">The calculator used to evaluate the expression.</param>
        /// <param name="line">The line to test for zeros.</param>
        /// <returns>
        /// A list of points where the specified line crosses the X axis. If the line does not
        /// cross the X axis at any point, the list will be empty.
        /// </returns>
        /// <remarks><para>
        /// The algorithm used to find the zeros of a line is similar to the binary search
        /// algorithm.
        /// </para><para>
        /// First, each point on the line is iterated through. In each iteration, it checks if the
        /// sign of the Y values of the current point and the last point on the line are different.
        /// For example, if we are iterating through the line "5x + 5," once we iterate through the
        /// point (-1.5, -2.5) and (-0.5, 2.5), we find that the Y values have changed from negative
        /// to positive. Those two points are then stored for later use. We repeat this process until
        /// we reach the end of the line.
        /// </para><para>
        /// After we store each place where the Y values change signs, the binary search begins.
        /// In a single iteration, we first determine if the left point of the pair (the minimum)
        /// begins in the negative or positive side of the X axis. If it begins in the negative, it
        /// is said to be moving "upward." Otherwise, it is moving "downward." This is important
        /// because it determines what values are set to the high and low values for the binary
        /// search. One of two things then happen:
        /// </para><para>
        /// In the case of the line going upward, if the sign of the middle value is negative, then
        /// the low value becomes the middle value for the next iteration. Otherwise, the high value
        /// becomes the middle value.
        /// </para><para>
        /// In the case of the line going downward, if the sign of the middle value is positive, then
        /// the low value becomes the middle value for the next iteration. Otherwise, the high value
        /// becomes the middle value.
        /// </para><para>
        /// This continues until the middle values for two consecutive iterations are the same value.
        /// Once this happens, the limits of the precision and accuracy of the datatype we are using
        /// (64-bit floating point in this specific implementation's case) has been reached, and the
        /// search stops. The final middle value is the X value of the zero.
        /// </para></remarks>
        public static List<PointD> FindZeros(Calculator calc, CalculatedLine line)
        {
            if (line.Expression.Type != ExpressionType.Linear)
            {
                throw new ArgumentException("The expression type must be Linear.");
            }

            // Each PointF array represents the two points where the
            // sign changes from positive to negative or vice versa
            var signChanges = from roughZero in line.PointData.SelectMany(FindRoughZero)
                              select new
                              {
                                  LowerBound = roughZero[0].X / line.XScale,
                                  UpperBound = roughZero[1].X / line.XScale,
                                  InitialSign = roughZero[0].Y < 0 ? Sign.Negative : Sign.Positive
                              };

            // Find the corresponding zero for each sign change
            var zeros = from change in signChanges
                        select RefineZero(calc, (StandardExpression)line.Expression, change.LowerBound, change.UpperBound, change.InitialSign);

            return zeros.ToList();
        }
        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);
        }
 public static PointD FindMinimum(Calculator calc, CalculatedLine line, double leftBound, double rightBound)
 {
     return FindMostSignificant(calc, line, leftBound, rightBound, Mode.Minimum);
 }
        private static PointD RefineSignificant(Calculator calc, CalculatedLine line, RoughSignificant roughSig, Mode mode)
        {
            double lo = roughSig.Left.X / line.XScale;
            double hi = roughSig.Right.X / line.XScale;
            double mid = (lo + hi) / 2;
            double lastMid = double.NaN;

            var stdExpr = (StandardExpression)line.Expression;
            Func<double, int> derivComparer = mode == Mode.Maximum ? _maxDerivComparer : _minDerivComparer;

            double y;
            while (lastMid != mid)
            {
                double deriv = DerivativeCalculator.CalculateDerivative(calc, stdExpr, mid, out y);
                int result = derivComparer(deriv);
                if (result == -1)
                {
                    lo = mid;
                }
                else if (result == 1)
                {
                    hi = mid;
                }
                else
                {
                    // Unlikely, but possible
                    break;
                }

                lastMid = mid;
                mid = (lo + hi) / 2;
            }

            mid = Math.Round(mid, DerivativeCalculator.DeltaXPrecision);

            calc.GraphingArgumentValue = mid;
            y = calc.Evaluate(stdExpr.Expression);

            return new PointD(mid, y);
        }
        private static RoughSignificant GetRoughSignificant(CalculatedLine line, Calculator calc, double leftBound, double rightBound, Mode mode)
        {
            IList<IList<PointD>> segments = line.PointData.Count > 1 ? GetCompleteLine(calc, line) : line.PointData;

            double scaledLeftBound = leftBound * line.XScale;
            double scaledRightBound = rightBound * line.XScale;

            Func<double, double, bool> comparer = mode == Mode.Maximum ? _maxValComparer : _minValComparer;
            var significant = new PointD(0, mode == Mode.Maximum ? double.MinValue : double.MaxValue);
            int signifSegment = -1, signifPoint = -1;
            for (int i = 0; i < segments.Count; i++)
            {
                var segment = segments[i];
                for (int j = 0; j < segment.Count; j++)
                {
                    var point = segment[j];
                    if (comparer(significant.Y, point.Y) && point.X >= scaledLeftBound && point.X <= scaledRightBound)
                    {
                        significant = point;
                        signifSegment = i;
                        signifPoint = j;
                    }
                }
            }

            if (signifSegment == -1 || signifPoint == -1)
            {
                throw new Exception("No significant value could be found.");
            }

            // Get the points to the left and right of the rough maximum
            PointD left;
            PointD right;
            GetSurroundingPoints(segments, signifSegment, signifPoint, out left, out right);

            return new RoughSignificant(left, right);
        }
 /// <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);
 }
        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();
        }
        private static double CalculateAreaChunk(Calculator calc, Func<Calculator, double> distanceMethod, double start, double rightBound, int iterCount)
        {
            iterCount++;

            double totalArea = 0;
            double lastX = start;

            calc.GraphingArgumentValue = start;

            // The left side of the trapezoid
            double a = distanceMethod(calc);

            bool calcEnd = false;
            for (int i = 1; i < iterCount; i++)
            {
                double x = lastX + Increment;

                if (x > rightBound)
                {
                    x = rightBound;
                    calcEnd = true;
                }

                // Height of a sideways trapezoid
                calc.GraphingArgumentValue = x;

                double b = distanceMethod(calc);

                // Area of trapezoid = (a + b) / 2 * h
                // In this case, the trapezoid is sideways, so the height is the
                // increment, or the space between the previous and current iteration
                totalArea += (a + b) / 2 * (x - lastX);

                lastX = x;
                a = b;

                if (calcEnd)
                {
                    break;
                }
            }

            return totalArea;
        }
        private static double CalculateIntegral(Calculator calc, Func<Calculator, double> distanceMethod, double leftBound, double rightBound)
        {
            // Protip: the Wolfram Alpha way of verifying the results from this is:
            // "integral of (<<top>> - <<bottom>>)dx between <<start>> and <<stop>>"

            int numCores = Environment.ProcessorCount;

            int iterCount = (int)Math.Ceiling((rightBound - leftBound) / Increment);
            int itersPerCore = (int)Math.Floor((double)iterCount / numCores);

            // The number of iterations that the last thread should do (to accomodate for rounding errors)
            int lastCoreIters = itersPerCore + (iterCount % numCores);

            // Assemble the worker threads
            Task<double>[] tasks = new Task<double>[numCores];
            int core = 0;

            bool lastTask = false;
            while (!lastTask)
            {
                lastTask = core + 1 >= numCores;

                double start = leftBound + ((core * itersPerCore) * Increment);
                int numIters = (lastTask ? lastCoreIters : itersPerCore);

                tasks[core++] = new Task<double>(() => CalculateAreaChunk(new Calculator(calc), distanceMethod, start, rightBound, numIters));
            }

            foreach (Task<double> t in tasks)
            {
                t.Start();
            }

            Task.WaitAll(tasks);

            double totalArea = tasks.Sum(t => t.Result);

            // Find the number of decimal places the increment goes to
            int decPlace = 0;
            double slicedIncrement = Increment;

            // Move the decimal point of the increment to the right on each iteration. We keep
            // moving the decimal over until the first significant digit of the increment is found
            while ((int)(slicedIncrement *= 10) == 0)
            {
                decPlace++;
            }

            // Assume the area is only accurate to the number of decimal places that the increment has
            return Math.Round(totalArea, decPlace + 1);
        }
 public bool Evaluate(Calculator calc)
 {
     return _compiledDomain(calc);
 }
 /// <summary>
 /// Evalutes the compiled expression with the specified arguments.
 /// </summary>
 /// <returns></returns>
 public double Evaluate(double[] arguments, Calculator calc)
 {
     return _compiled(arguments, calc);
 }
        private static void PushExpressionValue(ILGenerator il, CompiledExpression left, List<CompiledExpression> expressions, Calculator calc)
        {
            if (left.Arguments.Count > 0 || left.GraphingArgumentPresent)
            {
                // Push the Calculator
                il.Emit(OpCodes.Ldarg_1);

                // Evaluate and push the left side of the equality
                il.Emit(OpCodes.Ldarg_0); // Push the expression array

                int index;
                if ((index = expressions.IndexOf(left)) != -1)
                {
                    il.Emit(OpCodes.Ldelem, index);
                }
                else
                {
                    il.Emit(OpCodes.Ldc_I4, expressions.Count);
                    il.Emit(OpCodes.Ldelem, typeof(CompiledExpression)); // Push the left expression
                    expressions.Add(left);
                }

                il.Emit(OpCodes.Call, _evaluateInfo); // Call Calculator.Evaluate(), pushing the result
            }
            else
            {
                // Push the static result of the left side's evaluation
                il.Emit(OpCodes.Ldc_R8, calc.Evaluate(left));
            }
        }
 /// <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>
        /// Evaluates the expression represented by this function using the specified arguments.
        /// </summary>
        /// <param name="localArgs">The arguments used to evaluate the expression. The order of the values in the
        /// array should be the same as those in <see cref="ExplicitArguments"/>.</param>
        /// <param name="calc">The calculator used to evaluate the function.</param>
        /// <returns>The result of the evaluation of the expression this function represents.</returns>
        /// <exception cref="ArgumentException">Thrown when the number of values in <paramref name="localArgs"/>
        /// does not match the number of values in <see cref="ExplicitArguments"/>.</exception>
        public double Evaluate(double[] localArgs, Calculator calc)
        {
            if (localArgs.Length != ExplicitArguments.Count)
            {
                throw new ArgumentException("The size of the arguments must match the size of ExplicitArguments.");
            }

            double[] args = new double[Expression.ArgumentCount];

            // Set all the local arguments
            for (int i = 0; i < localArgs.Length; i++)
            {
                int argIndex = _explicitArgIndices[i];
                if (argIndex == -1)
                {
                    // The argument is not used in the expression
                    continue;
                }

                args[argIndex] = localArgs[i];
            }

            return Expression.Evaluate(args, calc);
        }
 public static double CalculateDerivative(Calculator calc, StandardExpression expr, double x)
 {
     double y;
     return CalculateDerivative(calc, expr, x, out y);
 }
        private static IList<IList<PointD>> GetCompleteLine(Calculator calc, CalculatedLine line)
        {
            var regions = new List<IList<PointD>>();

            double xScale = line.XScale;
            double yScale = line.YScale;

            int segmentIndex = 1;
            int projSegments = line.PointData.Count - 1;
            double pos = line.Window.MinimumX;

            if (Math.Abs(line.PointData[0][0].X / xScale - pos) > 1E-10)
            {
                // There is a void region between the left side of the window and the first segment
                segmentIndex = 0;
                projSegments++;
            }

            for (int i = 0; i < projSegments; i++)
            {
                PointD[] filled = CalculateLine(calc,
                                                line,
                                                line.PointData[segmentIndex][0].X / xScale,
                                                ref pos);

                regions.Add(filled);
                regions.Add(line.PointData[segmentIndex]);

                pos = line.PointData[segmentIndex++].Last().X / xScale + line.Increment;
            }

            IList<PointD> lastSegment = line.PointData.Last();
            if (Math.Abs(line.Window.MaximumX - lastSegment.Last().X / xScale) > 1E-10)
            {
                // There is a void region between the last segment and the right side of the window
                regions.Add(CalculateLine(calc, line, line.Window.MaximumX, ref pos));
            }

            return regions;
        }
        public static ConstructedMatrix Calculate(Calculator calc, CompiledExpression expr, Window3D window, float step)
        {
            float lowZ = float.MaxValue, highZ = float.MinValue;
            List<Vector3> results = new List<Vector3>();
            List<int> startPoints = new List<int>();

            int i = 0;
            for (float x = window.MinimumX; x < window.MaximumX; x += step)
            {
                startPoints.Add(i);
                calc.SetArgument("x", x);

                bool outsideGraph = true;
                Vector3? last = null;
                for (float y = window.MinimumY; y < window.MaximumY; y += step)
                {
                    calc.SetArgument("y", y);

                    float z = (float)calc.Evaluate(expr);

                    Vector3 result = new Vector3(x, y, z);
                    results.Add(result);

                    bool includeResult = false, includeLast = false;
                    if (z > window.MaximumZ || z < window.MinimumZ)
                    {
                        // Outside the window
                        if (!outsideGraph)
                        {
                            // First point outside the window
                            includeResult = true;
                            outsideGraph = true;
                        }
                    }
                    else
                    {
                        // Inside the window
                        if (outsideGraph)
                        {
                            // First point inside the window, include the last vertex as well
                            includeLast = true;
                        }

                        includeResult = true;
                        outsideGraph = false;
                    }

                    if (includeResult)
                    {
                        if (z < lowZ)
                        {
                            lowZ = includeLast && last.HasValue ? Math.Min(z, last.Value.Z) : z;
                        }

                        if (z > highZ)
                        {
                            highZ = includeLast && last.HasValue ? Math.Max(z, last.Value.Z) : z;
                        }
                    }

                    last = result;
                    i++;
                }
            }

            List<int> indices = new List<int>();
            for (int x = 0; x < startPoints.Count - 1; x++)
            {
                int currentX = startPoints[x];
                int nextX = startPoints[x + 1];

                for (int y = 0; y < startPoints[x + 1] - startPoints[x] - 1; y++)
                {
                    indices.AddRange(new[] { currentX + y, nextX + y, nextX + y + 1, currentX + y, nextX + y + 1, currentX + y + 1 });
                }
            }

            int[] colors = new int[results.Count];

            float absLowZ = Math.Abs(lowZ);
            float mulFactor = 255F / (absLowZ + Math.Abs(highZ));

            for (int j = 0; j < results.Count; j++)
            {
                float z = results[j].Z;

                int normalized = Math.Max(0, Math.Min(255, (int)Math.Round((z + absLowZ) * mulFactor)));
                colors[j] = Color.FromArgb(normalized, normalized, normalized).ToArgb();
            }

            return new ConstructedMatrix(results.ToArray(), indices.ToArray(), colors.ToArray());
        }