Advertisement
kburnik

C++ - BMP geometrijsko crtanje - proceduralna paradigma

Oct 6th, 2012
239
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.83 KB | None | 0 0
  1. /*
  2.     Tema: Crtanje geometrijskih likova - proceduralna paradigma
  3.    
  4.       U ovom primjeru ostvarujemo "framework", odnosno vlastito okružje kao
  5.       skup alata i metoda za rad s geometrijskim likovima.
  6.       U prvom dijelu radimo isključivo s osnovnim tipovima podataka
  7.       (bez struktura), a potom (u drugom primjeru) to isto ostvarujemo
  8.       rabeći strukture kako bi naglasili prednosti tog pristupa
  9.       implementaciji.
  10.      
  11.       Kao primjer uporabe ovog okružja, ostvarujemo crtanje nekoliko
  12.       kružnica, linija i pravokutnika.
  13.      
  14.       Crtanje ćemo ostvariti kao generiranje bitmape (matrice točaka,
  15.       tj. boja) koju kasnije možemo otvoriti u nekom grafičkom pregledniku.
  16.      
  17.       U ovoj implementaciji svakako treba uočiti da je bilo kakva manipulacija
  18.       "objektima" u smislu vektorske grafike gotovo nezamisliva, a u najmanju
  19.       ruku jako nezgrapna - takav rad bi se svodio na vođenje računa o jako
  20.       velikom broju nepovezanih (negrupiranih) varijabli. Također i metode
  21.       kojima bi manipulaciju (npr. skaliranje ili rotaciju) ostvarili bile
  22.       bi isto tako nezgrapne i tražile velik broj parametara. U tom smislu
  23.       bilo kakva objektna paradigma (objektno orijentirani dizajn), pa čak
  24.       i onaj s jednostavnim strukturama, mnogo pojednostavljuje rad s ovim
  25.       "objektima".
  26.  
  27.     Datum: 06.10.2012.
  28.  
  29.     Autor: Kristijan Burnik, udruga informatičara Božo Težak
  30.  
  31.     Gmail: kristijanburnik
  32.  
  33. */
  34.  
  35. #include <iostream>
  36. #include <cstdlib>
  37. #include <cmath>
  38.  
  39. using namespace std;
  40.  
  41. // tri byte-a su potrebna za ostvarenje RGB tehnike bojanja (16 milijuna boja)
  42. // često ćemo to rabiti pa ovdje radimo kraticu
  43. // R,G,B su u intervalu [0,255]
  44. typedef unsigned char byte;
  45.  
  46.  
  47. // definiramo neke konstante koje ćemo često rabiti,
  48. // zgodno nam je imati neka svojstva definirana na jednom mjestu
  49. // kako bi ih kasnije lako modificirali po potrebi ili učinili fleksibilnijima
  50. // dodatnom implementacijom (npr. proizvoljni unos dimenzija bitmape)
  51. const int BITMAP_WIDTH = 1024;
  52. const int BITMAP_HEIGHT = 768;
  53.  
  54. // definiramo kojim redom su poslagane boje, da ne bismo pomiješali indekse
  55. // ovo je jedan manji primjer tzv. "defenzivnog programiranja"
  56. // -> unaprijed spriječavamo moguće pogreške
  57. const int R = 0;
  58. const int G = 1;
  59. const int B = 2;
  60.  
  61. // bitmapa je ovdje matrica dimenzija 1024x768 i dodatne tri vrijednosti
  62. // na svakom polju za boju, ovo je najopćenitiji oblik zapisa bitmape
  63. // koji kasnije rabimo kod generiranja izlazne BMP datoteke
  64. byte bitmap[ BITMAP_WIDTH ][ BITMAP_HEIGHT ][ 3 ];
  65.  
  66.  
  67. // metoda za postavljanje jednog pixela u zadanu boju
  68. // rabi se u svim ostalim dijelovima za renderiranje (čitaj: produciranje slike)
  69. void setpixel(int x,int y,int r,int g,int b) {
  70.     bitmap[x][y][R] = r;
  71.     bitmap[x][y][G] = g;            
  72.     bitmap[x][y][B] = b;
  73. }
  74.  
  75. // metoda za postavljanje čitave bitmape u zadanu boju
  76. void clearbitmap(byte r, byte g, byte b)  {
  77.     for (int i = 0; i < BITMAP_WIDTH; i++ ) {
  78.         for (int j = 0; j < BITMAP_HEIGHT; j++ ) {
  79.            setpixel(i,j,r,g,b) ;
  80.         }  
  81.     }
  82. }
  83.  
  84. // metoda za crtanje linije, zapravo to je pravac kroz dvije točke u nekom
  85. // intervalu [x1,x2]
  86. // metoda nije baš "najfinija", treba se još doraditi da linija izgleda glađe
  87. // za neke nagibe
  88. void line(int x1,int y1, int x2,int y2, byte r, byte g, byte b) {
  89.     // jednadzba pravca kroz dvije točke glasi:
  90.     // (x2 - x1)*(y - y1) = (y2 - y1)*(x - x1)
  91.     // kako ne bi tražili po citavoj matrici
  92.     // ograničavamo se na opisani pravokutnik
  93.     int sx = min(x1,x2);
  94.     int ex = max(x1,x2);
  95.     int sy = min(y1,y2);
  96.     int ey = max(y1,y2);
  97.    
  98.    
  99.     float dx = x2 - x1;
  100.     float dy = y2 - y1;
  101.  
  102.     float dif = 1.f;
  103.     if (dx == 0) {
  104.         for (int y = sy; y <= ey; y++) {
  105.                  setpixel((int)sx,y,r,g,b);    
  106.         }
  107.     } else if (dy == 0) {
  108.         for (int x = sx; x <= ex; x++) {
  109.                  setpixel(x,sy,r,g,b);    
  110.         }
  111.     } else {
  112.         for (float x = sx; x <= ex; x+= dif) {
  113.                  float  y = y1 + (dy) * (x - x1)/(dx);
  114.                  setpixel((int)x,(int)y,r,g,b);
  115.         }
  116.     }
  117.    
  118. }
  119.  
  120. // pravokutnik je zadan s dva vrha (dijagonalom) i željenom bojom
  121. // isto kao i linija
  122. void rectangle(int x1,int y1, int x2,int y2, byte r, byte g, byte b) {
  123.     // normaliziramo točke kako bi dijagonalu mogli zadati na bilo koji način
  124.     if (x1 > x2) swap(x1,x2);
  125.     if (y1 > y2) swap(y1,y2);
  126.    
  127.     // crtamo redom linije spajajući točke:
  128.     /// NW,NE,SE,SW (orijentacija po stranama svijeta)
  129.     line(x1,y1,x2,y1,r,g,b);
  130.     line(x2,y1,x2,y2,r,g,b);
  131.     line(x2,y2,x1,y2,r,g,b);
  132.     line(x1,y2,x1,y1,r,g,b);
  133.    
  134.     // uočiti da smo složeniji "objekt" pravokutnik sastavili od linija
  135.     // a linije od točaka! ovo je česta pojava koju
  136.     // posebice u objektnoj paradigmi susrećemo gotovo na svakom koraku
  137.    
  138. }
  139.  
  140.  
  141. // metoda za crtanje kružnice
  142. // za nju su potrebe koordinate središta, radijus i boja
  143. // metoda također nije "najfinija", tj. dade se doraditi i pojednostavniti
  144. // druga, ponešto sporija metoda bi bila upotrebom trigonometrijskih funkcija
  145. // sinus i/ili kosinus, međutim ovo je svakako dovoljno za jednostavan prikaz
  146. void circle(int sx, int sy, int radius, byte r, byte g, byte b) {
  147.     // jednadžba kružnice glasi (x - sx)^2 + (y - sy)^2 = r
  148.     // da ne trazimo po čitavoj matrici ograničavamo se na opisani joj kvadrat
  149.     float rr = radius*radius;
  150.     for (float x = sx - radius - 1; x <= sx + radius + 1; x+=1 ) {
  151.         for (float y = sy - radius - 1; y <= sy + radius +1 ; y+=1) {
  152.             int xsx = (int)(x - sx);
  153.             int ysy  = (int)(y - sy);
  154.             if ( abs((xsx*xsx + ysy*ysy) - rr) <= radius)  {
  155.                setpixel((int)x,(int)y,r,g,b);
  156.             }
  157.         }
  158.     }
  159. }
  160.  
  161.  
  162. // metoda za spremanje bitmape, zanemariti implementaciju jer je manje važna
  163. // više o strukturi bitmap datoteka:
  164. //    http://en.wikipedia.org/wiki/BMP_file_format
  165. // ova implementacija konkretno ima problema sa ispravnim prikazom boja
  166. // međutim postoji niz bibiloteka koje nam mogu poslužiti za renderiranje BMP-a
  167. // s puno većom pouzdanošću i potrebnim opcijama
  168. // ova implementacija je prilagođena, a preuzeta je izvorno sa adrese :
  169. //    http://stackoverflow.com/a/2654860
  170. void outputbitmap(string filename = "img.bmp") {
  171.    
  172.     int w = BITMAP_WIDTH;
  173.     int h = BITMAP_HEIGHT;
  174.    
  175.     FILE *f;
  176.     unsigned char *img = NULL;
  177.     int filesize = 54 + 3*w*h;
  178.     if( img )
  179.         free( img );
  180.     img = (unsigned char *)malloc(3*w*h);
  181.     memset(img,0,sizeof(img));
  182.    
  183.     for(int i=0; i<w; i++)
  184.     {
  185.         for(int j=0; j<h; j++)
  186.     {
  187.         int x=i; int y=j;
  188.         int r = bitmap[i][j][R]*255;
  189.         int g = bitmap[i][j][G]*255;
  190.         int b = bitmap[i][j][B]*255;
  191.         if (r > 255) r=255;
  192.         if (g > 255) g=255;
  193.         if (b > 255) b=255;
  194.         img[(x+y*w)*3+2] = (unsigned char)(r);
  195.         img[(x+y*w)*3+1] = (unsigned char)(g);
  196.         img[(x+y*w)*3+0] = (unsigned char)(b);
  197.     }
  198.     }
  199.    
  200.     unsigned char bmpfileheader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0};
  201.     unsigned char bmpinfoheader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0};
  202.     unsigned char bmppad[3] = {0,0,0};
  203.    
  204.     bmpfileheader[ 2] = (unsigned char)(filesize    );
  205.     bmpfileheader[ 3] = (unsigned char)(filesize>> 8);
  206.     bmpfileheader[ 4] = (unsigned char)(filesize>>16);
  207.     bmpfileheader[ 5] = (unsigned char)(filesize>>24);
  208.    
  209.     bmpinfoheader[ 4] = (unsigned char)(       w    );
  210.     bmpinfoheader[ 5] = (unsigned char)(       w>> 8);
  211.     bmpinfoheader[ 6] = (unsigned char)(       w>>16);
  212.     bmpinfoheader[ 7] = (unsigned char)(       w>>24);
  213.     bmpinfoheader[ 8] = (unsigned char)(       h    );
  214.     bmpinfoheader[ 9] = (unsigned char)(       h>> 8);
  215.     bmpinfoheader[10] = (unsigned char)(       h>>16);
  216.     bmpinfoheader[11] = (unsigned char)(       h>>24);
  217.    
  218.     f = fopen(filename.c_str(),"wb");
  219.     fwrite(bmpfileheader,1,14,f);
  220.     fwrite(bmpinfoheader,1,40,f);
  221.     for(int i=0; i<h; i++)
  222.     {
  223.         fwrite(img+(w*(h-i-1)*3),3,w,f);
  224.         fwrite(bmppad,1,(4-(w*3)%4)%4,f);
  225.     }
  226.     fclose(f);    
  227. }
  228.  
  229.  
  230. // glavni program koji rabi naš "framework"
  231. // i obavlja pripremu, crtanje te rendering
  232. // čistimo bitmapu i crtamo nekoliko geometrijskih "likova" (objekata)
  233. int main() {
  234.    
  235.     clearbitmap(255,255,255);
  236.  
  237.     line (10,10,400,200,  100,0,0);
  238.     rectangle(10,10,400,200  ,0,100,0);
  239.        
  240.     circle(450,450,150, 0,0,100);
  241.  
  242.     // spremamo bitmapu
  243.     outputbitmap( "img.bmp" );
  244.    
  245.     cout << "Generirana bitmapa se nalazi u istom direktoriju programa."
  246.          << endl
  247.          << "Pod nazivom \"img.bmp\""
  248.          << endl
  249.          << endl
  250.     ;
  251.      
  252.     system("pause");
  253.  
  254.     return 0;
  255. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement