/// <summary> /// Initializes a new instance of the Function class. /// </summary> /// <param name="identifier">The name of the function. The identifier is the following part of the /// function: "_f_(x[,...])."</param> /// <param name="expression">The expression this function should represent.</param> /// <param name="arguments">The explicit arguments that should be specified whenever this function /// is called. The order of the items in this parameter is the order in which the arguments should /// be specified when calling <see cref="Evaluate"/>.</param> public Function(string identifier, string expression, IList<string> arguments) { Id = _nextId++; Identifier = identifier; // Only optimize the graphing argument if there isn't an explicit argument // with the same identifier _expr = ExpressionCompiler.CompileInfix(expression, !arguments.Any(arg => arg == Calculator.GraphingArgument)); if (arguments.Count == 0) { ExplicitArguments = new ReadOnlyCollection<string>(new List<string>()); return; } // The local indicies of the explicit arguments in the expression's arguments _explicitArgIndices = new int[arguments.Count]; for (int i = 0; i < _explicitArgIndices.Length; i++) { bool found = false; foreach (Argument arg in Expression.Arguments.Where(arg => arg.Identifier == arguments[i])) { _explicitArgIndices[i] = arg.Index; found = true; break; } if (!found) { // The argument is not used in the expression _explicitArgIndices[i] = -1; } } ExplicitArguments = arguments.ToList().AsReadOnly(); }
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> /// Evaluates the specified expression using this instance's arguments and functions. /// </summary> /// <param name="expr">The expression to evaluate.</param> /// <returns>A value that is the result of the evaluation of the specified expression.</returns> public double Evaluate(CompiledExpression expr) { var args = new double[expr.ArgumentCount]; for (int i = 0; i < args.Length; i++) { Argument arg = expr.Arguments[i]; args[i] = GetArgument(arg.Identifier); } return expr.Evaluate(args, this); }
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()); }