• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

orium

[C++] Desenho geométrico

1 mensagem neste tópico

Codigo que escrevi no verao passado, desenha algumas figuras geometrias (circunferencias e rectangulos), linhas (suporta cores). Grava as imagens como bmp ou xmb ou faz mostra-as com o openGL.

Isto foi escrito quando eu estava no 1º cap do "Programação com classes em C++", e por isso, o codigo ainda e' bastante "a' C".

Compilar com g++ -lm -lglut geometria.cc -o geometria

O código ja' trás alguns exemplos

/*
*  GPL
*
*  geometria - Written by Diogo Sousa aka orium
*  Copyright © 2007 Diogo Sousa
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <GL/gl.h>
#include <GL/glut.h>

#define BUFFER_SIZE 1024*50 /*50KB*/

void randomize();

typedef unsigned char rgbcolor;

class graphic
{
       private:
               int **matrix;

               void memcheck(void *) const;
               void write_to_buffer(int fd, char *buffer, const char *bytes, size_t size, int *counter) const;
               void dump_buffer(int fd, char *buffer, int size) const;
               float angle_to_rad(float angle) const;

               void froml(int wert, char *bopuffer) const;
               void froms(int wert, char *bopuffer) const;
       public:
               int xresolution;
               int yresolution;

               graphic(int xresolution, int yresolution);
               ~graphic();

               bool is_valid_point(int x, int y) const;

               int get_int_by_rgb(rgbcolor red, rgbcolor green, rgbcolor blue) const;
               void get_rgb_by_int(int rgb, rgbcolor *red, rgbcolor *green, rgbcolor *blue) const;

               /*Input*/
               int set_point(int x, int y, int color);
               void unset_point(int x, int y);
               void draw_rectangle(int x, int y, int l, int h, int color);
               void draw_circle(int x, int y, int r, int color);
               void draw_line(int x, int y, int fx, int fy, int color);

               /*Output*/
               int get_point(int x, int y) const;
               void print_graphic_tab(void) const;
               int write_xbm(const char *filename) const;
               int write_bmp(const char *filename) const;
               void show_graphic() const;
};

void graphic::memcheck(void *pointer) const
{
       if (pointer == NULL)
       {
               fprintf(stderr,"Erro na alocação de memória\n");
               exit(-1);
       }
}

graphic::graphic(int xresolution, int yresolution)
{
       int counter=0;

       this->xresolution=xresolution;
       this->yresolution=yresolution;

       matrix=(int **)malloc(xresolution*sizeof(*matrix)); /*Reserva memória para resolution apontadores*/

       memcheck(matrix);

       while (counter < xresolution)
       {
               matrix[counter]=(int *)malloc(yresolution*sizeof(**matrix));

               memcheck(matrix[counter]);

               memset(matrix[counter],0,yresolution*sizeof(**matrix));

               counter++;
       }
}

graphic::~graphic()
{
       int counter=0;

       while (counter < xresolution)
       {
               free(matrix[counter]);
               counter++;
       }

       free(matrix);
}

float graphic::angle_to_rad(float angle) const
{
       return angle*M_PI/180.0;
}

int graphic::get_int_by_rgb(rgbcolor red, rgbcolor green, rgbcolor blue) const
{
       int ret;

       ret=blue;
       ret|=green << 8;
       ret|=red << 16;

       return ret;
}

void graphic::get_rgb_by_int(int rgb, rgbcolor *red, rgbcolor *green, rgbcolor *blue) const
{
       *red=rgb >> 16;
       *green=(rgb >> 8) & 255;
       *blue=rgb & 255;
}

void graphic::print_graphic_tab(void) const
{
       int x=0;
       int y;
       int color;

       /*Lê coluna a coluna, da esquerda para a direita*/

       for (x=0; x < xresolution; x++)
               for (y=0; y < yresolution; y++)
                       if ((color=get_point(x,y)))
                               printf("x=%d y=%d rgb=%d\n",x,y,color);
}

