Ir ao conteúdo
  • Cadastre-se

C Gráfico de Função (Allegro4)


Midori

Posts recomendados

Este é um programa simples que fiz para mostrar o gráfico de uma função do primeiro grau e vou postar para quem tiver interesse.

 

A variável fator aumenta/diminui a unidade dos eixos, p.ex no primeiro print está como 10 e no segundo como 5.

 

As teclas para a esquerda/direita diminui/aumenta o valor de A e as para cima/baixo o valor de B.

 

graf1.png.04e54eeae92d195532e098a53229a6bf.png

 

graf2.png.51a925aed995b073c21fa47cca64a623.png

 

 

 

#include <allegro.h>

#define VMAX 10

typedef struct{
    float sx;
    float sy;
    float cx;
    float cy;
    float fator;
    BITMAP *buffer;
}Plano;

void eixos(Plano *);
void atualiza(Plano *);
void coordenadas(Plano *, float, float);

int main(){
    char texto[100];
    Plano P;
    float a = 1.5, b = 3;
    float valores[VMAX] = {6,5,-5,3,1,-5,0,-10,9,-15};

    allegro_init();
    install_keyboard();
    set_color_depth(32);
    set_gfx_mode(GFX_AUTODETECT_WINDOWED,500,500,0,0);
    set_window_title("Grafico");
    P.sx = SCREEN_W;
    P.sy = SCREEN_H;
    P.cx = P.sx/2;
    P.cy = P.sx/2;
    P.fator = 10;

    P.buffer = create_bitmap(P.sx,P.sy);
    clear_bitmap(P.buffer);

    do{
        float ax = 0, ay = 0;
        float bx, by;
        float x, y;
        int i = 0;

        eixos(&P);

        while(i < VMAX){
            x = valores[i];
            y = a * x + b;
            bx = P.cx + x * P.fator;
            by = P.cy - y * P.fator;

            if(key[KEY_LEFT]){a -= 0.01;};
            if(key[KEY_RIGHT]){a += 0.01;};
            if(key[KEY_DOWN]){b -= 0.01;};
            if(key[KEY_UP]){b += 0.01;};

            coordenadas(&P,x,y);		

            if(ax){
                line(P.buffer,ax,ay,bx,by,makecol(255,255,0));
            }
            ax = bx;
            ay = by;			
            i += 1;
        }
        sprintf(texto,"A = %.2f | B = %.2f",a,b);		
        textout_ex(P.buffer,font,"f(x) = a * x + b",
            10,10,makecol(255,165,0),-1);
        textout_ex(P.buffer,font,texto,10,25,makecol(255,165,0),-1);
        textout_ex(P.buffer,font,"y",P.cx-10,0,makecol(0,128,0),-1);
        textout_ex(P.buffer,font,"x",P.sx-10,P.cy+2,makecol(0,128,0),-1);
        atualiza(&P);
    }while(!key[KEY_ESC]);

    destroy_bitmap(P.buffer);
    allegro_exit();
    return 0;
}
END_OF_MAIN();

void eixos(Plano *P){
    int i = P->cx;
    int j = i;
    int cor = makecol(0,128,0);

    line(P->buffer,P->cx,0,P->cx,P->sy,cor);
    line(P->buffer,0,P->cy,P->sx,P->cy,cor);

    while(i){
        line(P->buffer,i,P->cy-2,i,P->cy+2,cor);
        line(P->buffer,j,P->cy-2,j,P->cy+2,cor);
        line(P->buffer,P->cx-2,i,P->cx+2,i,cor);
        line(P->buffer,P->cx-2,j,P->cx+2,j,cor);
        i -= P->fator;
        j += P->fator;
    }
}

