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";
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)
00099 {
00100 swap(x1, x2), swap(y1, y2);
00101 swap( ((RGB&)col1), ((RGB&)col2) );
00102 }
00103 if( (flip_y = y1 > y2) )
00104 {
00105 y1 = -y1, y2 = -y2;
00106 }
00107 if( (swap_xy = y2-y1 > x2-x1) )
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;
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 );
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;
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;
00167 vector<int> xvals;
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 }