PDA

Visualizza la versione completa : [C/C++] Assi Cartesiani


#define NOTHING
27-02-2012, 18:08
Ciao a tutti. Recentemente ho scritto un piccolo programma GUI per Windows in grado di graficare una qualsiasi funzione matematica. L'utente può anche modificare il dominio della funzione e spostare l'origine degli assi. Ora vorrei riuscire a disegnare la griglia numerata di riferimento(vedi immagine). Questa è la funzione che uso per disegnare gli assi,



void assi(HDC console) {
for(register int o = 0; o <= 1500; o++) SetPixelV(console,o,org2,RGB(0,0,0)); /*asse x */
for(register int v = 0; v <= 1000; v++) SetPixelV(console,org,v,RGB(0,0,0)); /*asse y*/
}


dove org2 e org sono i valori modificabili che mi permettono di spostare l'origine.
Per graficare la funzione matematica utilizzo un procedimento simile(SetPixel(...)).
Qualche suggerimento?
Grazie
http://upload.wikimedia.org/wikipedia/commons/4/44/Cartesian_coordinate_system_%28comma%29.svg

oregon
27-02-2012, 19:16
Originariamente inviato da #define NOTHING
Qualche suggerimento?


Ma su cosa?

:confused:

MItaly
27-02-2012, 19:19
Mi sfugge la domanda... :confused: o meglio, ok, vuoi disegnare i numeri e le tacchette... cosa non sai fare/a che punto è che ti blocchi?

Tra parentesi, per disegnare gli assi fai prima ad usare la LineTo, è sicuramente più efficiente che disegnare un pixel alla volta; inoltre, anche per la funzione in genere si usano tratti continui invece che singoli pixel, altrimenti in punti con pendenza elevata non si vede praticamente niente. Infine, register non serve a niente, ti consiglio di toglierla.

#define NOTHING
27-02-2012, 23:27
Ringraziando per le risposte, puntualizzo la mia domanda. Stampato a video il sistema di assi, vorrei aggiungerci una scala graduata indicante i valori principali di riferimento e, possibilmente, una griglia sullo sfondo.
Nello specifico, la funzione incaricata dovrebbe permettere all'utente di impostare la scala. Ho provato con altri sistemi(OpenGL, MFC) senza risultati soddisfacenti.
Es.
3 |
2 |
1 |
0 |____________
0 1 2 3 4 5

Per una dimostrazione più incisiva vi consiglio questo video (http://www.youtube.com/watch?v=JKqZYesk6fY).
P.S. Proverò sicuramente a sostituire SetPixel con LineTo, nonostante sia applicabile soltanto agli assi.

ardito86
28-02-2012, 15:50
Ma tu tieni già conto della scala di riferimento?
No perché, una funzione per essere disegnata bene non deve prevedere una determinata scala, ma una scala che dipende appunto dalla funzione, dalla dispersione dei punti critici della stessa.

Spiega come fai a disegnare la funzione...perché così 1 pixel potrebbe valere 100 come potrebbe valere 10^-8 come potrebbe valere 10^6...insommma :D

#define NOTHING
28-02-2012, 17:54
Per graficare la funzione l'applicativo elabora i singoli valori della funzione nell'intervallo scelto dall'utente e poi li passa uno per uno alla funzione SetPixel.
Ovviamente la scala degli assi dovrebbe adattarsi al codominio.


register double y;
for(register float x = MIN_DOM; x<MAX_DOM; x++){
y = parser(hWnd, x, espressione); //funzione di elaborazione dell'espressione
y = (int) y;
ShowCursor(TRUE);
SetPixelV(console,x+org,y+org2,RGB(100,100,100));
}


P.S. la funzione esterna "parser" effettua le opportune trasformazioni richieste(da gradi a radianti e viceversa).

ardito86
28-02-2012, 19:30
L'intervallo scelto dall'utente è un sottoinsieme del dominio o del codominio?

Allora, se è un sottoinsieme del codominio, e se lavori in una finestra, dividi la larghezza della finestra per la lunghezza dell'intervallo scelto dall'utente. (es. -5, 5 la lunghezza è 10)
Poi fai un ciclo per disegnare le "tacchette"
Es, supponiamo abbia ricavato la larghezza con GetWIndowRect:


int step = width / intervallo;
int
void tacchette(HDC console) {
for (int i=org; i < width ; i = i+step) {
MoveToEx(console, i ,org2 , (LPPOINT) NULL);
LineTo(console, i,org2+5);
}
}


Questo codice dovrebbe disegnare le tacchette nel semiasse positivo delle x (dico dovrebbe perché non l'ho provato).

Ad ogni modo ti ho dato uno spunto

#define NOTHING
28-02-2012, 23:50
Ho provato la soluzione propostami e ho felicemente constatato che, con le opportune modifiche, soddisfa in parte le richieste. Tuttavia, sarebbe interessante aggiungere anche una scala numerica regolabile.

ardito86
29-02-2012, 00:40
Devi variare la variabile "intervallo" quindi ridisegnare tutto.
Io ho fatto esempio per piccole scale, ovvero quando il rapporto width/intervallo è maggiore di 1. A scale grandi, questo rapporto sarà minore di uno e devi trovarti un metodo che invece di fare le tacche a distanza di un'unità (come ho scritto) lo faccia a cinque a cinque, o a dieci a dieci...non so se rendo l'idea.

se noti che step è abbastanza piccolo(minore di 1), allora nel ciclo for modificherai così, per esempio:
for (int i=org; i >= 0; i -= step*5)
in modo che la prima tacca vale 0,k la seconda 5, la terza 10 e così via.

Quanto al semiasse negativo, usa questo:


for (int i=org; i >= 0; i = i-step) {
MoveToEx(console, i ,org2 , (LPPOINT) NULL);
LineTo(console, i,org2+5);
}

#define NOTHING
29-02-2012, 19:08
Ho pensato di inserire nel ciclo un TextOut per stampare la scala numerica.

for (register int i=org; i < width ; i = i+step) {
MoveToEx(console, i, org2, NULL);
LineTo(console, i, org2+4);
TextOut(console, i, org2+6, str, 1); //asse delle ascisse
MoveToEx(console, i, org2, NULL);
LineTo(console, i, org2-4); }

Come posso unire la stringa str con la variabile step/intervallo, in modo tale da permettere all'utente di sfoltire o infittire la griglia?

Loading