Main Page | File List

Canvas.cpp

00001 #include "Canvas.h"
00002 #include "color.h"
00003 #include "xmath.h"
00004 #include <iostream>
00005 #include <fstream>
00006 #include <vector>
00007 
00008 
00009 using namespace std;
00010 
00011 namespace columbia
00012 {
00013 
00014   void Canvas :: init() 
00015   { 
00016     int N = hReso*vReso;
00017     
00018     delete [] data; 
00019     data = new RGB [N]; 
00020     memset(data, 0, sizeof(RGB) * N);
00021   }
00022 
00023   void Canvas :: Clear(RGB const& color)
00024   {
00025     for (int row = 0; row < vReso; row++) 
00026       for (int col = 0; col < hReso; col++) 
00027       {
00028         (*this)[row][col] = color;
00029       }
00030   }
00031   
00032 
00033   void Canvas :: WritePPM(const char *_filename) const
00034   {
00035     Canvas* This =  (Canvas*)this;
00036     
00037     if(!_filename) 
00038       _filename = filename.c_str();
00039 
00040     ofstream file;
00041     file.open (_filename, ios::out | ios::binary);
00042     
00043     if(file) 
00044     {
00045       file << "P6\n";   // color rawbits format
00046       file << hReso << " " << vReso << endl << 100 << endl;
00047   
00048       unsigned char r, g, b;
00049       for (int row = 0; row < vReso; row++) 
00050         for (int col = 0; col < hReso; col++) 
00051         {
00052           r = (unsigned char) (100.0*(*This)[vReso-row-1][col][0]);  
00053           g = (unsigned char) (100.0*(*This)[vReso-row-1][col][1]);  
00054           b = (unsigned char) (100.0*(*This)[vReso-row-1][col][2]);  
00055 
00056           if(r>100.0 || g>100.0 || b>100.0)  throw "RGB color overflow\n"; 
00057 
00058           file << r << g << b;
00059         }
00060 
00061       file << endl;
00062       file.close();
00063     }
00064     else 
00065       cerr << "Can't open output file " << _filename << endl;
00066   }
00067 
00068 
00069   void Canvas :: scanLineSegment(int x1, int y1, RGB const& col1, int x2, int y2, RGB const& col2, multimap<int, int>* output)
00070   {
00071     assert( x2-x1 >= 1 && x2-x1 >= y2-y1 && y2-y1 >= 0);
00072 
00073     for(int x = x1; x != x2; ++x)
00074     {
00075       double t = ( double(x-x1) ) / (x2 - x1);
00076       int y = round( interpolate(t, double(y1), double(y2)) );
00077 
00078       int X = x, Y = y;
00079 
00080       if(swap_xy)
00081       {
00082         swap(X,Y);
00083       }
00084       if(flip_y) Y = -Y; 
00085       
00086       if(output) 
00087         output->insert(make_pair(Y, X));
00088       else
00089         Pixel(Y + vReso/2, X + hReso/2) = interpolate(t, col1, col2);
00090     }
00091   }
00092   
00093 
00094   void Canvas :: ScanLineSegment(int x1, int y1, RGB const& col1, int x2, int y2, RGB const& col2, multimap<int,int>* output)
00095   {
00096     if(x1==x2 && y1==y2) return;
00097     
00098     if(x1 > x2)                                       // always scan convert from left to right.
00099     {
00100       swap(x1, x2), swap(y1, y2); 
00101       swap( ((RGB&)col1),  ((RGB&)col2) );
00102     }
00103     if( (flip_y = y1 > y2) )                          // always scan convert from down to up.
00104     {
00105       y1 = -y1, y2 = -y2;
00106     }
00107     if( (swap_xy = y2-y1 > x2-x1) )                   // and always scan convert a line with <= 45 deg to x-axis.
00108     {
00109       swap(x1, y1), swap(x2, y2);
00110     }
00111     scanLineSegment(x1, y1, col1, x2, y2, col2, output);
00112   }
00113 
00114 
00115   void Canvas :: WireCircle(int center_x, int center_y, int radius, int slices, RGB const& col)
00116   {
00117     double angle_step = 2 * pi / slices;
00118 
00119     double angle = 0;
00120     int x1 = center_x + radius, y1 = center_y;
00121     int x2, y2;
00122     
00123     for(int i=0; i<slices; i++)
00124     {
00125       angle += angle_step;
00126       x2 = round(center_x + radius * cos(angle));
00127       y2 = round(center_y + radius * sin(angle));
00128       (*this)[y2 + vReso/2][x2 + hReso/2] = col;   // make sure consecutive segment is connected.  
00129       ScanLineSegment(x1, y1, col, x2, y2, col);
00130       x1 = x2;
00131       y1 = y2;
00132     }
00133   }
00134 
00135 
00136   void Canvas :: SolidCircle(int center_x, int center_y, int radius, RGB const& col)
00137   {
00138     for(int y = 0; y <= radius; y++)
00139     {
00140       int x = round( sqrt(double(radius * radius - y * y)) );
00141       if(x == 0) 
00142         x = round( sqrt(2. * radius - 1) / 2 );     // half value of the previous x. this way the circle looks better.
00143       
00144       ScanLineSegment(-x + center_x,  y + center_y, col,   x + center_x,  y + center_y, col);
00145       if(y != 0)
00146         ScanLineSegment(-x + center_x,  -y + center_y, col,   x + center_x,  -y + center_y, col);
00147     }
00148   }
00149 
00150   
00151   void Canvas :: SolidRectangle(int minx, int miny, int maxx, int maxy, RGB const& col)
00152   {
00153     for(int y = miny; y < maxy; y++)
00154       ScanLineSegment(minx,  y, col,   maxx, y, col);
00155   }
00156   
00157 
00158   void Canvas :: SolidTriangle(int x1, int y1, RGB const& col1, int x2, int y2, RGB const& col2, int x3, int y3, RGB const& col3)
00159   {
00160     multimap<int, int> scanned_pnts;     // the key is y value of the scanned point.
00161 
00162     ScanLineSegment(x1,y1,White, x2,y2,White, &scanned_pnts);
00163     ScanLineSegment(x1,y1,White, x3,y3,White, &scanned_pnts);
00164     ScanLineSegment(x3,y3,White, x2,y2,White, &scanned_pnts);
00165 
00166     int cur_yval = vReso / 2;           // initialize to an invalid value.
00167     vector<int> xvals;                  // put x_vals of all points with the same y value here.
00168     
00169     for (multimap<int, int>::iterator it = scanned_pnts.begin(); it != scanned_pnts.end(); ++it)
00170     {
00171       int y = it->first;
00172       if(y != cur_yval) 
00173       {
00174         if(xvals.size())
00175         {
00176           int xleft = *( min_element( xvals.begin(), xvals.end() ) );
00177           int xright = *( max_element( xvals.begin(), xvals.end() ) );
00178           ScanLineSegment(xleft, cur_yval, White, xright, cur_yval, White);
00179           xvals.clear();
00180         }
00181         cur_yval = y;
00182       }
00183       xvals.push_back(it->second);
00184     }
00185   }
00186   
00187 }

Generated on Fri Jul 9 11:02:31 2004 by doxygen 1.3.6