void graphic::dump_buffer(int fd, char *buffer, int size) const
{
       if (size)
               write(fd,buffer,size);
}

void graphic::write_to_buffer(int fd, char *buffer, const char *bytes, size_t size, int *counter) const
{
       int bytecount=0;

       while (size--)
       {
               if (*counter >= BUFFER_SIZE)
               {
                       dump_buffer(fd,buffer,*counter);

                       *counter=0;
               }

               buffer[(*counter)++]=bytes[bytecount++];
       }
}

int graphic::write_xbm(const char *filename) const
{
       int fd;
       int counter=0;
       int bcounter=0;
       int buffcount=0;
       char *tmp;
       int byte;
       int x;
       int y;
       const char *hex="0123456789abcdef";
       char *buffer;

       fd=open(filename,O_WRONLY | O_CREAT | O_TRUNC,0700);

       if (fd == -1)
       {
               fprintf(stderr,"Erro ao abrir o ficheiro\n");

               return -1;
       }

       asprintf(&tmp,"%d",xresolution);

       memcheck(tmp);

       write(fd,"#define graphic_width ",22);
       write(fd,tmp,strlen(tmp));

       free(tmp);
       asprintf(&tmp,"%d",yresolution);

       write(fd,"\n#define graphic_height ",24);
       write(fd,tmp,strlen(tmp));

       free(tmp);

       write(fd,"\nstatic char graphic_bits[] = {\n   ",33);

       buffer=(char *)malloc(BUFFER_SIZE);

       memcheck(buffer);

       y=yresolution-1;

       /*De cima para baixo, da esquerda para a direita*/
       /*
               Cada byte contêm 8 pixeis:
                       0xaa == 0b00000010 == BRANCO PRETO (...)

               Nota:
                       Quando acabar a linha, deve ser imediatamente escrito o byte, pois este não e' somado aos pixeis seguintes
       */
       while (y >= 0)
       {
               x=0;

               byte=0;
               bcounter=0;

               while (x < xresolution)
               {
                       if (get_point(x,y))
                               byte+=((int)exp2((float)bcounter));

                       bcounter++;

                       if (bcounter == 8)
                       {
                               bcounter=0;

                               write_to_buffer(fd,buffer,"0x",2,&buffcount);
                               write_to_buffer(fd,buffer,&hex[byte/16%16],1,&buffcount);
                               write_to_buffer(fd,buffer,&hex[byte%16],1,&buffcount);
                               write_to_buffer(fd,buffer,", ",2,&buffcount);

                               counter++;
                               byte=0;

                               if (counter == 12)
                               {
                                       write_to_buffer(fd,buffer,"\n   ",4,&buffcount);
                                       counter=0;
                               }
                       }

                       x++;
               }

               if (bcounter)
               {

                       write_to_buffer(fd,buffer,"0x",2,&buffcount);
                       write_to_buffer(fd,buffer,&hex[byte/16%16],1,&buffcount);
                       write_to_buffer(fd,buffer,&hex[byte%16],1,&buffcount);
                       write_to_buffer(fd,buffer,", ",2,&buffcount);

                       counter++;

                       if (counter == 12)
                       {
                               write_to_buffer(fd,buffer,"\n   ",4,&buffcount);
                               counter=0;
                       }
               }

               y--;
       }

       dump_buffer(fd,buffer,buffcount);

       free(buffer);

       lseek(fd,-2,SEEK_CUR);

       write(fd,"};",2);

       close(fd);

       return 0;
}

void graphic::froml(int wert, char *bopuffer) const /* Copiado do gimp 2.3.5 /plug-ins/bmp/bmpwrite.c */
{
 bopuffer[0] = (wert & 0x000000ff)>>0x00;
 bopuffer[1] = (wert & 0x0000ff00)>>0x08;
 bopuffer[2] = (wert & 0x00ff0000)>>0x10;
 bopuffer[3] = (wert & 0xff000000)>>0x18;
}

void graphic::froms(int wert, char *bopuffer) const /* Copiado do gimp 2.3.5 /plug-ins/bmp/bmpwrite.c */
{
 bopuffer[0] = (wert & 0x00ff)>>0x00;
 bopuffer[1] = (wert & 0xff00)>>0x08;
}

int graphic::write_bmp(const char *filename) const
{
       int fd;
       int buffcount=0;
       int xcounter;
       int ycounter;
       char *buffer;
       char hibuff[40];

       fd=open(filename,O_WRONLY | O_CREAT | O_TRUNC,0700);

       if (fd == -1)
       {
               fprintf(stderr,"Erro ao abrir o ficheiro\n");

               return -1;
       }

       buffer=(char *)malloc(BUFFER_SIZE);

       memcheck(buffer);

       /*header*/

       /*
        *      0x36 = Numero de bytes do "BM" + header + info
        */
       froml(0x36+yresolution*xresolution,&hibuff[0x00]);    /*Tamanho do ficheiro (em pixels (c/ header))*/
       froms(0,&hibuff[0x04]);                               /*????*/
       froms(0,&hibuff[0x06]);                               /*????*/
       froml(0x36,&hibuff[0x08]);                            /*Offset do inicio da imagem*/
       froml(40,&hibuff[0x0C]);                              /*Tamanho do Info*/

       write_to_buffer(fd,buffer,"BM",2,&buffcount);

       write_to_buffer(fd,buffer,hibuff,16,&buffcount);

       /*info*/
       froml(xresolution,&hibuff[0x00]);                               /*Colunas*/
       froml(yresolution,&hibuff[0x04]);                               /*Linhas*/
       froms(1,&hibuff[0x08]);                                         /*color planes????*/
       froms(24,&hibuff[0x0A]);                                        /*Bits por pixel*/
       froml(0,&hibuff[0x0C]);                                         /*Tipo de compressão (0=none)*/
       froml(xresolution*24/8*yresolution,&hibuff[0x10]);              /*Tamanho do ficheiro (em bytes)*/
       froml(0,&hibuff[0x14]);                                         /*Colunas (pixeis por metro)*/
       froml(0,&hibuff[0x18]);                                         /*Linhas (pixeis por metro)*/
       froml(0,&hibuff[0x1C]);                                         /*Nº de cores (0 em caso se use 24 bits de profundidade de cor)*/
       froml(0,&hibuff[0x20]);                                         /*Nº de cores, blah blah blah...*/

       write_to_buffer(fd,buffer,hibuff,36,&buffcount);

       /*Gravar a imagem propriamente dita*/

       for (ycounter=0; ycounter < yresolution; ycounter++)
       {
               for (xcounter=0; xcounter < xresolution; xcounter++)
               {
                       rgbcolor r;
                       rgbcolor g;
                       rgbcolor b;

                       get_rgb_by_int(get_point(xcounter,ycounter),&r,&g,&b);

                       write_to_buffer(fd,buffer,(const char *)&r,1,&buffcount);
                       write_to_buffer(fd,buffer,(const char *)&g,1,&buffcount);
                       write_to_buffer(fd,buffer,(const char *)&b,1,&buffcount);
               }
       }

       dump_buffer(fd,buffer,buffcount);
       free(buffer);
       close(fd);

       return 0;
}

int graphic::set_point(int x, int y, int color)
{
       if (!is_valid_point(x,y))
               return -1;

       matrix[x][y]=color;

       return 0;
}

void graphic::unset_point(int x, int y)
{
       matrix[x][y]=0;
}

void graphic::draw_rectangle(int x, int y, int l, int h, int color)
{
       int counter=y;

       /*Desenha linhas paralelas verticais com altura h*/
       while (counter <= y+h)
       {
               set_point(x,counter,color);
               set_point(x+l,counter,color);

               counter++;
       }

       /*Desenha linhas paralelas horizontais com comprimento l*/
       counter=x;
       while (counter <= x+l)
       {
               set_point(counter,y,color);
               set_point(counter,y+h,color);

               counter++;
       }
}