void coordenadas(Plano *P, float x, float y){
    char texto[50];
    int cor = makecol(200,200,0);
    int px = P->cx + x * P->fator;
    int py = P->cy - y * P->fator;

    sprintf(texto,"(%.0f,%.0f)",x,y);		
    textout_ex(P->buffer,font,texto,px,py+5,makecol(0,60,0),-1);    
    circlefill(P->buffer,px,py,1.5,cor);

    if(x && y){
        int i;
        if(x > 0){
            for(i = px; i > P->cx ; i -= 2){
                putpixel(P->buffer,i,py,cor);
            }
        }else{
            for(i = px; i < P->cx ; i += 2){
                putpixel(P->buffer,i,py,cor);
            }
        }

        if(y > 0){
            for(i = py; i < P->cy ; i += 2){
                putpixel(P->buffer,px,i,cor);
            }
        }else{
            for(i = py; i > P->cy ; i -= 2){
                putpixel(P->buffer,px,i,cor);
            }
        }
    }
}

void atualiza(Plano *P){
    draw_sprite(screen,P->buffer,0,0);
    clear_bitmap(P->buffer);
}

 

  • Curtir 2
  • Amei 1
Link para o comentário
Compartilhar em outros sites

22 minutos atrás, devair1010 disse:

opa , esse seu código só funciona no Allegr4 ?      tentei usa - lo no Allegro5 e deu muitos erros e não funcionou

é diferente mesmo. Sugeri que @Midorimudasse a versão meses atrás. Se você usa um gerenciador de pacotes por exemplo pode instalar em uma linha só, mas em geral para a versão mais recente. Então é muito mais difícil usar uma versão anterior: tem que compilar tudo, configurar includes e bibliotecas. Muito mais chato. E as versões novas sempre tem mais recursos e mais suporte.

Link para o comentário
Compartilhar em outros sites

@devair1010  Como o @arfneto comentou as versão não são compatíveis, não tenho o 5 instalado.

 

Fiz umas modificações e comecei o gráfico da função do segundo grau, mas ainda não está 100%.

 

Prolonguei a reta da função do primeiro grau.

 

g1.PNG.9a4afc6557a0599c5114b559169f99bb.PNG

 

 

Ainda tenho que corrigir o gráfico da função do segundo grau que sai com uma linha indevida em alguns casos.

 

g3.PNG.a40d9d1d2a8f8f9944fe6dc6de77f3ee.PNG

 

g2.PNG.c1ae1d7b7919a3b1423914998733a250.PNG

 

Nesse tipo de gráfico usei um loop interno para pegar números intermediários entre os valores do vetor de x para fazer a curva e não ficar uma linha reta. Talvez não seja a melhor forma, alguém tem uma sugestão de como melhorar essa função?

 

#include <allegro.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>

#define VMAX 7

#define COR_EIXOS 0x008000
#define COR_LINHA 0xc8c800
#define COR_TEXTO 0x1b3d1b
#define COR_TEXTO2 0xad720a

typedef struct{
    float raiz1;
    float raiz2;
    float vertx;
    float verty;
    float delta;
}EQsgrau;

typedef struct{
    int sx;
    int sy;
    int cx;
    int cy;
    int fator;
    BITMAP *buffer;
}Plano;

void eixos(Plano *P);
void atualiza(Plano *P);
void coordenadas(Plano *P, float x, float y, int mlinhas, int mpontos);
void pgrau(Plano *P, float a, float *x, float b);
void sgrau(Plano *P, float a, float *x, float b, float c);
Plano *inicia(int sx, int sy, int fator, int tela_cheia);
EQsgrau *eq2(float a, float b, float c);

