// Polygon.cpp -- classes for colored polygons // // // DESCRIPTION // Draw colored polygons for Mondrian motion test sequences. // For now: rectangles and triangles. // // SEE ALSO // Polygon.h - definition of classes // // Copyright © Daniel Scharstein, 2003. // /////////////////////////////////////////////////////////////////////////// #include "Error.h" #include "Image.h" #include "Color.h" #include "Polygon.h" #include "Utils.h" #include /////////////////////////////////////////////////////////////////////////// // Implementation of CVec2 class void CVec2::randomize(float min, float max) { x = randIn(min, max); y = randIn(min, max); } // swap two vectors void swap(CVec2 &v, CVec2 &w) { float t; t = v.x; v.x = w.x; w.x = t; t = v.y; v.y = w.y; w.y = t; } /////////////////////////////////////////////////////////////////////////// // Drawing helper functions // round and clip to lie within shape (note: loop using "<", not "<=") inline int clipx(float x, CShape sh) { return __max(0, __min(sh.width, ROUND(x))); } inline int clipy(float y, CShape sh) { return __max(0, __min(sh.height, ROUND(y))); } // draw horizontal line inline void drawScanline(CByteImage dst, int y, float fx0, float fx1, CCol color) { CCol *row = (CCol *)&dst.Pixel(0, y, 0); int x0 = clipx(__min(fx0, fx1), dst.Shape()); int x1 = clipx(__max(fx0, fx1) + 1.0f, dst.Shape()); for (int x = x0; x < x1; x++) { row[x].overWriteWith(color); // combine using alpha } } inline void drawPixel(CByteImage dst, int x, int y, CCol color) { CCol *row = (CCol *)&dst.Pixel(0, y, 0); CShape sh=dst.Shape(); if(x<0||x>=sh.width) return; if(y<0||y>=sh.height) return; row[x].overWriteWith(color); // combine using alpha } /////////////////////////////////////////////////////////////////////////// // Implementation of Rectangle class // draw this rectangle at time t // assumes that drawing is done back-to-front void CRect::draw(CByteImage dst, float t) { CShape sh = dst.Shape(); int w = sh.width, h = sh.height, nB = sh.nBands; if (nB != 4) throw CError("CRect::draw: only 4-band (RGBA) images are supported"); CVec2 c0 = p0 + t * vel; CVec2 c1 = c0 + diag; int y0 = clipy(c0.y, sh); int y1 = clipy(c1.y + 1.0f, sh); for (int y = y0; y < y1; y++) { drawScanline(dst, y, c0.x, c1.x, color); } } /////////////////////////////////////////////////////////////////////////// // Implementation of Triangle class // draw this triangle at time t // assumes that drawing is done back-to-front void CTri::draw(CByteImage dst, float t) { CShape sh = dst.Shape(); int w = sh.width, h = sh.height, nB = sh.nBands; if (nB != 4) throw CError("CTri::draw: only 4-band (RGBA) images are supported"); CVec2 c0 = p0 + t * vel; CVec2 c1 = p1 + t * vel; CVec2 c2 = p2 + t * vel; //c0 = p0 + t * CVec2(0, 10); //c1 = c1 + t * CVec2(-2, -10); //c2 = c2 + t * CVec2(-9, 1); // sort vertices from top (c0) to bottom (c2) if (c0.y > c1.y) swap(c0, c1); if (c0.y > c2.y) swap(c0, c2); if (c1.y > c2.y) swap(c1, c2); // top and bottom y coordinates: int y0 = clipy(c0.y + 1.0f, sh); // need to add 1 so don't draw past vertex int y2 = clipy(c2.y + 1.0f, sh); for (int y = y0; y < y2; y++) { float f1, f2, x1, x2; // values for top half of triangle f1 = (y - c0.y) / (c1.y - c0.y); f2 = (y - c0.y) / (c2.y - c0.y); x1 = c0.x + f1 * (c1.x - c0.x); x2 = c0.x + f2 * (c2.x - c0.x); // adjust one side in bottom half of triangle if (y >= c1.y) { f1 = (y - c1.y) / (c2.y - c1.y); x1 = c1.x + f1 * (c2.x - c1.x); } drawScanline(dst, y, x1, x2, color); } } /////////////////////////////////////////////////////////////// //Implementation of the CConvex class CConvex::CConvex(CVec2 ip0, CVec2 idiag, CVec2 ivel, float iz, CCol ic) { p0=ip0; diag=CVec2((float)(int)idiag.x,(float)(int)idiag.y); vel=ivel; z=iz; color=ic; int y=(int)diag.y; int x=(int)diag.x; float min=diag.x/8.0f,max=(7.0f*diag.x)/8.0f,dmax=0,dmin=0; float* mins,*maxes; mins=new float[y]; maxes=new float[y]; mins[0]=min; maxes[0]=max; for(int i=1; i((float)(x)/4.0f)){ dmin-=.05f; } if(max<((float)(3*x)/4.0f)){ dmax+=.05f; } if(max>((float)(15*x)/16.0f)){ dmax-=.05f; } dmax=__min(3,__max(-3,dmax)); dmin=__min(3,__max(-3,dmin)); max+=dmax; min+=dmin; mins[i]=min; maxes[i]=max; } for(int i=0;i=mins[j]&&i<=maxes[j]&&j!=0){ data[i][j]=true; }else{ data[i][j]=false; } } } } //draws the region at time t void CConvex::draw(CByteImage dst, float t) { CShape sh = dst.Shape(); int w = sh.width, h = sh.height, nB = sh.nBands; if (nB != 4) throw CError("CShape::draw: only 4-band (RGBA) images are supported"); CVec2 c0 = p0 + t * vel; CVec2 c1 = c0 + diag; int y0 = clipy(c0.y, sh); int y1 = clipy(c1.y + 1.0f, sh); int y=(int)diag.y; int x=(int)diag.x; for(int i=0;i=0;ret--){ if(data[ret][row]==1) return ret; } return -1; } int CConvex::getMin(int row) { int ret=0; for (;ret