/// <summary>
        /// Parses an atomic production.<para/>
        /// An atomic production can be represented as EBNF like:
        /// <code>&lt;atomic&gt; := [ &lt;literal&gt; ] { &lt;exp&gt; } { &lt;token&gt; { &lt;exp&gt; } }</code><para/>
        /// This means that, in an equation such as <c>y=4x√2</c> the three tokens '4', 'x' and '√2' are correctly broken
        /// down into three separate multiplications. This is so the algebraic multiplication short-hand of omitting the
        /// cross symbol still works. Lastly, this also parses any exponents.
        /// </summary>
        /// <param name="enumerator">An enumerator containing the current location in the Expression of the parser.</param>
        /// <returns>Returns a parse tree node representing this sub-expression in the order it should be evaluated.</returns>
        protected ParseTreeNode ParseAtomic(ParserEnumerator enumerator)
        {
            ParseTreeNode currentNode = null;

            // parse the preceding literal, if there is one
            if (enumerator.Check <DigitToken>())
            {
                currentNode = ParseLiteral(enumerator);
            }
            if (enumerator.Check <ExpToken>())
            {
                if (currentNode != null) // we can't exponentiate a non-existent literal
                {
                    currentNode = new BinaryParseTreeNode(
                        ExpEvaluator,
                        currentNode,
                        ParseExponent(enumerator));
                }
                else
                {
                    throw new ParseException("Expected a valid token before an exponent.", enumerator.Current);
                }
            }

            while (enumerator.Accept <Token>(t => t is IParsable))
            {
                // parse any other successive tokens
                ParseTreeNode currentNodeSubtoken = (enumerator.Current as IParsable).Parse();

                if (enumerator.Check <ExpToken>())
                {
                    currentNodeSubtoken = new BinaryParseTreeNode(
                        ExpEvaluator,
                        currentNodeSubtoken,
                        ParseExponent(enumerator));
                }

                if (currentNode == null)
                {
                    // if the current node is null, create it
                    currentNode = currentNodeSubtoken;
                }
                else
                {
                    // otherwise, multiply the existing current node with the new subnode
                    currentNode = new BinaryParseTreeNode(
                        MultiplyEvaluator,
                        currentNode,
                        currentNodeSubtoken);
                }
            }

            if (currentNode == null)
            {
                throw new ParseException("Expected a valid token.", enumerator.Current);
            }
            return(currentNode);
        }
Esempio n. 2
0
        /// <summary>
        /// Plots this Equation onto the specified <paramref name="graph"/> with the given <paramref name="plotParams"/>.
        /// This method will determine which method of plotting is most appropriate for this equation. This could be the
        /// implicit plotting method for implicit equations, or explicit plotting with respect to one of the two plotted
        /// variables in the graph. Explicit plotting will be attempted wherever possible.
        /// </summary>
        /// <param name="graph">The Graph to plot this IPlottable onto.</param>
        /// <param name="graphics">The GDI+ drawing surface to use for plotting this IPlottable.</param>
        /// <param name="graphSize">The size of the Graph on the screen. This is a property of the display rather than the
        /// graph and is thus not included in the graph's parameters.</param>
        /// <param name="plotParams">The parameters used to plot this IPlottable.</param>
        /// <param name="resolution">The plotting resolution to use. Using a coarser resolution may make the plotting
        /// process faster, and is thus more suitable when the display is being resized or moved.</param>
        public void PlotOnto(Graph graph, Graphics graphics, Size graphSize, PlottableParameters plotParams, PlotResolution resolution)
        {
            if (resolution == PlotResolution.Resize)
            {
                return;
            }
            if (ParseTree == null)
            {
                Parse();
            }
            BinaryParseTreeNode parseTreeRoot = ParseTree as BinaryParseTreeNode;

            var originalSmoothingMode = graphics.SmoothingMode;

            graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; // smoother pen for the graph

            using (Pen graphPen = new Pen(plotParams.PlotColor, EquationPenWidth))
            {
                if (parseTreeRoot.Left is VariableParseTreeNode && // if the only instance of a variable is on the left eg. y=x+1
                    !parseTreeRoot.Right.ContainsVariable((parseTreeRoot.Left as VariableParseTreeNode).Variable))
                {
                    PlotExplicit(
                        graph,
                        graphics,
                        graphSize,
                        graphPen,
                        (parseTreeRoot.Left as VariableParseTreeNode).Variable,
                        parseTreeRoot.Right,
                        resolution);
                }
                else if (parseTreeRoot.Right is VariableParseTreeNode && // if the only instance of a variable is on the right eg. y-1=x
                         !parseTreeRoot.Left.ContainsVariable((parseTreeRoot.Right as VariableParseTreeNode).Variable))
                {
                    PlotExplicit(
                        graph,
                        graphics,
                        graphSize,
                        graphPen,
                        (parseTreeRoot.Right as VariableParseTreeNode).Variable,
                        parseTreeRoot.Left,
                        resolution);
                }
                else // if variables are equated implicitly eg. xy=x+y-x^2
                {
                    PlotImplicit(graph, graphics, graphSize, graphPen, resolution);
                }
            }

            graphics.SmoothingMode = originalSmoothingMode;
        }