int main(){
    Plano *plano = inicia(400,400,15,FALSE);
    EQsgrau *eq = NULL;
    float valores[VMAX] = {1,3,5,4.5,-2,6,-3};
    float a = -1.5;
    float b = -2;
    float c = -3;

    eixos(plano);
    pgrau(plano, a, valores, b);
    textprintf_ex(
        plano->buffer,font,10,10,
        COR_TEXTO2, -1,"A = %.2f | B = %.2f", a, b);
    /*
    sgrau(plano, a, valores, b, c);
    eq = eq2(a, b, c);
    if(eq != NULL){
        textprintf_ex(
            plano->buffer,font,10,10,
            COR_TEXTO2, -1,"DELTA = %.2f", 
            eq->delta);
        textprintf_ex(
            plano->buffer,font,10,21,
            COR_TEXTO2, -1,"VERTICE (%.2f,%.2f)", 
            eq->vertx, eq->verty);
        textprintf_ex(
            plano->buffer,font,10,31,
            COR_TEXTO2, -1,"R1 = %.2f | R2 = %.2f", 
            eq->raiz1, eq->raiz2);
    }
    */
    atualiza(plano);

    do{
        /* ... */
    }while(!key[KEY_ESC]);

    destroy_bitmap(plano->buffer);
    if(eq != NULL){free(eq);}
    free(plano);
    allegro_exit();
    return 0;
}
END_OF_MAIN();

void eixos(Plano *P){
    int i = P->cx;
    int j = i;

    line(P->buffer, P->cx, 0, P->cx, P->sy, COR_EIXOS);
    line(P->buffer, 0, P->cy, P->sx, P->cy, COR_EIXOS);

    while(i > 0){
        line(P->buffer, i, P->cy - 2, i, P->cy + 2, COR_EIXOS);
        line(P->buffer, j, P->cy - 2, j, P->cy + 2, COR_EIXOS);
        line(P->buffer, P->cx - 2, i, P->cx + 2, i, COR_EIXOS);
        line(P->buffer, P->cx - 2, j, P->cx + 2, j, COR_EIXOS);
        i -= P->fator;
        j += P->fator;
    }
    textout_ex(P->buffer, font, "y", P->cx - 10, 0, COR_EIXOS, -1);
    textout_ex(P->buffer, font, "x", P->sx - 10, P->cy + 3, COR_EIXOS, -1);
}

void coordenadas(Plano *P, float x, float y, int mlinhas, int mpontos){
    int px = P->cx + x * P->fator;
    int py = P->cy - y * P->fator;

    if(mpontos == TRUE){
        circlefill(P->buffer,px + 2,py + 2, 2, COR_LINHA);
        if(mlinhas == TRUE){
            textprintf_ex(P->buffer,font,px,py,COR_TEXTO,-1,"(%.0f,%.0f)",x,y);
        }
    }

    if(x && y && mlinhas == TRUE){
        int i;
        if(x > 0){
            for(i = px; i > P->cx ; i -= 2){
                putpixel(P->buffer, i, py, COR_LINHA);
            }
        }else{
            for(i = px; i < P->cx ; i += 2){
                putpixel(P->buffer, i, py, COR_LINHA);
            }
        }

        if(y > 0){
            for(i = py; i < P->cy ; i += 2){
                putpixel(P->buffer, px, i, COR_LINHA);
            }
        }else{
            for(i = py; i > P->cy ; i -= 2){
                putpixel(P->buffer, px, i, COR_LINHA);
            }
        }
    }
}

void atualiza(Plano *P){
    draw_sprite(screen, P->buffer, 0, 0);
    clear_bitmap(P->buffer);
}

Plano *inicia(int sx, int sy, int fator, int tela_cheia){
    Plano *plano = (Plano *)malloc(sizeof(Plano));
    int tela = GFX_AUTODETECT_WINDOWED;

    if(tela_cheia == TRUE){
        tela = GFX_AUTODETECT_FULLSCREEN;
    }

    allegro_init();
    install_keyboard();
    set_color_depth(32);
    set_gfx_mode(tela, sx, sy, 0, 0);
    set_window_title("Grafico");
    
    plano->sx = SCREEN_W;
    plano->sy = SCREEN_H;
    plano->cx = plano->sx/2;
    plano->cy = plano->sy/2;
    plano->buffer = create_bitmap(plano->sx, plano->sy);
    plano->fator = fator;
    
    clear_bitmap(plano->buffer);
    
    return plano;
}