void graphic::draw_circle(int x, int y, int r, int color)
{
       float angle_inc;
       float angle;
       float co;
       float ca;
       int h;
       int l;

       angle_inc=(360.0/(pow((double)r,2.0)*M_PI))*1.1;

       /*printf("Incrementar angulo: %fº\n",angle_inc);*/

       angle=angle_inc;

       set_point(x+r,y,color);
       set_point(x-r,y,color);
       set_point(x,y+r,color);
       set_point(x,y-r,color);

       for (angle=0.0; angle <= 90.0; angle+=angle_inc)
       {
               ca=cos(angle_to_rad(angle))*r;
               co=tan(angle_to_rad(angle))*ca;

               /*printf("Angulo=%f Cateto adjacente=%f Cateto oposto=%f\n",angle,ca,co);*/

               h=(int)nearbyint(co);
               l=(int)nearbyint(ca);

               /*
               set_point(x+l,y+h,color);
               set_point(x-l,y+h,color);
               set_point(x+l,y-h,color);
               set_point(x-l,y-h,color);
               */


               set_point(x+l,y+h,get_int_by_rgb(0,(rand()%155)+100,0));
               set_point(x-l,y+h,get_int_by_rgb(0,(rand()%155)+100,0));
               set_point(x+l,y-h,get_int_by_rgb(0,(rand()%155)+100,0));
               set_point(x-l,y-h,get_int_by_rgb(0,(rand()%155)+100,0));
       }
}

void graphic::draw_line(int x, int y, int fx, int fy, int color)
{
       int xcounter;
       int ycounter;
       int h;
       float angle;
       float co;

       if (x > fx && y < fy
           || x > fx && y > fy)
       {
               int tmp;

               tmp=fx;
               fx=x;
               x=tmp;

               tmp=fy;
               fy=y;
               y=tmp;
       }

       set_point(x,y,color);

       /* Isto esta' tão mau... */
       if (fx > x && fy > y)
       {
               angle=(float)(fy-y+1)/(float)(fx-x+1);

               for (xcounter=x+1; xcounter <= fx; xcounter++)
               {
                       co=angle*(float)(xcounter-x);

                       h=(int)nearbyint(co);

                       set_point(xcounter,h+y,color);
               }
       }

       if (fx > x && fy < y)
       {
               angle=(float)(y-fy+1)/(float)(fx-x+1);

               for (xcounter=x+1; xcounter <= fx; xcounter++)
               {
                       co=angle*(float)(y-xcounter);

                       h=(int)nearbyint(co);

                       set_point(xcounter,h+y,color);
               }
       }

       if (fx == x)
       {
               if (fy < y)
               {
                       int tmp;

                       tmp=y;
                       y=fy;
                       fy=tmp;
               }

               for (ycounter=y+1; ycounter <= fy; ycounter++)
                       set_point(x,ycounter,color);
       }

       if (fy == y)
       {
               if (fx < x)
               {
                       int tmp;

                       tmp=x;
                       x=fx;
                       fx=tmp;
               }

               for (xcounter=x+1; xcounter <= fx; xcounter++)
                       set_point(xcounter,y,color);
       }
}

int graphic::get_point(int x, int y) const
{
       if (is_valid_point(x,y))
               return matrix[x][y];

       return -1;
}

bool graphic::is_valid_point(int x, int y) const
{
       return (x < xresolution
                && y < yresolution
                && x >= 0
                && y >= 0);
}

graphic *gl_graphic;

void gl_draw_graphic(void)
{
       int xcounter;
       int ycounter;
       int color;
       rgbcolor r;
       rgbcolor g;
       rgbcolor b;

       glBegin(GL_POINTS);
               for (xcounter=0; xcounter < gl_graphic->xresolution; xcounter++)
                       for (ycounter=0; ycounter < gl_graphic->yresolution; ycounter++)
                               if ((color=gl_graphic->get_point(xcounter,ycounter)))
                               {
                                       gl_graphic->get_rgb_by_int(color,&r,&g,&b);
                                       glColor3f(r/255.0,g/255.0,b/255.0);
                                       glVertex3f((float)xcounter,(float)ycounter,0.0);
                               }
       glEnd();
}