Esempio n. 3
0
 /// <summary>
 /// Initialize a new instance of the <c>Graphmatic.Interaction.Equation</c> class from the given expression,
 /// representing an equation that describes this <c>Graphmatic.Interaction.Equation</c>.
 /// </summary>
 public Equation(Expression expression)
     : base()
 {
     Expression = expression;
     if (Expression.Count == 0)
     {
         // create a dummy parse tree equivalent to '0=1'
         // meaning it won't be plotted but it won't throw any exceptions either
         ParseTree =
             new BinaryParseTreeNode(Expression.EqualsEvaluator,
                                     new ConstantParseTreeNode(0),
                                     new ConstantParseTreeNode(1));
     }
     else
     {
         ParseTree = Expression.Parse();
     }
 }
 /// <summary>
 /// Parses a series of <c>ExpToken</c>s, and returns the combined power.
 /// This function takes advantage of the mathematical identity: <c>(a^b)^c=a^(b*c)</c>. Successive <c>ExpToken</c>s
 /// have their powers multiplied together such to return a single power to which to raise the previous expression to.
 /// </summary>
 /// <param name="enumerator">An enumerator containing the current location in the Expression of the parser.</param>
 /// <returns>Returns the power that the token preceding the parsed <c>ExpToken</c>s should be raised to.</returns>
 protected ParseTreeNode ParseExponent(ParserEnumerator enumerator)
 {
     if (enumerator.Accept <ExpToken>())
     {
         ParseTreeNode exponentNode = (enumerator.Current as ExpToken).Power.Parse();
         while (enumerator.Accept <ExpToken>())
         {
             exponentNode = new BinaryParseTreeNode(
                 MultiplyEvaluator,
                 exponentNode,
                 (enumerator.Current as ExpToken).Power.Parse());
         }
         return(exponentNode);
     }
     else
     {
         return(null);
     }
 }
        /// <summary>
        /// Parses a summation production, handling addition and subtraction.
        /// </summary>
        /// <param name="enumerator">An enumerator containing the current location in the Expression of the parser.</param>
        /// <returns>Returns a parse tree node representing this sub-expression in the order it should be evaluated.</returns>
        protected ParseTreeNode ParseSummation(ParserEnumerator enumerator)
        {
            ParseTreeNode currentNode = ParseProduction(enumerator);

            while (enumerator.Accept <OperationToken>(t =>
                                                      t.Operation == OperationToken.OperationType.Add ||
                                                      t.Operation == OperationToken.OperationType.Subtract))
            {
                OperationToken current = enumerator.Current as OperationToken;

                if (current.Operation == OperationToken.OperationType.Add)
                {
                    currentNode = new BinaryParseTreeNode(AddEvaluator, currentNode, ParseProduction(enumerator));
                }
                else if (current.Operation == OperationToken.OperationType.Subtract)
                {
                    currentNode = new BinaryParseTreeNode(SubtractEvaluator, currentNode, ParseProduction(enumerator));
                }
            }
            return(currentNode);
        }
        /// <summary>
        /// Parses a production production (I might have called it that on purpose.)<para/>
        /// Basically, this handles multiplication and division.
        /// </summary>
        /// <param name="enumerator">An enumerator containing the current location in the Expression of the parser.</param>
        /// <returns>Returns a parse tree node representing this sub-expression in the order it should be evaluated.</returns>
        protected ParseTreeNode ParseProduction(ParserEnumerator enumerator)
        {
            ParseTreeNode currentNode = ParseUnary(enumerator);

            while (enumerator.Accept <OperationToken>(t =>
                                                      t.Operation == OperationToken.OperationType.Multiply ||
                                                      t.Operation == OperationToken.OperationType.Divide))
            {
                OperationToken current = enumerator.Current as OperationToken;

                if (current.Operation == OperationToken.OperationType.Multiply)
                {
                    currentNode = new BinaryParseTreeNode(MultiplyEvaluator, currentNode, ParseUnary(enumerator));
                }
                else if (current.Operation == OperationToken.OperationType.Divide)
                {
                    currentNode = new BinaryParseTreeNode(DivideEvaluator, currentNode, ParseUnary(enumerator));
                }
            }
            return(currentNode);
        }