00001
00007 #ifndef __IMAGE_H__
00008 #define __IMAGE_H__
00009
00010 #include <algorithm>
00011 #include <cmath>
00012 #include <fstream>
00013 #include <string>
00014
00015 #include "matrix.h"
00016 #include "pixel.h"
00017
00018 #ifndef M_PI
00019 #define M_PI 3.14159265358979323846
00020 #endif
00021
00022 namespace Plot {
00023
00024
00042 template<class PixelType=RGBPixel<>, class PixelMatrix=MatrixType<PixelType>::rectangular >
00043 class AARImage {
00044 private:
00045 void BresenhamAlongC(int rA, int cA, int rB, int cB, int direction, PixelType p, int thickness);
00046 void BresenhamAlongR(int rA, int cA, int rB, int cB, int direction, PixelType p, int thickness);
00047
00049 PixelMatrix pixels;
00050
00051 public:
00053 typedef typename PixelMatrix::size_type PixelSubscript;
00054 typedef PixelSubscript size_type;
00055 typedef PixelType value_type;
00056
00058 typedef double CartesianCoordinate;
00059
00061 AARImage(PixelSubscript height=0, PixelSubscript width=0)
00062 : pixels (height,width) { mat::set(pixels,default_bg); }
00063
00065 inline void draw_pixel(const PixelSubscript r, const PixelSubscript c, PixelType p) {
00066 if (inbounds(r,c))
00067 pixels[r][c] = p;
00068 }
00069
00071 inline const PixelType& get_pixel(const PixelSubscript r, const PixelSubscript c) const
00072 { return(pixels[r][c]); }
00073
00075 inline PixelSubscript nrows() const { return pixels.nrows(); }
00076
00078 inline PixelSubscript ncols() const { return pixels.ncols(); }
00079
00080
00081 void draw_rectangle(int r1, int c1, int r2, int c2, PixelType p);
00082 void draw_line(int r1, int c1, int r2, int c2, PixelType p, int thickness=1);
00083 void draw_bar(CartesianCoordinate cx, CartesianCoordinate cy,
00084 double angle, double length, double width=1, PixelType p=default_fg, bool always_draw=true);
00085
00087 void draw_border(size_type borderwidth=1, PixelType p=default_border) {
00088 const PixelSubscript b=borderwidth;
00089 const PixelSubscript r=nrows();
00090 const PixelSubscript c=ncols();
00091
00092 draw_rectangle(0, 0, r, b, p);
00093 draw_rectangle(0, b, b, c-b, p);
00094 draw_rectangle(0, c-b, r, c, p);
00095 draw_rectangle(r-b, b, r, c-b, p);
00096 }
00097
00098 ostream& ppm_write( ostream& os, const string& comments="", int max_val=255 );
00099
00101 template<class PType, class PMatrix>
00102 friend ostream& operator<<(ostream& s, const AARImage<PType,PMatrix>& o);
00103
00104 protected:
00106 inline PixelSubscript col_from_x(const CartesianCoordinate x) { return PixelSubscript(x); }
00107
00109 inline PixelSubscript row_from_y(const CartesianCoordinate y) { return PixelSubscript(pixels.nrows()-1-y); }
00110
00112 inline bool inbounds(const PixelSubscript r, const PixelSubscript c) const {
00113 return (r>=0 && r<pixels.nrows() &&
00114 c>=0 && c<pixels.ncols());
00115 }
00116
00117 public:
00119 static PixelType default_fg;
00120 static PixelType default_bg;
00121 static PixelType default_border;
00122 };
00123
00124
00125
00126
00127 template<class PixelType, class PixelMatrix> PixelType AARImage<PixelType,PixelMatrix>::default_fg(1,1,1,false);
00128 template<class PixelType, class PixelMatrix> PixelType AARImage<PixelType,PixelMatrix>::default_bg(0,0,0);
00129 template<class PixelType, class PixelMatrix> PixelType AARImage<PixelType,PixelMatrix>::default_border(1,1,1);
00130
00131
00132
00139 template<class PixelType, class PixelMatrix>
00140 ostream& AARImage<PixelType,PixelMatrix>::ppm_write( ostream& os, const string& comments, int max_val)
00141 {
00142 os << "P6\n";
00143 os << "#" << comments.c_str() << "\n";
00144 os << pixels.ncols() << " " << pixels.nrows() << "\n";
00145 os << max_val << "\n";
00146
00147 for (PixelSubscript r=0; r<pixels.nrows(); r++)
00148 for (PixelSubscript c=0; c<pixels.ncols(); c++)
00149 (pixels[r][c].write_binary(os, max_val));
00150
00151 return os;
00152 }
00153
00154
00155
00157 template<class PixelType, class PixelMatrix>
00158 ostream& operator<<(ostream& s, const AARImage<PixelType,PixelMatrix>& o)
00159 { return cout << o.pixels; }
00160
00161
00162
00166 template<class PixelType, class PixelMatrix>
00167 void AARImage<PixelType,PixelMatrix>::draw_rectangle(int r1, int c1, int r2, int c2, PixelType p)
00168 {
00169 for (PixelSubscript r=min(r1,r2); r<max(r1,r2); r++)
00170 for (PixelSubscript c=min(c1,c2); c<max(c1,c2); c++)
00171 draw_pixel(r,c,p);
00172 }
00173
00174
00175
00182 template<class PixelType, class PixelMatrix>
00183 void AARImage<PixelType,PixelMatrix>::draw_line(int r1, int c1, int r2, int c2, PixelType p, int thickness)
00184 {
00185 int rA,rB,cA,cB;
00186 int r, direction;
00187
00188
00189 const int dc = c2-c1;
00190 if (dc >= 0) { rA = r1; cA = c1; r = r2; cB = c2; }
00191 else { rA = r2; cA = c2; r = r1; cB = c1; }
00192
00193
00194 00195
00196 const int dr = rA-r;
00197 if (dr < 0) { direction = 1; rB = r; }
00198 else { direction = -1; rB = (rA<<1)-r; }
00199
00200
00201
00202
00203
00204 if (abs(dc) > abs(dr)) BresenhamAlongC(rA, cA, rB, cB, direction, p, thickness);
00205 else BresenhamAlongR(rA, cA, rB, cB, direction, p, thickness);
00206 }
00207
00208
00209
00212 template<class PixelType, class PixelMatrix>
00213 void AARImage<PixelType,PixelMatrix>::BresenhamAlongC(int rA, int cA, int rB, int cB, int direction, PixelType p, int thickness)
00214 {
00215 const int dr = rB-rA;
00216 const int dc = cB-cA;
00217 const int incE = 2*dr;
00218 const int incSE = 2*(dr-dc);
00219
00220
00221
00222 int d = 2*dr-dc;
00223 int r = rA;
00224 int i;
00225
00226 for (i=-thickness/2; i<=thickness/2; i++)
00227 draw_pixel(rA+i,cA,p);
00228
00229 for (int c=cA+1; c<=cB; c++) {
00230 if (d <= 0 )
00231 d += incE;
00232 else {
00233 d += incSE;
00234 r += direction;
00235 }
00236 for (i=-thickness/2; i<=thickness/2; i++)
00237 draw_pixel(r+i,c,p);
00238 }
00239 }
00240
00241
00242
00245 template<class PixelType, class PixelMatrix>
00246 void AARImage<PixelType,PixelMatrix>::BresenhamAlongR(int rA, int cA, int rB, int cB, int direction, PixelType p, int thickness)
00247 {
00248 const int dc = cB-cA;
00249 const int dr = rB-rA;
00250 const int incE = 2*dc;
00251 const int incSE = 2*(dc-dr);
00252
00253
00254
00255 int d = 2*dc-dr;
00256 int c = cA;
00257 int rp = rA;
00258
00259 int i;
00260
00261 for (i=-thickness/2; i<=thickness/2; i++)
00262 draw_pixel(rA,cA+i,p);
00263
00264 for (int r=rA; r<rB; r++) {
00265 rp += direction;
00266 if (d <= 0 )
00267 d += incE;
00268 else {
00269 d += incSE;
00270 c += 1;
00271 }
00272 for (i=-thickness/2; i<=thickness/2; i++)
00273 draw_pixel(rp,c+i,p);
00274 }
00275 }
00276
00277
00278
00294 template<class PixelType, class PixelMatrix>
00295 void AARImage<PixelType,PixelMatrix>::draw_bar(CartesianCoordinate cx, CartesianCoordinate cy,
00296 double angle, double length, double width,
00297 PixelType p, bool always_draw)
00298 {
00299
00300
00301 if (always_draw || length >= 1.0) {
00302 const double xoffset = (double)(((length)/2)*cos(angle));
00303 const double yoffset = (double)(((length)/2)*sin(angle));
00304 const CartesianCoordinate y1 = cy-yoffset;
00305 const CartesianCoordinate y2 = cy+yoffset;
00306 const CartesianCoordinate x1 = cx-xoffset;
00307 const CartesianCoordinate x2 = cx+xoffset;
00308 const PixelSubscript r1 = row_from_y(y1);
00309 const PixelSubscript r2 = row_from_y(y2);
00310 const PixelSubscript c1 = col_from_x(x1);
00311 const PixelSubscript c2 = col_from_x(x2);
00312
00315 if (p.istransparent()) {
00316 PixelAverage<> pa;
00317 pa+=get_pixel(r1,c1);
00318 pa+=get_pixel(r2,c2);
00319 p=contrasting_color(pa());
00320 }
00321
00322
00323 if (width<=1)
00324 draw_line(r1,c1,r2,c2,p,1);
00325 else {
00326
00327 double delt;
00328 for (delt=0; delt<width/2; delt+=0.5) {
00329 const double deltax=(double)(delt*cos(M_PI/2-angle));
00330 const double deltay=(double)(delt*sin(M_PI/2-angle));
00331 draw_line( row_from_y(y1+deltay), col_from_x(x1-deltax),
00332 row_from_y(y2+deltay), col_from_x(x2-deltax), p, std::min(2,int(width)));
00333 draw_line( row_from_y(y1-deltay), col_from_x(x1+deltax),
00334 row_from_y(y2-deltay), col_from_x(x2+deltax), p, std::min(2,int(width)));
00335 }
00336 }
00337 }
00338 }
00339
00340
00341
00342 }
00343 #endif