void gl_display(void)
{
       glClear(GL_COLOR_BUFFER_BIT);

       gl_draw_graphic();

       glFlush();
}

void gl_init(void)
{
       glClearColor(0.0,0.0,0.0,0.0);
       glMatrixMode(GL_PROJECTION);
       glLoadIdentity();
       glOrtho(0.0,(float)gl_graphic->xresolution,0.0,(float)gl_graphic->yresolution,-1.0,1.0);
}

void gl_window(void)
{
       int argv=0;

       glutInit(&argv,NULL);
       glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
       glutInitWindowSize(gl_graphic->xresolution,gl_graphic->yresolution);
       glutInitWindowPosition(50,50);
       glutCreateWindow("...");
       gl_init();
       glutDisplayFunc(gl_display);

       glutMainLoop();
}

void graphic::show_graphic(void) const
{
       gl_graphic=(graphic *)this;
       gl_window();
}

void face(graphic *graphic)
{
       graphic->draw_line(200,200,50,10,graphic->get_int_by_rgb(255,0,0));
       graphic->draw_rectangle(300,200,300,50,graphic->get_int_by_rgb(255,255,255));
       graphic->draw_circle(300,600,150,graphic->get_int_by_rgb(0,255,0));

       graphic->draw_circle(300,600,75,graphic->get_int_by_rgb(0,0,255));

       graphic->draw_circle(600,600,75,graphic->get_int_by_rgb(150,150,150));

       graphic->draw_circle(400,400,380,graphic->get_int_by_rgb(255,255,0));

       graphic->draw_rectangle(380,320,100,300,graphic->get_int_by_rgb(250,190,190));
}

void randomize(void)
{
       struct timeval tm;

       gettimeofday(&tm,NULL);

       srand((unsigned)(tm.tv_usec*1000000+tm.tv_usec+getpid()));
}

void random_painting(graphic *graphic) /* Just for fun */
{
       int x;
       int y;

       for (x=0; x < graphic->xresolution; x++)
               for (y=0; y < graphic->yresolution; y++)
               {
                       //graphic->set_point(x,y,graphic->get_int_by_rgb(rand()%256,rand()%256,rand()%256));
                       graphic->set_point(x,y,graphic->get_int_by_rgb(0,(rand()%156)+100,0));
               }
}

void draw_sic_cos_func(graphic &graphic)
{
       graphic.draw_line(0,graphic.yresolution/2,graphic.xresolution-1,graphic.yresolution/2,graphic.get_int_by_rgb(255,255,255));

       graphic.draw_line(0,(graphic.yresolution*0.4)+graphic.yresolution/2.0,graphic.xresolution-1,
                         (graphic.yresolution*0.4)+graphic.yresolution/2.0,graphic.get_int_by_rgb(100,0,0));

       graphic.draw_line(0,-(graphic.yresolution*0.4)+graphic.yresolution/2.0,graphic.xresolution-1,
                         -(graphic.yresolution*0.4)+graphic.yresolution/2.0,graphic.get_int_by_rgb(100,0,0));

       for (int x=0; x < graphic.xresolution; x++)
       {
               graphic.set_point(x,cos(x/100.0)*(graphic.yresolution*0.4)+graphic.yresolution/2.0,graphic.get_int_by_rgb(0,255,0));
               graphic.set_point(x,sin(x/100.0)*(graphic.yresolution*0.4)+graphic.yresolution/2.0,graphic.get_int_by_rgb(0,0,255));
       }
}

int main(void)
{
       graphic graphic(1200,800);
#if 0
       randomize();

       //random_painting(&graphic);
       face(&graphic);

       graphic.write_bmp("/tmp/graphic.bmp");

       graphic.show_graphic();
#endif
       draw_sic_cos_func(graphic);

       graphic.show_graphic();

       return 0;
}

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora