Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

Graphics.cc

Go to the documentation of this file.
00001 #include "DualCoding/ShapeEllipse.h"
00002 #include "DualCoding/EllipseData.h"
00003 #include "Graphics.h"
00004 #include "FilterBankGenerator.h"
00005 
00006 using namespace std;
00007 
00008 //! empty definition of macro for checking for any exceeding of image's memory boundaries
00009 //#define CHKBOUNDS(p) {}
00010 
00011 // ! check memory boundaries of image, first that we are after the start of the image, second that we are before the end of the image, and third that we are within a valid row (in case of interleaved rows), fourth that we are within a valid column (interleaved pixels)
00012 #define CHKBOUNDS(p,ERR_F) { \
00013   unsigned int rowoffset=(p-img1)-(p-img1)/yInc*yInc; \
00014   if(p<img1 || p>=img1+h*yInc || rowoffset>=w*xInc || rowoffset/xInc*xInc!=rowoffset) { \
00015     cout << "Graphics Bad draw! line:" << __LINE__ << " frame=" << (gen!=NULL?gen->getFrameNumber():0) << ' '  /*<< (void*)p << '-' << (void*)img1 << '='*/ << (int)(p-img1) << " w=" << w << " xInc=" << xInc << " h=" << h << " yInc=" << yInc << endl; \
00016     ERR_F; \
00017   } \
00018 }
00019 
00020 Graphics::Graphics(FilterBankGenerator& fbg, unsigned int layer, unsigned int channel)
00021   : gen(&fbg), genLayer(layer), genChan1(channel), genChan2(channel), genChan3(channel), 
00022     img1(NULL), img2(NULL), img3(NULL), w(0), h(0), xInc(0), yInc(0), color(0, 0, 0) {
00023   updateFBG();
00024 }
00025 
00026 Graphics::Graphics(FilterBankGenerator& fbg, unsigned int layer, unsigned int chan1, unsigned int chan2, unsigned int chan3)
00027   : gen(&fbg), genLayer(layer), genChan1(chan1), genChan2(chan2), genChan3(chan3),
00028     img1(NULL), img2(NULL), img3(NULL), w(0), h(0), xInc(0), yInc(0), color(0, 0, 0) {
00029   updateFBG();
00030 }
00031 
00032 Graphics::Graphics(unsigned char* base, unsigned int width, unsigned int height, unsigned int interval, unsigned int stride)
00033   : gen(NULL), genLayer(), genChan1(), genChan2(), genChan3(),
00034     img1(base), img2(base), img3(base), w(width), h(height), xInc(interval), yInc(stride), color(0, 0, 0) {}
00035 
00036 void Graphics::updateFBG() {
00037   if(gen==NULL)
00038     return;
00039   img1=gen->getImage(genLayer,genChan1);
00040   img2=gen->getImage(genLayer,genChan2);
00041   img3=gen->getImage(genLayer,genChan3);
00042   w=gen->getWidth(genLayer);
00043   h=gen->getHeight(genLayer);
00044   xInc=gen->getIncrement(genLayer);
00045   yInc=gen->getStride(genLayer);
00046 }
00047 
00048 void Graphics::drawRect(int x, int y, int width, int height) {
00049   if(width<0) {
00050     x+=width;
00051     width=-width;
00052   }
00053   if(height<0) {
00054     y+=height;
00055     height=-height;
00056   }
00057   if(x>=(int)w || y>=(int)h || x+width<0 || y+height<0) //completely out of bounds
00058     return;
00059   if(x<0 && y<0 && x+width>=(int)w && y+height>=(int)h) //out of bounds (circumscribed)
00060     return;
00061   unsigned int left=x>0?x:0;
00062   unsigned int top=y>0?y:0;
00063   unsigned int right=( (x+width>=(int)w) ? w : (unsigned int)(x+width)); //not inclusive
00064   unsigned int bot=( (y+height>=(int)h) ? h : (unsigned int)(y+height)); //not inclusive
00065   //left vertical
00066   if(x>=0) {
00067     unsigned int result = top*yInc+left*xInc;
00068     unsigned char* p1=img1+result;
00069     unsigned char* p2=img2+result;
00070     unsigned char* p3=img3+result;
00071     unsigned char* end1=img1+result;
00072     while (p1!=end1) {
00073       CHKBOUNDS(p1,return);
00074       *p1=color.y;
00075       *p2=color.u;
00076       *p3=color.v;
00077       p1+=yInc;
00078       p2+=yInc;
00079       p3+=yInc;
00080     }
00081   }   
00082   //top horizontal
00083   if(y>=0) {
00084     unsigned int result1 = top*yInc+left*xInc;
00085     unsigned int result2 = top*yInc+right*xInc;
00086     unsigned char* p1=img1+result1;
00087     unsigned char* p2=img2+result1;
00088     unsigned char* p3=img3+result1;
00089     unsigned char* end1=img1+result2;
00090     while (p1!=end1) {
00091       CHKBOUNDS(p1,return);
00092       *p1=color.y;
00093       *p2=color.u;
00094       *p3=color.v;
00095       p1+=xInc;
00096       p2+=xInc;
00097       p3+=xInc;
00098     }
00099   }
00100   //right vertical
00101   if(right<w && left!=right) {
00102     unsigned int result1 = top*yInc+right*xInc;
00103     unsigned int result2 = bot*yInc+right*xInc;
00104     unsigned char* p1=img1+result1;
00105     unsigned char* p2=img2+result1;
00106     unsigned char* p3=img3+result1;
00107     unsigned char* end1=img1+result2;
00108     while (p1!=end1) {
00109       CHKBOUNDS(p1,return);
00110       *p1=color.y;
00111       *p2=color.u;
00112       *p3=color.v;
00113       p1+=yInc;
00114       p2+=yInc;
00115       p3+=yInc;
00116     }
00117   }   
00118   //bottom horizontal
00119   if(bot<h && top!=bot) {
00120     unsigned int result1 = bot*yInc+left*xInc;
00121     unsigned int result2 = bot*yInc+right*xInc;
00122     unsigned char* p1=img1+result1;
00123     unsigned char* p2=img2+result1;
00124     unsigned char* p3=img3+result1;
00125     unsigned char* end1=img1+result2;
00126     unsigned char* end2=img2+result2;
00127     unsigned char* end3=img3+result2;
00128     while(p1!=end1 && p2!=end2 && p3!=end3) {
00129       CHKBOUNDS(p1,return);
00130       *p1=color.y;
00131       *p2=color.u;
00132       *p3=color.v;
00133       p1+=xInc;
00134       p2+=xInc;
00135       p3+=xInc;
00136     }
00137   }
00138   //bottom right corner
00139   if(right<w && bot<h) {
00140     unsigned int result = bot*yInc+right*xInc;
00141     unsigned char* p1=img1+result;
00142     unsigned char* p2=img2+result;
00143     unsigned char* p3=img3+result;
00144     CHKBOUNDS(p1,return);
00145     *p1=color.y;
00146     *p2=color.u;
00147     *p3=color.v;
00148     return;
00149   }
00150 }
00151 void Graphics::drawRect(float x, float y, float width, float height) {
00152   unsigned int left,top,right,bot;
00153   getPixelCoordinates(left,top,x,y);
00154   getPixelCoordinates(right,bot,x+width,y+height);
00155   drawRect((int)left,(int)top,(int)(right-left),(int)(bot-top));
00156 }
00157 
00158 /*! @todo I think this could be a little faster by writing two cases -- one that
00159  *  handles mostly-vertical lines, and one that handles mostly-horizontal ones.
00160  *  Then the primary loop could be over integer coordinates along that axis, and
00161  *  only the position along the other axis would have to be calculated as
00162  *  floating point */
00163 void Graphics::drawLine(int ix1, int iy1, int ix2, int iy2) {
00164   // the "right" way, allows full range of unsigned int for width
00165   //if(ix1<0 && ix2<0 || iy1<0 && iy2<0 || ix1>0 && ix2>0 && (unsigned int)ix1>=w && (unsigned int)ix2>=w || iy1>0 && iy2>0 && (unsigned int)iy1>=h && (unsigned int)iy2>=h)
00166   //  return; //completely outside visible region
00167 
00168   // the "realistic way" saves some CPU
00169   if( (ix1<0 && ix2<0) || (iy1<0 && iy2<0) || (ix1>=(int)w && ix2>=(int)w) || (iy1>=(int)h && iy2>=(int)h) )
00170     return; //completely outside visible region
00171 
00172   float x1=ix1, y1=iy1, x2=ix2, y2=iy2;
00173   float width=x2-x1;
00174   float height=y2-y1;
00175   bool clipped=false;
00176   if(width!=0) {
00177     float slope=height/width;
00178     if(x1<x2) {
00179       if(x1<0) {
00180         y1-=x1*slope;
00181         x1=0;
00182         clipped=true;
00183       }
00184       if(x2>=w) {
00185         y2-=(x2-(w-1))*slope;
00186         x2=w-1;
00187         clipped=true;
00188       }
00189     } else {
00190       if(x2<0) {
00191         y2-=x2*slope;
00192         x2=0;
00193         clipped=true;
00194       }
00195       if(x1>=w) {
00196         y1-=(x1-(w-1))*slope;
00197         x1=w-1;
00198         clipped=true;
00199       }
00200     }
00201   }
00202   if(clipped) {
00203     if( (x1<0 && x2<0) || (y1<0 && y2<0) || (x1>=w && x2>=w) || (y1>=h && y2>=h) )
00204       return; //completely outside visible region
00205     clipped=false;
00206   }
00207   if(height!=0) {
00208     float invslope=width/height;
00209     if(y1<y2) {
00210       if(y1<0) {
00211         x1-=y1*invslope;
00212         y1=0;
00213         clipped=true;
00214       }
00215       if(y2>=h) {
00216         x2-=(y2-(h-1))*invslope;
00217         y2=h-1;
00218         clipped=true;
00219       }
00220     } else {
00221       if(y2<0) {
00222         x2-=y2*invslope;
00223         y2=0;
00224         clipped=true;
00225       }
00226       if(y1>=h) {
00227         x1-=(y1-(h-1))*invslope;
00228         y1=h-1;
00229         clipped=true;
00230       }
00231     }
00232   }
00233   if(clipped) {
00234     if((x1<0 && x2<0) || (y1<0 && y2<0) || (x1>=w && x2>=w) || (y1>=h && y2>=h) )
00235       return; //completely outside visible region
00236     clipped=false;
00237   }
00238   width=x2-x1;
00239   height=y2-y1;
00240   int aw=abs((int)width);
00241   int ah=abs((int)height);
00242   int d=aw>ah?aw:ah;
00243   float dx=width/d;
00244   float dy=height/d;
00245   for(float x=x1,y=y1;d>0;d--,x+=dx,y+=dy) {
00246     unsigned int result = ((int)y)*yInc+((int)x)*xInc;
00247     unsigned char* p1=img1+result;
00248     unsigned char* p2=img2+result;
00249     unsigned char* p3=img3+result;
00250     CHKBOUNDS(p1,continue);
00251     *p1=color.y;
00252     *p2=color.u;
00253     *p3=color.v;
00254   }
00255   unsigned int result = ((int)y2)*yInc+((int)x2)*xInc;
00256   unsigned char* p1=img1+result;
00257   unsigned char* p2=img2+result;
00258   unsigned char* p3=img3+result;
00259   CHKBOUNDS(p1,return);
00260   *p1=color.y;
00261   *p2=color.u;
00262   *p3=color.v;
00263 }
00264 void Graphics::drawLine(float x1, float y1, float x2, float y2) {
00265   unsigned int px1,py1,px2,py2;
00266   getPixelCoordinates(px1,py1,x1,y1);
00267   getPixelCoordinates(px2,py2,x2,y2);
00268   drawLine((int)px1,(int)py1,(int)px2,(int)py2);
00269 }
00270 
00271 void Graphics::drawEllipse(int x, int y, float semimajor, float semiminor, AngPi orientation) {
00272    const float cosT = cos(orientation);
00273    const float sinT = sin(orientation);
00274    const float xRange = semimajor;
00275    const float majorSq = xRange * xRange;
00276    const float aspectRatio = semiminor / semimajor;
00277 
00278    for(float xDist = -xRange; xDist <= xRange; xDist += 0.2f) {
00279        const float yRange = sqrt(max(0.f, majorSq - xDist*xDist)) * aspectRatio;
00280        int px = round(x + xDist*cosT + yRange*sinT);
00281        int py = round(y - yRange*cosT + xDist*sinT);
00282        drawPoint(px, py);
00283        px = round(x + xDist*cosT - yRange*sinT);
00284        py = round(y + yRange*cosT + xDist*sinT);
00285        drawPoint(px, py);
00286    }
00287 }
00288 
00289 void Graphics::drawEllipse(float x, float y, float semimajor, float semiminor, AngPi orientation ) {
00290   unsigned int px, py;
00291   getPixelCoordinates(px,py,x,y);
00292   drawEllipse((int)px,(int)py,semimajor,semiminor,orientation);
00293 }
00294 
00295 void Graphics::drawQuarterEllipse(int x, int y, float semimajor, float semiminor, AngPi orientation) {
00296    const float cosT = cos(orientation);
00297    const float sinT = sin(orientation);
00298    const float xmax = abs(semimajor);
00299    const float majorSq = semimajor * semimajor;
00300    const float xsign = semimajor > 0 ? 1 : -1;
00301    const float ysign = semiminor > 0 ? 1 : -1;
00302    const float aspectRatio = abs(semiminor / semimajor);
00303    for (float xval=0; xval <= xmax; xval += 0.1f) {
00304      const float yval = sqrt(max(0.f, majorSq-xval*xval)) * aspectRatio;
00305      int px = round(x + xval*cosT*xsign - yval*sinT*ysign);
00306      int py = round(y + yval*cosT*ysign + xval*sinT*xsign);
00307      drawPoint(px, py);
00308    }
00309 }
00310 
00311 void Graphics::getPixelCoordinates(unsigned int& px, unsigned int& py, float x, float y) const {
00312   if(gen!=NULL) {
00313     gen->getPixelCoordinates(px,py,x,y,genLayer);
00314   } else {
00315     //note width sets the scale for both, so coordinate system is square... is good? I'm up for debate.
00316     px=(unsigned int)((w-1)*(x+1)/2+.5f); //+.5 to round to nearest
00317     float aspect=h/(float)w;
00318     py=(unsigned int)((h-1)*(y+aspect)/(aspect*2)+.5f); //+.5 to round to nearest
00319   }
00320 }
00321   
00322 void Graphics::getRealCoordinates(float& x, float& y, unsigned int px, unsigned int py) const {
00323   if(gen!=NULL) {
00324     gen->getRealCoordinates(x,y,px,py,genLayer);
00325   } else {
00326     //note width sets the scale for both, so coordinate system is square... is good? I'm up for debate.
00327     x=px/(float)(w-1)*2-1;
00328     float aspect=h/(float)w;
00329     y=py/(float)(h-1)*aspect*2-aspect;
00330   }
00331 }
00332 
00333 /*! @file
00334  * @brief 
00335  * @author ejt (Creator)
00336  */

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:41 2016 by Doxygen 1.6.3