void pgrau(Plano *P, float a, float *x, float b){
    float ax;
    float ay;
    int i = 0;
    
    while(i < VMAX){
        float y = a * x[i] + b;
        if(i == 0){
            ax = P->cx + x[i] * P->fator;
            ay = P->cy - y * P->fator;
        }
        coordenadas(P, x[i], y, TRUE, TRUE);
        i += 1;
    }

    line(P->buffer, ax, ay, 
        P->cx + P->sy * P->fator, 
        P->cy - (a * P->sy + b) * P->fator, 
        COR_LINHA
    );

    line(P->buffer, ax, ay,
        P->cx + -P->sy * P->fator,
        P->cy - (a * -P->sy + b) * P->fator,
        COR_LINHA
    );
}

EQsgrau *eq2(float a, float b, float c){
    EQsgrau *eq;
    float delta = (b * b) - 4 * a * c;

    if(delta < 0){
        return NULL;
    }
    eq = (EQsgrau *)malloc(sizeof(EQsgrau));
    eq->delta = delta;
    eq->raiz1 = eq->raiz2 = (-b + sqrt(delta))/(2 * a);
    eq->vertx = -b/(2 * a);
    eq->verty = -delta/(4 * a);
    if(delta == 0){
        return eq;
    }
    eq->raiz2 = (-b - sqrt(delta))/(2 * a);
	
    return eq;
}

void sgrau(Plano *P, float a, float *x, float b, float c){
    float ax;
    float ay;
    int i = 0;
	
    while(i < VMAX - 1){
        float nx = x[i];
        while(nx < x[i + 1]){
            float y = a * (nx * nx) + b * nx + c;
            float bx = P->cx + nx * P->fator;
            float by = P->cy - y * P->fator;

            coordenadas(P, nx, y, FALSE, -(nx == x[i]));			
            line(P->buffer, ax, ay, bx, by, COR_LINHA);
			
            ax = bx;
            ay = by;
            nx += 0.1;
        }
        i += 1;
    }
}

 

Link para o comentário
Compartilhar em outros sites

33 minutos atrás, Midori disse:

Nesse tipo de gráfico usei um loop interno para pegar números intermediários entre os valores do vetor de x para fazer a curva e não ficar uma linha reta. Talvez não seja a melhor forma, alguém tem uma sugestão de como melhorar essa função

 

Use interpolação. A partir do intervalo inicial e final defina o número de pontos e coloque na "tela" um por um. 

Para usar a versão 5 em Visual studio usando vcpkg:
 


C:\bin\vcpkg>vcpkg install allegro5
Computing installation plan...
The following packages are already installed:
    allegro5[core]:x86-windows
Package allegro5:x86-windows is already installed

Total elapsed time: 1.476 ms


C:\bin\vcpkg>

 

Nessa máquina em particular já está instalado. Mas todo o processo seria esse aí: uma linha. E o pessoal que mantem o pacote allegro claro que cuida de manter isso funcionando. A partir daí qualquer programa pode usar allegro, basta usar os #include e gerar o programa. Não precisa de nenhum tipo de configuração. 

 

Por isso disse que é complicado usar uma versão para a qual não tenha suporte. Pode ter que compilar TUDO. E configurar os include, as lib, DLL, um inferno.

 

Em geral se usa isso quando tem um pacote que foi escrito já para a versão anterior

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Adaptei o programa para o Allegro 5 para quem quiser testar nessa versão.

 

Para mostrar os textos coloquei o arquivo ttf (neste caso o DejaVuSans.ttf) no diretório do executável.

 

Usei o g++ para compilar via linha de comando:

g++ graficos.c `pkg-config --cflags --libs allegro-5` -lallegro_primitives -lallegro_ttf -lallegro_font

 

 

#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include <stdlib.h>
#include <math.h>

