using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UnitsNet; using UnitsNet.Units; using NCalc; using System.Text.RegularExpressions; using System.Reflection; namespace CaeGlobals { public static class MyNCalc { // Variables public static OrderedDictionary ExistingParameters = null; // Methods static public double ConvertFromString(string valueString, Func ConvertToCurrentUnits) { double valueDouble; valueString = valueString.Trim(); // if (valueString.Length == 0 || valueString == "=") return 0; // empty string -> 0 if (!double.TryParse(valueString, out valueDouble)) { if (valueString.StartsWith("=")) { valueString = valueString.Substring(1, valueString.Length - 1); valueString = PreprocessExpression(valueString); //List parameters = GetParameters(valueString); Expression e = GetExpression(valueString); if (!e.HasErrors()) { object result = e.Evaluate(); if (result is bool bl) valueDouble = bl ? 1 : 0; else if (result is byte byt) valueDouble = byt; else if (result is decimal dec) valueDouble = (double)dec; else if (result is int i) valueDouble = i; else if (result is float f) valueDouble = f; else if (result is double d) valueDouble = d; else { double.TryParse(result.ToString(), out valueDouble); } } else { throw new CaeException("Equation error:" + Environment.NewLine + e.Error); } } else valueDouble = ConvertToCurrentUnits(valueString); } // return valueDouble; } static public double SolveEquation(string valueString) { double valueDouble; valueString = valueString.Trim(); // if (valueString.Length == 0 || valueString == "=") return 0; // empty string -> 0 if (!double.TryParse(valueString, out valueDouble)) { if (valueString.StartsWith("=")) { valueString = valueString.Substring(1, valueString.Length - 1); valueString = PreprocessExpression(valueString); //List parameters = GetParameters(valueString); Expression e = GetExpression(valueString); if (!e.HasErrors()) { object result = e.Evaluate(); if (result is bool bl) valueDouble = bl ? 1 : 0; else if (result is byte byt) valueDouble = byt; else if (result is decimal dec) valueDouble = (double)dec; else if (result is int i) valueDouble = i; else if (result is float f) valueDouble = f; else if (result is double d) valueDouble = d; else { double.TryParse(result.ToString(), out valueDouble); } } else { throw new CaeException("Equation error:" + Environment.NewLine + e.Error); } } else throw new CaeException("Equation error:" + Environment.NewLine + "Equation must start with = sign."); } // return valueDouble; } static public double[] SolveArrayEquation(string equation) { double[] values; string scalarEquation = equation; equation = equation.Trim(); // if (equation.Length == 0 || equation == "=") throw new CaeException("Equation error:" + Environment.NewLine + "Equation cannot be evaluated."); // if (equation.StartsWith("=")) { equation = equation.Substring(1, equation.Length - 1); equation = PreprocessExpression(equation); // Expression e = GetArrayExpression(equation); if (!e.HasErrors()) { object result = e.Evaluate(); if (result is List list) { // Array equation if (list.Count > 0) { int count = 0; values = new double[list.Count]; foreach (var obj in list) { if (obj is bool bl) values[count++] = bl ? 1 : 0; else if (obj is byte byt) values[count++] = byt; else if (obj is decimal dec) values[count++] = (double)dec; else if (obj is int i) values[count++] = i; else if (obj is float f) values[count++] = f; else if (obj is double d) values[count++] = d; else count++; } } // Scalar equation else { double value = ConvertFromString(scalarEquation, null); return new double[] { value }; } } else { throw new CaeException("Equation error:" + Environment.NewLine + "Equation return type unrecognized."); } } else { throw new CaeException("Equation error:" + Environment.NewLine + e.Error); } } else throw new CaeException("Equation error:" + Environment.NewLine + "Equation must start with = sign."); // return values; } static public bool HasErrors(string equation, out HashSet parameterNames) { double valueDouble; parameterNames = null; // equation = equation.Trim(); // if (equation.Length == 0 || equation == "=") return false; if (!double.TryParse(equation, out valueDouble)) { if (equation.StartsWith("=")) { equation = equation.Substring(1, equation.Length - 1); equation = PreprocessExpression(equation); Expression e = GetExpression(equation); parameterNames = GetParameters(equation); // if (!e.HasErrors()) { object result = e.Evaluate(); } return e.HasErrors(); } else return false; } // return false; } static public Expression GetExpression(string expression) { Expression e = new Expression(expression, EvaluateOptions.IgnoreCase); // Add constants e.Parameters.Add("pi", Math.PI); e.Parameters.Add("Pi", Math.PI); // if (ExistingParameters != null) { foreach (var entry in ExistingParameters) e.Parameters.Add(entry.Key, entry.Value); } return e; } // static public Expression GetArrayExpression(string expression) { Expression e = new Expression(expression, EvaluateOptions.IgnoreCase | EvaluateOptions.IterateParameters); // Add constants e.Parameters.Add("pi", Math.PI); e.Parameters.Add("Pi", Math.PI); // if (ExistingParameters != null) { foreach (var entry in ExistingParameters) e.Parameters.Add(entry.Key, entry.Value); } return e; } static public HashSet GetParameters(string expression) { HashSet parameters = new HashSet(); Expression e = new Expression(expression); // e.EvaluateFunction += delegate (string name, FunctionArgs args) { args.EvaluateParameters(); args.Result = 0; }; e.EvaluateParameter += delegate (string name, ParameterArgs args) { parameters.Add(name); args.Result = 0; }; try { e.Evaluate(); } catch { } return parameters; } // static public string PreprocessExpression(string expr) { // Sort parameter names by length (longest first) var sortedNames = ExistingParameters.Keys .OrderByDescending(name => name.Length) .ToList(); // Step 1: Replace each parameter with a unique placeholder int count = 0; string placeholder; string bracketedParam; Dictionary placeholders = new Dictionary(); // foreach (var param in sortedNames) { // Create a unique placeholder placeholder = $"@{count++}@"; bracketedParam = $"[{param}]"; // Replace all instances of the parameter with the placeholder if (expr.Contains(bracketedParam)) { expr = expr.Replace(bracketedParam, placeholder); // Store the mapping between placeholder and actual parameter placeholders[placeholder] = param; } else if (expr.Contains(param)) { expr = expr.Replace(param, placeholder); // Store the mapping between placeholder and actual parameter placeholders[placeholder] = param; } } // Step 2: Replace the placeholders with the bracketed parameter names string bracketed; foreach (var entry in placeholders) { bracketed = $"[{entry.Value}]"; expr = expr.Replace(entry.Key, bracketed); } // return expr; } static public string[] GetReservedParameterNames() { return new string[] { "Pi", "pi", "x", "y", "z" }; } // static public string[] GetFunctionConstants() { return new string[] { "Pi" }; } static public string[] GetFunctionSnippets() { return new string[] { "Abs(^)", "Acos(^)", "Asin(^)", "Atan(^)", "Ceiling(^)", "Cos(^)", "Exp(^)", "Floor(^)", "IEEERemainder(^, )", "Ln(^)", "Log(^, )", "Log10(^)", "Max(^, )", "Min(^, )", "Pow(^, )", "Round(^, )", "Sign(^)", "Sin(^)", "Sqrt(^)", "Tan(^)", "Truncate(^)", "If(^, , )" }; } } }