Grafico di funzione

di
Anonimizzato10204
il
9 risposte

Grafico di funzione

Ciao a tutti, volevo provare a fare un grafico di funzione in C#, in un textbox scrivo la funzione, ad es. sin(x)+4x e in un pannello disegno il grafico, per il disegno tutto ok, quello che volevo chiedere è se in .Net esiste qualche classe Parser che permette di valutare la funzione passata come stringa? Grazie per l'aiuto.

9 Risposte

  • Re: Grafico di funzione

    Per valuare un' espressione numerica, ci sono vari sistemi, ad esempio puoi ricorrere al Parser inserito nei DataTable.
    
    DataTable table = new DataTable();
    table.Columns.Add(new DataColumn("""", typeof(double), expression));
    table.Rows.Add(0);
    return (double)(table.Rows[0][0]);
    
    È un giochino simpatico ma non credo faccia al caso tuo, tanto per cominciare dovresti sostituire la 'x' della tua funzione con un valore numerico e poi valutarla, poi il parser dell' Sql non gestisce le funzioni trigonometriche ecc.

    Una bella soluzione è quella di ricorrere alla compilazione a run-time, hai un tempo di compilazione iniziale (piccolo) ma poi ti ritrovi con del codice compilato rapidissimo.

    Per tracciare il grafico magari consideri centinaia o migliaia di coordinate x, sicuramente è più efficiente per ogni punto richiamare del codice compilato piuttosto intrpretare una stringa. Però non è quello che chiedevi, se questo tipo di soluzione ti interessa ne parliamo.
  • Re: Grafico di funzione

    Fai un po te, se non è troppo complicato mi interressa.
  • Re: Grafico di funzione

    Non è complicato, sono poche righe di codice, devi aver chiari i concetti di OOP.
    Considera questa interfaccia:
    
    public interface IMyFunction
    {
        double Eval(double x);
    }
    
    Una classe che implementa questa interfaccia può fornire i valori di una specifica funzione, ad esempio:.
    
    public class MyFunction_1: IMyFunction
    {
        public double Eval(double x)
        {
             return Math.Cos(x) * Math.Sin(x);
        }
    }
    
    Ora l' idea è che quando tu hai ottenuto la stringa che descrive la funzione, scrivi proprio questo testo, lo compili, istanzi la classe, e ne richiami il metodo 'Eval' per ogni punto che devi disegnare.
    In tutto sono dieci righe di codice:
    
    private IMyFunction CreateFunction(string text)
    {
        CompilerParameters cp = new CompilerParameters();
        cp.ReferencedAssemblies.Add("system.dll");
        cp.ReferencedAssemblies.Add(GetType().Module.Name);   
    
        string s = "using System;" +
            "class MyFunction:" + GetType().Namespace + ".IMyFunction" +   
            "{ public double Eval(double x) { return " + text + "; }}";
    
        CompilerResults result = new CSharpCodeProvider().CompileAssemblyFromSource(cp, s);
        if (result.Errors.Count != 0)
            return null;
    
        Type type = result.CompiledAssembly.GetType("MyFunction");
        return  (IMyFunction) Activator.CreateInstance(type);
    }
    
    A questo punto basta chiamarla in questo modo:
    
       IMyFunction f = CreateFunction("Math.Cos(x * x)");
       ...
       double y = f.Eval(10);
    
    Ovviamente gli passerai il testo scritto nel TextBox (ricordati di dichiarare IMyFunction).
  • Re: Grafico di funzione

    Funziona! ed è velocissimo. Però non ho capito la CreateFunction me la spieghi?
  • Re: Grafico di funzione

    La funzione 'CreateFunction' fa tre cose 1) crea il testo da compilare, 2) lo compila, 3) istanzia un oggetto e lo te lo restituisce.

    - Il testo da compilare viene messo nella stringa s (è la classe MyFunction di cui abbiamo già parlato).
    - La compilazione avviene richiamando new CSharpCodeProvider().CompileAssemblyFromSource.
    - A questo punto hai un assembly (pensa a una dll) attraverso il quale prima ottieni il tipo della classe da istanziare con CompiledAssembly.GetType e poi la istanzi con Activator.CreateInstance.

    Bye
  • Re: Grafico di funzione

    Ho capito. Quindi posso creare a run-time un sorgente qualsiasi compilarlo e mandarlo in esecuzione?
  • Re: Grafico di funzione

    Risposta seria:
    Si, ad esempio se guardi in rete ci sono diversi programmi che permettono di scrivere degli script in C#. Il funzionamento è semplice, associ l' estensione dei tuoi file al programma, quando questo parte legge lo scritp, lo compila e lo esegue.

    Risposta semi-seria:
    Oppure puoi creare delle classi a run-time in base all' evoluzione del programma. L' idea di creare del codice che crea dell' altro codice è affascinate ed inquietante. Potresti creare comportamenti nuovi e non previsti, del codice che si trasforma ed evolve, insomma dei mostri tipo Skynet.
  • Re: Grafico di funzione

    barba59 ha scritto:


    Risposta seria:
    Si, ad esempio se guardi in rete ci sono diversi programmi che permettono di scrivere degli script in C#. Il funzionamento è semplice, associ l' estensione dei tuoi file al programma, quando questo parte legge lo scritp, lo compila e lo esegue.
    Riesci a farmi un esempio? Se non è una cosa troppo lunga.
  • Re: Grafico di funzione

    Con una classe tipo questa puoi eseguire uno script, alla fine sono poche righe, più using aggiungi più lo script può utilizzare caretteristiche del .NetFramework
    
    class CSharpScript
    {
        private bool HasError(CompilerResults result)
        {
            if (result.Errors.Count > 0)
            {
                StringBuilder sb = new StringBuilder();
                foreach (CompilerError error in result.Errors)
                    sb.AppendLine(error.ErrorText);
    
                MessageBox.Show(sb.ToString());
                return true;
            }
    
            return false;
        }
    
        public void Execute(string text)
        {
            CompilerParameters cp = new CompilerParameters();
            cp.ReferencedAssemblies.Add("System.Data.dll");
            cp.ReferencedAssemblies.Add("System.dll");
            cp.ReferencedAssemblies.Add("System.Drawing.dll");
            cp.ReferencedAssemblies.Add("System.Windows.Forms.dll");
            cp.ReferencedAssemblies.Add("System.Xml.dll");
    
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("using System;");
            sb.AppendLine("using System.Collections.Generic;");
            sb.AppendLine("using System.Diagnostics;");
            sb.AppendLine("using System.Drawing;");
            sb.AppendLine("using System.Data.OleDb;");
            sb.AppendLine("using System.Data;");
            sb.AppendLine("using System.Data.Common;");
            sb.AppendLine("using System.IO;");
            sb.AppendLine("using System.Text;");
            sb.AppendLine("using System.Threading;");
            sb.AppendLine("using System.Windows.Forms;");
            sb.AppendLine("using System.Xml;");
    
            sb.AppendLine("public class MyScript {");
            sb.AppendLine("public void Run() {");
            sb.AppendLine(text);
            sb.AppendLine("}}");
    
            CSharpCodeProvider code = new CSharpCodeProvider();
            CompilerResults result = code.CompileAssemblyFromSource(cp, sb.ToString());
            if (HasError(result))
                return;
    
            Type type = result.CompiledAssembly.GetType("MyScript");
            object obj = Activator.CreateInstance(type);
    
            type.InvokeMember("Run", BindingFlags.InvokeMethod, null, obj, null);
        }
    }
    
    Poi ti puoi fare un programma da associare ad una certa estensione file, leggere il file ed eseguire lo script.
Devi accedere o registrarti per scrivere nel forum
9 risposte