#define VMAX 7
#define TRUE 1
#define FALSE 0
#define COR_EIXOS al_map_rgb(0,255,0)
#define COR_LINHA al_map_rgb(255,255,0)
#define COR_TEXTO al_map_rgb(0,128,64)
#define COR_TEXTO2 al_map_rgb(255,128,0)

typedef struct{
    float raiz1;
    float raiz2;
    float vertx;
    float verty;
    float delta;
}EQsgrau;

typedef struct{
    ALLEGRO_EVENT_QUEUE *evq;
    ALLEGRO_EVENT ev;
}Evento;

typedef struct{
    int sx;
    int sy;
    int cx;
    int cy;
    int fator;
    ALLEGRO_DISPLAY *display;
    ALLEGRO_FONT *fonte;
    Evento evento;
}Plano;

void eixos(Plano *P);
void coordenadas(Plano *P, float x, float y, int mlinhas, int mpontos);
void pgrau(Plano *P, float a, float *x, float b);
void sgrau(Plano *P, float a, float *x, float b, float c);
Plano *inicia(int sx, int sy, int fator, int tela_cheia);
EQsgrau *eq2(float a, float b, float c);

int main(){
    Plano *plano = inicia(500,500,15,FALSE);
    EQsgrau *eq = NULL;
    float valores[VMAX] = {1,3,5,4.5,-2,6,-3};
    float a = 1.5;
    float b = -2;
    float c = -3;

    eixos(plano);
    pgrau(plano, a, valores, b);
/*    
    sgrau(plano, a, valores, b, c);
    eq = eq2(a, b, c);
*/
    if(plano->fonte){
        al_draw_textf(plano->fonte,
            COR_TEXTO2, 10, 10, 0, "A = %.2f | B = %.2f", a, b);
    	/*
        if(eq != NULL){
            al_draw_textf(plano->fonte, 
                COR_TEXTO2, 10, 25, 0, "DELTA = %.2f", eq->delta);
            al_draw_textf(plano->fonte,
                COR_TEXTO2, 10, 35, 0, "VERTICE (%.2f,%.2f)", eq->vertx, eq->verty);
            al_draw_textf(plano->fonte, COR_TEXTO2,
                10, 45, 0, "R1 = %.2f | R2 = %.2f", eq->raiz1, eq->raiz2);
        }
    	*/
    }
    al_flip_display();

    do{
        al_wait_for_event(
            plano->evento.evq, &plano->evento.ev
        );
    }while(!plano->evento.ev.type);
    
    if(eq != NULL){free(eq);}
    al_destroy_display(plano->display);
    free(plano);
    return 0;
}

void eixos(Plano *P){
    int i = P->cx;
    int j = i;

    al_draw_line(P->cx, 0, P->cx, P->sy, COR_EIXOS, 1);
    al_draw_line(0, P->cy, P->sx, P->cy, COR_EIXOS, 1);

    while(i > 0){
        al_draw_line(i, P->cy - 2, i, P->cy + 2, COR_EIXOS, 1);
        al_draw_line(j, P->cy - 2, j, P->cy + 2, COR_EIXOS, 1);
        al_draw_line(P->cx - 2, i, P->cx + 2, i, COR_EIXOS, 1);
        al_draw_line(P->cx - 2, j, P->cx + 2, j, COR_EIXOS, 1);
        i -= P->fator;
        j += P->fator;
    }
    
    if(P->fonte){
        al_draw_text(P->fonte, COR_EIXOS, P->cx - 10, 0, 0, "y");
        al_draw_text(P->fonte, COR_EIXOS, P->sx - 10, P->cy + 3, 0, "x");
    }
}

