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