Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

image.h

Go to the documentation of this file.
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 /* Static defaults */ 
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"; /* file type: P6=binary, P3=ASCII */
00146   os << "#" << comments.c_str() << "\n";
00147   os << pixels.ncols()  << " " << pixels.nrows() << "\n";  
00148   os << int(max_val)    << "\n"; /* maximum R, G, or B value */
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;  /* canonical form of coordinates   */
00189   int r, direction;
00190   
00191   /* Swap endpoints if line wasn't specifed from left to right */
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   /* Flip right endpoint across horizontal axis if it is above it 
00198      (leaves lower right quadrant only) */
00199   const int dr = rA-r;
00200   if (dr < 0)   { direction =  1;  rB =         r; }
00201   else          { direction = -1;  rB = (rA<<1)-r; }
00202 
00203   //cout << "(" << rA << "," << cA << ") -> (" << rB << "," << cB << ") " << direction << " " << p << endl;
00204   //cout << "dr: " << dr << " dc: " << dc << endl;
00205 
00206   /* Iterate along the axis which changes the most */
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   //cout << "AlongC" << endl;
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);  /* set starting point */
00231 
00232   for (int c=int(cA+1); c<=int(cB); c++) {
00233     if (d <= 0 ) /* choose E */
00234       d += incE;
00235     else {       /* choose SE */
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   //cout << "AlongR" << endl;
00257   
00258   int d  = 2*dc-dr;
00259   int c  = cA;
00260   int rp = rA; /* r corrected for direction */
00261 
00262   int i;
00263   
00264   for (i=-thickness/2; i<=thickness/2; i++)
00265     draw_pixel(rA,cA+i,p);  /* set starting point */
00266 
00267   for (int r=int(rA); r<int(rB); r++) {
00268     rp += direction;
00269     if (d <= 0 ) /* choose E */
00270       d += incE;
00271     else {       /* choose SE */
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   /* Lines shorter than one pixel can be skipped if requested */
00303   /* The "-1" corrects for the width of the halves of each endpoint that are counted implicitly */
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     /* Draw at least one full line */ 
00326     if (width<=1)
00327       draw_line(r1,c1,r2,c2,p,1);
00328     else {
00329       /* This is a hack to get a filled rectangle without having to handle polygons */
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 } /* namespace Plot */
00346 #endif /* __IMAGE_H__ */

Generated on Mon Jan 20 02:35:44 2003 for RF-LISSOM by doxygen1.3-rc2