void SPHSystem::sortParticles() { pgrid.reset(); const int neighbors[][3] = { {-1, -1, -1}, {-1, 0, -1}, {-1, 1, -1}, { 0, -1, -1}, { 0, 0, -1}, { 0, 1, -1}, { 1, -1, -1}, { 1, 0, -1}, { 1, 1, -1}, {-1, -1, 0}, {-1, 0, 0}, {-1, 1, 0}, { 0, -1, 0}, { 0, 0, 0}, { 0, 1, 0}, { 1, -1, 0}, { 1, 0, 0}, { 1, 1, 0}, {-1, -1, 1}, {-1, 0, 1}, {-1, 1, 1}, { 0, -1, 1}, { 0, 0, 1}, { 0, 1, 1}, { 1, -1, 1}, { 1, 0, 1}, { 1, 1, 1}, }; for( int i=0;i<p.size();i++ ) { int gx = min(max((int)floor(p[i].x * pgrid.w), 0), pgrid.w-1); int gy = min(max((int)floor(p[i].y * pgrid.h), 0), pgrid.h-1); int gz = min(max((int)floor(p[i].z * pgrid.d), 0), pgrid.d-1); Grid::cell_t& cell = pgrid.getcell(gx, gy, gz); cell.push_back(i); cid[i] = iVec(gx, gy, gz); // determine relevant neighbors nid[i].clear(); nid[i].reserve(27); for(int nidx=0;nidx<27;nidx++) { int nx = gx + neighbors[nidx][0]; int ny = gy + neighbors[nidx][1]; int nz = gz + neighbors[nidx][2]; if( nx >= 0 && nx < pgrid.w && ny >= 0 && ny < pgrid.h && nz >= 0 && nz < pgrid.d ) { nid[i].push_back(nz * pgrid.w * pgrid.h + ny * pgrid.w + nx); } } } }
// Illustrate the use of the fill and fill_n functions. void fill_example () { std::cout << "Illustrate fill function\n"; // Example 1, fill an array with initial values char buffer [100]; char *bufferp = buffer; std::fill (bufferp, (bufferp + 100), '\0'); std::fill_n (bufferp, 10, 'x'); std::cout << buffer << '\n'; // Example 2, use fill to initialize a std::list. std::list<std::string, std::allocator<std::string> > aList; std::fill_n (std::inserter (aList, aList.begin ()), 10, "empty"); std::copy (aList.begin (), aList.end (), str_ostrm_iter (std::cout, " ")); std::cout << '\n'; // Example 3, use fill to overwrite values in a std::list. std::fill (aList.begin (), aList.end (), "full"); std::copy (aList.begin (), aList.end (), str_ostrm_iter (std::cout, " ")); std::cout << '\n'; // Example 4, fill in a portion of a std::list. std::vector<int, std::allocator<int> > iVec (10); std::generate (iVec.begin (), iVec.end (), iotaGen (1)); std::vector<int, std::allocator<int> >::iterator seven = std::find (iVec.begin (), iVec.end (), 7); std::fill (iVec.begin (), seven, 0); std::copy (iVec.begin (), iVec.end (), int_ostrm_iter (std::cout)); std::cout << '\n'; }
// Illustrate the use of the generate and genrate_n functions. void generate_example () { std::cout << "Illustrate generate algorithm\n"; // Example 1, generate a std::list of label numbers. std::list<std::string, std::allocator<std::string> > labelList; std::generate_n (std::inserter (labelList, labelList.begin ()), 4, generateLabel); std::copy (labelList.begin (), labelList.end (), str_ostrm_iter (std::cout, " ")); std::cout << '\n'; // Example 2, generate an arithmetic progression. std::vector<int, std::allocator<int> > iVec (10); std::generate (iVec.begin (), iVec.end (), iotaGen (2)); std::generate_n (iVec.begin (), 5, iotaGen (7)); std::copy (iVec.begin (), iVec.end (), int_ostrm_iter (std::cout, " ")); std::cout << '\n'; }
// Quantization takes place here! bool medianCut::performQuantization(const image& src, image& dest, channel8& mask, palette &thePalette) const { // parameters and const variables const parameters& param = getParameters(); const int imageRows=src.rows(); // number of rows in src const int imageCols=src.columns(); // number of columns in src // resize destination containers dest.resize(imageRows,imageCols,rgbPixel(),false,false); mask.resize(imageRows,imageCols,ubyte(),false,false); // Variables int row,col; // row, column counters int r,g,b; // red,green,blue ivector iVec(3); // int-vector std::list<boxInfo> theLeaves; // list of leaves (tree without root // and nodes) std::list<boxInfo>::iterator splitPos; // position to split std::list<boxInfo>::iterator iter; // iterator for theLeaves // create histogram with desired pre-quantization dimensions from src histogram theHist(3,param.preQuant); const float factor = param.preQuant/256.0f; for (row = 0 ; row < imageRows ; row++) { for (col = 0 ; col < imageCols ; col++) { r = static_cast<int>(src.at( row,col ).getRed() * factor); g = static_cast<int>(src.at( row,col ).getGreen() * factor); b = static_cast<int>(src.at( row,col ).getBlue() * factor); // insert point with quantized color dest.at(row,col).set((r*256+128)/param.preQuant, (g*256+128)/param.preQuant, (b*256+128)/param.preQuant,0); iVec[0] = r; iVec[1] = g; iVec[2] = b; theHist.put(iVec); } } // initialization of first box of list (the whole histogram) boxInfo theBox(rgbPixel(0,0,0), rgbPixel(param.preQuant-1, param.preQuant-1, param.preQuant-1)); computeBoxInfo(theHist,theBox); // return, if desired number of colors smaller than colors in // pre-quantized image if (theBox.colors < param.numberOfColors) { thePalette.resize(theBox.colors,rgbPixel(),false,false); // prepare palette int i = 0; for (r=0;r<param.preQuant;++r) { for (g=0;g<param.preQuant;++g) { for (b=0;b<param.preQuant;++b) { iVec[0] = r; iVec[1] = g; iVec[2] = b; if (theHist.at(iVec) > 0) { thePalette.at(i).set((r*256+128)/param.preQuant, (g*256+128)/param.preQuant, (b*256+128)/param.preQuant); } } } } // use the palette to generate the corresponding channel usePalette colorizer; colorizer.apply(dest,thePalette,mask); return true; } // Push first box into List theLeaves.push_back(theBox); // MAIN LOOP (do this until you have enough leaves (count), or no // splittable boxes (entries)) int count, entries=1; // auxiliary variables for the main loop for (count=1; (count<param.numberOfColors) && (entries!=0); count++) { // find box with largest number of entries from list entries = 0; for (iter = theLeaves.begin() ; iter != theLeaves.end() ; iter++) { if ( (*iter).colorFrequency > entries ) { // Avoid choosing single colors, i.e. unsplittable boxes if ( ((*iter).max.getRed() > (*iter).min.getRed()) || ((*iter).max.getGreen() > (*iter).min.getGreen()) || ((*iter).max.getBlue() > (*iter).min.getBlue()) ) { entries = (*iter).colorFrequency; splitPos = iter; } } } // A splittable box was found. // The iterator "splitPos" indicates its position in the List if (entries >0) { // Determine next axis to split (largest variance) and box dimensions int splitAxis; // split axis indicator if ( ((*splitPos).var[0] >= (*splitPos).var[1]) && ((*splitPos).var[0] >= (*splitPos).var[2]) ) { splitAxis = 0; // red axis } else if ( (*splitPos).var[1] >= (*splitPos).var[2] ) { splitAxis = 1; // green axis } else { splitAxis = 2; // blue axis } int rMax = ((*splitPos).max.getRed()); int rMin = ((*splitPos).min.getRed()); int gMax = ((*splitPos).max.getGreen()); int gMin = ((*splitPos).min.getGreen()); int bMax = ((*splitPos).max.getBlue()); int bMin = ((*splitPos).min.getBlue()); // pass through box along the axis to split bool found; // becomes true when split plane is found int nrOfCols=0; // counter: number of colors of box int prevNrOfCols=0; // forerunner of nrOfCols rgbPixel lower1; // lower pixel from box 1 rgbPixel upper1; // upper pixel from box 1 rgbPixel lower2; // lower pixel from box 2 rgbPixel upper2; // upper pixel from box 2 switch (splitAxis) { case 0: // red axis nrOfCols = 0; for (r = rMin , found = false ; (!found) && (r<=rMax) ; r++) { prevNrOfCols = nrOfCols; for (g = gMin ; g <= gMax ; g++) { for (b=bMin;b<=bMax;b++) { iVec[0] = r; iVec[1] = g; iVec[2] = b; if (theHist.at(iVec) > 0.0) { nrOfCols += static_cast<long int>(theHist.at(iVec)); } } } if ( nrOfCols >= (*splitPos).colorFrequency/2 ) { found=true; } } if (fabs(prevNrOfCols - static_cast<float>((*splitPos).colorFrequency)/2) < fabs(nrOfCols - static_cast<float>((*splitPos).colorFrequency)/2)) { r--; nrOfCols = prevNrOfCols; } // first box lower1.setRed(rMin); lower1.setGreen(gMin); lower1.setBlue(bMin); upper1.setRed(r-1); upper1.setGreen(gMax); upper1.setBlue(bMax); // second box lower2.setRed(r); lower2.setGreen(gMin); lower2.setBlue(bMin); upper2.setRed(rMax); upper2.setGreen(gMax); upper2.setBlue(bMax); break; case 1: // g axis nrOfCols = 0; for (g = gMin , found = false ; (!found) && (g<=gMax) ; g++) { prevNrOfCols = nrOfCols; for (r = rMin ; r <= rMax ; r++) { for (b = bMin ; b <= bMax ; b++) { iVec[0] = r; iVec[1] = g; iVec[2] = b; if (theHist.at(iVec) > 0.0) { nrOfCols += static_cast<long int>(theHist.at(iVec)); } } } if ( nrOfCols >= (*splitPos).colorFrequency/2 ) { found=true; } } if (fabs(prevNrOfCols - static_cast<float>((*splitPos).colorFrequency)/2) < fabs(nrOfCols - static_cast<float>((*splitPos).colorFrequency)/2)) { g--; nrOfCols = prevNrOfCols; } // first box lower1.setRed(rMin); lower1.setGreen(gMin); lower1.setBlue(bMin); upper1.setRed(rMax); upper1.setGreen(g-1); upper1.setBlue(bMax); // second box lower2.setRed(rMin); lower2.setGreen(g); lower2.setBlue(bMin); upper2.setRed(rMax); upper2.setGreen(gMax); upper2.setBlue(bMax); break; case 2: // b axis nrOfCols = 0; for (b = bMin , found = false ; (!found) && (b<=bMax) ; b++) { prevNrOfCols = nrOfCols; for (r = rMin ; r <= rMax ; r++) { for (g = gMin ; g <= gMax ; g++) { iVec[0] = r; iVec[1] = g; iVec[2] = b; if (theHist.at(iVec) > 0.0) { nrOfCols += static_cast<long int>(theHist.at(iVec)); } } } if ( nrOfCols >= (*splitPos).colorFrequency/2 ) { found=true; } } if (fabs(prevNrOfCols - static_cast<float>((*splitPos).colorFrequency)/2) < fabs(nrOfCols - static_cast<float>((*splitPos).colorFrequency)/2)) { b--; nrOfCols = prevNrOfCols; } // first box lower1.setRed(rMin); lower1.setGreen(gMin); lower1.setBlue(bMin); upper1.setRed(rMax); upper1.setGreen(gMax); upper1.setBlue(b-1); // second box lower2.setRed(rMin); lower2.setGreen(gMin); lower2.setBlue(b); upper2.setRed(rMax); upper2.setGreen(gMax); upper2.setBlue(bMax); break; default: break; } // end of switch // compute box info of new boxes and // append both at the end of list theBox.min = lower1; theBox.max = upper1; computeBoxInfo(theHist,theBox); theLeaves.push_back(theBox); theBox.min = lower2; theBox.max = upper2; computeBoxInfo(theHist,theBox); theLeaves.push_back(theBox); // delete splited box from list theLeaves.erase(splitPos); } } // end of for (MAIN LOOP) // compute block histogram and respective color palette thePalette.resize(theLeaves.size()); int i; for (iter = theLeaves.begin() , i=0 ; iter != theLeaves.end() ; iter++ , i++) { // misuse histogram as a look-up-table for (r = (*iter).min.getRed(); r <= (*iter).max.getRed(); r++) { for (g = (*iter).min.getGreen(); g <= (*iter).max.getGreen(); g++) { for (b = (*iter).min.getBlue(); b <= (*iter).max.getBlue(); b++) { iVec[0] = r; iVec[1] = g; iVec[2] = b; theHist.at(iVec) = i; // insert palette-index (refers to // color in palette) } } } // create palette r = (static_cast<int>((*iter).mean[0]*factor)*256+128)/param.preQuant; g = (static_cast<int>((*iter).mean[1]*factor)*256+128)/param.preQuant; b = (static_cast<int>((*iter).mean[2]*factor)*256+128)/param.preQuant; thePalette[i].set(r,g,b,0); // insert color } // create new image with palette and theHist dest.resize(imageRows,imageCols); mask.resize(imageRows,imageCols,0,false,true); // <= 256 colors? then also fill the mask if (thePalette.size() <= 256) { for (row = 0 ; row < imageRows ; row++) { for (col = 0 ; col < imageCols ; col++) { iVec[0] = static_cast<int>(src.at( row,col ).getRed() * factor); iVec[1] = static_cast<int>(src.at( row,col ).getGreen() * factor); iVec[2] = static_cast<int>(src.at( row,col ).getBlue() * factor); i = static_cast<int>(theHist.at( iVec )); dest.at(row,col) = thePalette[i];// insert point with quantized color mask.at(row,col) = i; // insert palette index of quantized color } } } else { for (row = 0 ; row < imageRows ; row++) { for (col = 0 ; col < imageCols ; col++) { iVec[0] = static_cast<int>(src.at( row,col ).getRed() * factor); iVec[1] = static_cast<int>(src.at( row,col ).getGreen() * factor); iVec[2] = static_cast<int>(src.at( row,col ).getBlue() * factor); i = static_cast<int>(theHist.at( iVec )); r = thePalette[i].getRed(); g = thePalette[i].getGreen(); b = thePalette[i].getBlue(); dest.at(row,col).set(r,g,b,0); // insert point with quantized color } } } return true; }
// protected functions void medianCut::computeBoxInfo(const histogram& hist, boxInfo& theBox) const { // boxInfo.min and .max must be specified before entry and histogram // must be valid. Missing information in boxInfo is computed (mean, // var, colorFrequency, colors) and box boundaries (min,max) are set // to the smallest size, that still encloses all entries in the // specified range of the histogram. int rLow=theBox.min.getRed(); int gLow=theBox.min.getGreen(); int bLow=theBox.min.getBlue(); int rUp=theBox.max.getRed(); int gUp=theBox.max.getGreen(); int bUp=theBox.max.getBlue(); int rMin=rUp,rMax=rLow,gMin=gUp,gMax=gLow,bMin=bUp,bMax=bLow; int i=rLow,j=gLow,k=bLow; int freq; ivector iVec(3); double meanR, meanG, meanB, meanSquareR, meanSquareG, meanSquareB; meanR = meanG = meanB = meanSquareR = meanSquareG = meanSquareB = 0; double accu = 0; theBox.colors = 0; for (i=rLow;i<=rUp;i++) { for (j=gLow;j<=gUp;j++) { for (k=bLow;k<=bUp;k++) { iVec[0]=i; iVec[1]=j; iVec[2]=k; if (hist.at(iVec)>0.0f) { if (k<bMin) {bMin=k;} if (k>bMax) {bMax=k;} if (j<gMin) {gMin=j;} if (j>gMax) {gMax=j;} if (i<rMin) {rMin=i;} if (i>rMax) {rMax=i;} freq = static_cast<const int>(hist.at(iVec)); meanR += freq * i; meanG += freq * j; meanB += freq * k; meanSquareR += freq *i*i; meanSquareG += freq *j*j; meanSquareB += freq *k*k; accu += freq; // Count number of distinct colors theBox.colors++; } } } } meanR /= accu; meanG /= accu; meanB /= accu; meanSquareR /= accu; meanSquareG /= accu; meanSquareB /= accu; // Set minimum and maximum enclosing bounds theBox.min.setRed(rMin); theBox.min.setGreen(gMin); theBox.min.setBlue(bMin); theBox.max.setRed(rMax); theBox.max.setGreen(gMax); theBox.max.setBlue(bMax); // Set number of entries inside box theBox.colorFrequency = static_cast<long int>(accu); // set mean and variance inside box theBox.mean[0] = meanR; theBox.mean[1] = meanG; theBox.mean[2] = meanB; theBox.var[0] = meanSquareR - meanR*meanR; theBox.var[1] = meanSquareG - meanG*meanG; theBox.var[2] = meanSquareB - meanB*meanB; }