void coordenadas(Plano *P, float x, float y, int mlinhas, int mpontos){
    int px = P->cx + x * P->fator;
    int py = P->cy - y * P->fator;

    if(mpontos == TRUE){
        al_draw_filled_circle(px + 2, py + 2, 2, COR_LINHA);
        if(mlinhas == TRUE){
            if(P->fonte){
                al_draw_textf(P->fonte, COR_TEXTO, px, py, 0, "(%.0f,%.0f)", x, y);
            }
        }
    }

    if(x && y && mlinhas == TRUE){
        int i;
        if(x > 0){
            for(i = px; i > P->cx ; i -= 2){
                al_draw_pixel(i, py, COR_LINHA);
            }
        }else{
            for(i = px; i < P->cx ; i += 2){
                al_draw_pixel(i, py, COR_LINHA);
            }
        }

        if(y > 0){
            for(i = py; i < P->cy ; i += 2){
                al_draw_pixel(px, i, COR_LINHA);
            }
        }else{
            for(i = py; i > P->cy ; i -= 2){
                al_draw_pixel(px, i, COR_LINHA);
            }
        }
    }
}

Plano *inicia(int sx, int sy, int fator, int tela_cheia){
    Plano *plano = (Plano *)malloc(sizeof(Plano));
    int tela = ALLEGRO_WINDOWED;
	
    if(tela_cheia == TRUE){
        tela = ALLEGRO_FULLSCREEN;
    }
	
    al_init();
    al_install_keyboard();
    al_init_font_addon();
    al_init_ttf_addon();
    al_set_new_display_flags(tela);
    plano->display = al_create_display(sx, sy);
    al_set_window_title(plano->display,"Graficos");	
    al_init_primitives_addon();

    plano->evento.evq = al_create_event_queue();

    al_register_event_source(
        plano->evento.evq, al_get_keyboard_event_source()
    );

    plano->fonte = al_load_font("DejaVuSans.ttf", 12, 0);
    plano->sx = sx;
    plano->sy = sy;
    plano->cx = plano->sx/2;
    plano->cy = plano->sy/2;
    plano->fator = fator;
    
    return plano;
}

void pgrau(Plano *P, float a, float *x, float b){
    float ax;
    float ay;
    int i = 0;
    
    while(i < VMAX){
        float y = a * x[i] + b;
        if(i == 0){
            ax = P->cx + x[i] * P->fator;
            ay = P->cy - y * P->fator;
        }
        coordenadas(P, x[i], y, TRUE, TRUE);
        i += 1;
    }

    al_draw_line(ax, ay, 
        P->cx + P->sy * P->fator, 
        P->cy - (a * P->sy + b) * P->fator, 
        COR_LINHA, 1
    );

    al_draw_line(ax, ay,
        P->cx + -P->sy * P->fator,
        P->cy - (a * -P->sy + b) * P->fator,
        COR_LINHA, 1
    );
}

EQsgrau *eq2(float a, float b, float c){
    EQsgrau *eq;
    float delta = (b * b) - 4 * a * c;

    if(delta < 0){
        return NULL;
    }	
    eq = (EQsgrau *)malloc(sizeof(EQsgrau));
    eq->delta = delta;
    eq->raiz1 = eq->raiz2 = (-b + sqrt(delta))/(2 * a);
    eq->vertx = -b/(2 * a);
    eq->verty = -delta/(4 * a);
    if(delta == 0){
        return eq;
    }
    eq->raiz2 = (-b - sqrt(delta))/(2 * a);
	
    return eq;
}

void sgrau(Plano *P, float a, float *x, float b, float c){
    float ax;
    float ay;
    int i = 0;
	
    while(i < VMAX - 1){
        float nx = x[i];
        while(nx < x[i + 1]){
            float y = a * (nx * nx) + b * nx + c;
            float bx = P->cx + nx * P->fator;
            float by = P->cy - y * P->fator;

            coordenadas(P, nx, y, FALSE, nx == x[i]);			
            al_draw_line(ax, ay, bx, by, COR_LINHA, 1);
			
            ax = bx;
            ay = by;
            nx += 0.1;
        }
        i += 1;
    }
}

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...