Visualizzazione dei risultati da 1 a 8 su 8
  1. #1
    Utente di HTML.it
    Registrato dal
    Feb 2011
    Messaggi
    156

    [C++/QT] plottare funzione (parsing)

    sto creando un programma in qt per disegnare una funzione inserita dall'utente.
    Ho già creato un parser abbastanza completo (ho aggiunto anche funzioni goniometriche ed algoritmi) che mi permetta di interpretare la funzione inserita dall'utente IN FORMA ESPLICITA (ma sto pensando ad un modo per trasformare una funzione implicita in forma esplicita) e raccogliere un numero sufficiente di punti. Ho pero dei dubbi:

    1: per l'appunto il programma riconosce solo le funzioni, mentre non può disegnare ad esempio grafici di ellissi o circonferenze. come potrei procedere per implementare questa possibilità?

    2: cosa che mi preme di più: disegnare per l'appunto il grafico. ho visto diversi tutorial su Qpainter come questo http://www.youtube.com/watch?v=5JE5ek_oN_0 ma inanzi tutto utilizzano tutti come classe base dialog ed invece vorrei usare QMainWindow, è possibile?
    e poi vorrei limitare la zona dedicata al disegno solo ad una porzione, per dedicare il resto della finestra a textbox e pulsanti vari

  2. #2

    Re: [C++/QT] plottare funzione (parsing)

    Originariamente inviato da Rising1
    1: per l'appunto il programma riconosce solo le funzioni, mentre non può disegnare ad esempio grafici di ellissi o circonferenze. come potrei procedere per implementare questa possibilità?
    Invece di imporre di usare la forma cartesiana y=f(x) (in cui il grafico della funzione è {(x, f(x)) ∀ x ∈ D}, D dominio di x), lascia che l'utente possa fornire la curva in forma parametrica (x, y) = f(t) = (f1(t), f2(t)) (quindi, il grafico è {(f1(t), f2(t)) ∀ t ∈ A}, A dominio di t).
    In questa maniera diventa possibile disegnare ogni curva - ad esempio, la circonferenza di raggio 7 centrata in (2, 5) è

    f1(t) = 7cos(t) + 2
    f2(t) = 7sin(t) + 5
    con t ∈ [0, 2π )

    e i grafici cartesiani sono semplicemente un caso speciale (con f1(t)=t e f2(t)=f(t)).
    2: cosa che mi preme di più: disegnare per l'appunto il grafico. ho visto diversi tutorial su Qpainter come questo http://www.youtube.com/watch?v=5JE5ek_oN_0 ma inanzi tutto utilizzano tutti come classe base dialog ed invece vorrei usare QMainWindow, è possibile?
    e poi vorrei limitare la zona dedicata al disegno solo ad una porzione, per dedicare il resto della finestra a textbox e pulsanti vari
    Dimenticati i tutorial video e studiati documentazione ed esempi delle Qt. Per il resto, puoi tranquillamente disegnare ad esempio dentro un QFrame (basta scrivere una classe che derivi da esso e reimplementarne il metodo paintEvent).
    Amaro C++, il gusto pieno dell'undefined behavior.

  3. #3
    Utente di HTML.it
    Registrato dal
    Feb 2011
    Messaggi
    156
    ok grazie della risposta.
    ho incominciato a fare un po' di pratica con Qpainter, l'unica vera scomodità è che può disegnare su un widget solo se si trova all'interno di paintEvent...

    per quanto riguarda le funzioni parametriche in effetti è un buon compromesso. Programmi come, che so, Derive per disegnare grafici del genere a partire dall'equazione "canonica" (tipo x^2/4+y^2/9=1 per le ellissi) implementano qualche particolare algoritmo? perchè io avevo pensato ad un modo: memorizzare per ogni token il suo esponente e ciclare sul vettore dove sono contenuti tutti i token finchè tutti gli esponenti non sono naturali (detto a parole povere). dunque riordinare affinchè sia in forma esplicita. ma qualora ci sono radici c'è un problema con i segni
    y^2=x ----> y=(+ o -)sqrt(x)

  4. #4
    Originariamente inviato da Rising1
    ok grazie della risposta.
    ho incominciato a fare un po' di pratica con Qpainter, l'unica vera scomodità è che può disegnare su un widget solo se si trova all'interno di paintEvent...
    Si può disegnare su un widget anche al di fuori di un paintEvent, ma è una pessima idea, visto che al ridisegno successivo sparirebbe tutto. Semmai nel tuo caso può aver senso disegnare in una bitmap in memoria al momento di cambiare la funzione e nei paintEvent limitarti a copiare il contenuto della bitmap sul widget.
    Programmi come, che so, Derive per disegnare grafici del genere a partire dall'equazione "canonica" (tipo x^2/4+y^2/9=1 per le ellissi) implementano qualche particolare algoritmo?
    In genere si usano metodi numerici; un metodo semplice è partire dal segno della funzione implicita su punti "campionati" sul piano per poi usare il metodo di Newton. Qui trovi un articoletto sulla questione - è vecchio e relativo al BASIC, ma mi pare che spieghi in maniera semplice e chiara l'algoritmo di base.
    perchè io avevo pensato ad un modo: memorizzare per ogni token il suo esponente e ciclare sul vettore dove sono contenuti tutti i token finchè tutti gli esponenti non sono naturali (detto a parole povere). dunque riordinare affinchè sia in forma esplicita. ma qualora ci sono radici c'è un problema con i segni
    y^2=x ----> y=(+ o -)sqrt(x)
    Fai prima con metodi numerici, se vuoi rimaneggiare l'equazione in forma analitica inizi a servirti un pacchetto tipo CAS. Ma soprattutto, funzioni implicite anche relativamente semplici in genere non si riescono a girare in forma esplicita analitica: prova a girare in forma esplicita questa roba - non è un caso che anche "a mano" si risolvano usando metodi particolari.
    Amaro C++, il gusto pieno dell'undefined behavior.

  5. #5
    Utente di HTML.it
    Registrato dal
    Feb 2011
    Messaggi
    156
    Originariamente inviato da MItaly


    In genere si usano metodi numerici; un metodo semplice è partire dal segno della funzione implicita su punti "campionati" sul piano per poi usare il metodo di Newton.
    Qui trovi un articoletto sulla questione - è vecchio e relativo al BASIC, ma mi pare che spieghi in maniera semplice e chiara l'algoritmo di base.
    lo definirei... illuminante!! Davvero praticamente con un post hai risposto a numerose domande che mi tenevo in serbo ma che prima o poi avrei fatto. Ovviamente implementerò questo metodo che mi sembra più completo, ora mi rimane qualche dubbio riguardo la rappresentazione di intervalli "con la virgola" sullo schermo (esempio, trovare una scala per stampare abbastanza proporzionalmente i punti (1,5 ; 1,4) e (2,55 ; 6,77) )

  6. #6
    Utente di HTML.it
    Registrato dal
    Feb 2011
    Messaggi
    156
    mi dispiace se riprendo questa discussione dopo un po', ma non ho avuto molto tempo.

    MItaly per quanto riguarda il documento che hai messo ho capito bene il metodo delle tangenti di newton, e anche la logica di fondo, ma a partire da pagina 7 non capisco bene:

    dunque io ho provato a fare un programma che segue quest'algoritmo (che in alcuni casi funziona, in altri no)

    codice:
    considero il grafico tridimensionale della funzione z(x,y)=funzione implicita e considero il piano orizzontale passante per l'origine.
    a questo punto ciclo sulla y (for(y=-100;y<=100;y+=intervallo))
    
    x=-100
    mentre la x  è minore di 100:
    {
    se z(x,y)>0  trovo con il metodo delle tangnti il punto esatto, dunque scorro x finchè z(x,y)>0 (di nuovo) o x>100
    
    se z(x,y)<0 scorro fino a che z(x,y)>0 o x>100
    
    se (x,y) è una soluzione la memorizzo ed incremento x
    }
    anche se a livello logico mi puzza di bruciato. Sapresti indicarmi dove sbaglio? anche perchè ho cercato come un matto guide più chiare (e magari in un linguaggio più moderno) ma non ho trovato un bel niente

  7. #7
    Mah l'idea dovrebbe essere è quella... tu per ogni colonna ti vai a cercare tutti gli zeri della funzione, ovvero trovi i punti in cui la restrizione della tua F alla colonna (=fissi x, fai variare y) cambia segno, e lì vai a lavorare di precisione con il metodo di Newton.
    Amaro C++, il gusto pieno dell'undefined behavior.

  8. #8
    Utente di HTML.it
    Registrato dal
    Feb 2011
    Messaggi
    156
    ecco il codice:

    codice:
    //z(double,double) è la funzione implicita
    //g(double,double) ritorna (z(x+0.001,y)-z(x,y))/0.001;
    
    int main()
    {
    
        for (double Y=0.003;Y<=1;Y+=0.001)
            {
                double x=-1;
                while (x<=1)
                {
                    if (z(x,Y)>0)
                        {
                            double tm=x; //tm è il valore di x che poi verrà approssimato con il metodo delle tangenti all'ascissa del punto sul grafico
                             for (int i=0;i<10;i++) tm=tm-z(tm,Y)/g(tm,Y);
                            cout<<Y<<" "<<tm<<endl; //stampo il punto
                            while((z(x,Y)>0)&&(x<=1)) x+=0.01;
                        }
    
                    else if (z(x,Y)<0) while(z(x,Y)<0) x+=0.01;
                    else {cout<<Y<<" "<<x<<endl; x+=0.01;}
                }
    
                 getchar();
            }
    }
    per alcune funzioni (come la circonferenza) funziona alla perfezione, per altre (come una qualsiasi parabola) entra in loop in prossimità del ciclo while (x<=1)

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.