rect_packer.h
Go to the documentation of this file.
00001 /****************************************************************************
00002 * VCGLib                                                            o o     *
00003 * Visual and Computer Graphics Library                            o     o   *
00004 *                                                                _   O  _   *
00005 * Copyright(C) 2004                                                \/)\/    *
00006 * Visual Computing Lab                                            /\/|      *
00007 * ISTI - Italian National Research Council                           |      *
00008 *                                                                    \      *
00009 * All rights reserved.                                                      *
00010 *                                                                           *
00011 * This program is free software; you can redistribute it and/or modify      *
00012 * it under the terms of the GNU General Public License as published by      *
00013 * the Free Software Foundation; either version 2 of the License, or         *
00014 * (at your option) any later version.                                       *
00015 *                                                                           *
00016 * This program is distributed in the hope that it will be useful,           *
00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
00019 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
00020 * for more details.                                                         *
00021 *                                                                           *
00022 ****************************************************************************/
00023 #ifndef __VCG_RectPacker__
00024 #define __VCG_RectPacker__
00025 
00026 #include <stdio.h>
00027 #include <assert.h>
00028 #include <algorithm>
00029 #include <vector>
00030 #include <ctime>
00031 #include <vcg/space/point2.h>
00032 #include <vcg/math/similarity2.h>
00033 
00034 namespace vcg
00035 {
00036 
00037 template <class SCALAR_TYPE>
00038 class RectPacker
00039 {
00040   typedef typename vcg::Box2<SCALAR_TYPE> Box2x;
00041   typedef typename vcg::Point2<SCALAR_TYPE> Point2x;
00042   typedef typename vcg::Similarity2<SCALAR_TYPE> Similarity2x;
00043 public:
00044   class Stat
00045   {
00046   public:
00047     void clear() {
00048       pack_attempt_num=0;
00049       pack_attempt_time=0;
00050       pack_total_time=0;
00051     }
00052 
00053     int pack_attempt_num;
00054     float pack_attempt_time;
00055     float pack_total_time;
00056   };
00057 
00058 
00059   static Stat &stat() { static Stat _s; return _s; }
00060 
00061 
00062   static  bool Pack(const std::vector<Box2x > & rectVec,  
00063                     const Point2i containerSizeX,         
00064                     std::vector<Similarity2x> &trVec,     
00065                     Point2x &coveredContainer)            
00066 {
00067   float bestOccupancy=0,currOccupancy=0.1f;
00068   std::vector<Similarity2x> currTrVec;
00069   Point2x currCovered;
00070   int start_t=clock();
00071   stat().clear();
00072   bool ret=true;
00073   while(ret)
00074   {
00075     stat().pack_attempt_num++;
00076     int t0=clock();
00077     ret=PackOccupancy(rectVec,containerSizeX,currOccupancy,currTrVec,currCovered);
00078     stat().pack_attempt_time = float(clock()-t0)/float(CLOCKS_PER_SEC);
00079     if(ret)
00080     {
00081       assert(currOccupancy>bestOccupancy);
00082       bestOccupancy = currOccupancy;
00083       trVec=currTrVec;
00084       coveredContainer=currCovered;
00085       currOccupancy = (2.0f*currOccupancy+1.0f)/3.0f;
00086     }
00087   }
00088   stat().pack_total_time=float(clock()-start_t)/float(CLOCKS_PER_SEC);;
00089   if(bestOccupancy>0) return true;
00090   return false;
00091 }
00092 
00093 
00094 static  bool PackOccupancy(const std::vector<Box2x > & rectVec,  
00095                   const Point2i containerSizeX,         
00096                   const SCALAR_TYPE occupancyRatio,     
00097                   std::vector<Similarity2x> &trVec,     
00098                   Point2x &coveredContainer)            
00099   {
00100     Point2x maxSize(0,0);
00101     const vcg::Point2i containerSize=Point2i::Construct(containerSizeX);
00102     SCALAR_TYPE areaSum=0;
00103     SCALAR_TYPE areaContainer = containerSize[0]*containerSize[1];
00104 
00105     for (size_t i=0;i<rectVec.size();++i)
00106     {
00107       maxSize[0]=std::max(maxSize[0],rectVec[i].DimX());
00108       maxSize[1]=std::max(maxSize[1],rectVec[i].DimY());
00109       areaSum += rectVec[i].DimX() * rectVec[i].DimY();
00110     }
00111 
00112     Point2x scaleFactor2(containerSize[0]/maxSize[0],containerSize[1]/maxSize[1]);
00113 
00114 //    SCALAR_TYPE unitScaleFactor = std::min(scaleFactor2[0],scaleFactor2[1]);
00115 
00116     SCALAR_TYPE scaleFactor = (sqrt(areaContainer)/sqrt(areaSum))*sqrt(occupancyRatio);
00117 
00118 //    printf("unitScaleFactor %6.3f\n",unitScaleFactor);
00119 //    printf("scaleFactor %6.3f\n",scaleFactor);
00120 //    printf("areaContainer %6.3f\n",areaContainer);
00121 //    printf("areaSum %6.3f\n",areaSum);
00122     std::vector<vcg::Point2i> sizes(rectVec.size());
00123     for (size_t i=0;i<rectVec.size();++i)
00124     {
00125       sizes[i][0]=ceil(rectVec[i].DimX()*scaleFactor);
00126       sizes[i][1]=ceil(rectVec[i].DimY()*scaleFactor);
00127     }
00128 
00129     std::vector<vcg::Point2i> posiz;
00130     vcg::Point2i global_size;
00131 
00132     bool res = PackInt(sizes,containerSize,posiz,global_size);
00133     if(!res) return false;
00134 
00135     trVec.resize(rectVec.size());
00136     for (size_t i=0;i<rectVec.size();++i)
00137     {
00138       trVec[i].tra = Point2x::Construct(posiz[i]) - rectVec[i].min*scaleFactor;
00139       trVec[i].sca = scaleFactor;
00140 
00141 //      qDebug("rectVec[ %5i ] (%6.2f %6.2f) - (%6.2f %6.2f) : SizeI (%6i %6i) Posiz (%6i %6i)",i,
00142 //             rectVec[i].min[0],rectVec[i].min[1],  rectVec[i].max[0],rectVec[i].max[1],
00143 //             sizes[i][0],sizes[i][1],  posiz[i][0],posiz[i][1]);
00144     }
00145 //    printf("globalSize (%6i %6i)\n",global_size[0],global_size[1]);
00146     coveredContainer = Point2x::Construct(global_size);
00147     return true;
00148   }
00149 static  bool PackMulti(const std::vector<Box2x > & rectVec,  
00150                   const Point2i containerSizeI,         
00151                   const int containerNum,
00152                   std::vector<Similarity2x> &trVec,     
00153                   std::vector<int> &indVec,
00154                   std::vector<Point2x> &coveredContainer)            
00155 {
00156   float bestOccupancy=0,currOccupancy=0.1f;
00157   std::vector<Similarity2x> currTrVec;
00158   std::vector<int> currIndVec;
00159   std::vector<Point2x> currCovered;
00160   int start_t=clock();
00161   stat().clear();
00162   bool ret=true;
00163   while(ret && bestOccupancy < 0.99f)
00164   {
00165     stat().pack_attempt_num++;
00166     int t0=clock();
00167     ret=PackOccupancyMulti(rectVec,containerSizeI,containerNum,currOccupancy,currTrVec, currIndVec, currCovered);
00168     stat().pack_attempt_time = float(clock()-t0)/float(CLOCKS_PER_SEC);
00169     if(ret)
00170     {
00171       printf("CurrOccupancy %f\n",currOccupancy);
00172       assert(currOccupancy>bestOccupancy);
00173       bestOccupancy = currOccupancy;
00174       trVec=currTrVec;
00175       indVec=currIndVec;
00176       coveredContainer=currCovered;
00177       currOccupancy = (2.0*currOccupancy+1.0)/3.0;
00178     }
00179   }
00180   stat().pack_total_time=float(clock()-start_t)/float(CLOCKS_PER_SEC);;
00181   if(bestOccupancy>0) return true;
00182   return false;
00183 }
00184 
00185 static  bool PackOccupancyMulti(const std::vector<Box2x > & rectVec,  
00186                                 const Point2i containerSizeX,         
00187                                 const int containerNum,
00188                                 const SCALAR_TYPE occupancyRatio,     
00189                                 std::vector<Similarity2x> &trVec,     
00190                                 std::vector<int> &indVec,
00191                                 std::vector<Point2x> &coveredContainer)            
00192 {
00193     Point2x maxSize(0,0);
00194     const vcg::Point2i containerSize=Point2i::Construct(containerSizeX);
00195     SCALAR_TYPE areaSum=0;
00196     SCALAR_TYPE areaContainer = containerSize[0]*containerSize[1]*containerNum;
00197 
00198     for (size_t i=0;i<rectVec.size();++i)
00199     {
00200       maxSize[0]=std::max(maxSize[0],rectVec[i].DimX());
00201       maxSize[1]=std::max(maxSize[1],rectVec[i].DimY());
00202       areaSum += rectVec[i].DimX() * rectVec[i].DimY();
00203     }
00204 
00205     Point2x scaleFactor2(containerSize[0]/maxSize[0],containerSize[1]/maxSize[1]);
00206 
00207     SCALAR_TYPE scaleFactor = (sqrt(areaContainer)/sqrt(areaSum))*sqrt(occupancyRatio);
00208 
00209 //    printf("unitScaleFactor %6.3f\n",unitScaleFactor);
00210 //    printf("scaleFactor %6.3f\n",scaleFactor);
00211 //    printf("areaContainer %6.3f\n",areaContainer);
00212 //    printf("areaSum %6.3f\n",areaSum);
00213     std::vector<vcg::Point2i> sizes(rectVec.size());
00214     for (size_t i=0;i<rectVec.size();++i)
00215     {
00216       sizes[i][0]=ceil(rectVec[i].DimX()*scaleFactor);
00217       sizes[i][1]=ceil(rectVec[i].DimY()*scaleFactor);
00218     }
00219 
00220     std::vector<vcg::Point2i> posiz;
00221     std::vector<vcg::Point2i> global_sizeVec;
00222 
00223     bool res = PackIntMulti(sizes,containerNum,containerSize,posiz,indVec,global_sizeVec);
00224     if(!res) return false;
00225 
00226     trVec.resize(rectVec.size());
00227     for (size_t i=0;i<rectVec.size();++i)
00228     {
00229       trVec[i].tra = Point2x::Construct(posiz[i]) - rectVec[i].min*scaleFactor;
00230       trVec[i].sca = scaleFactor;
00231 
00232 //      qDebug("rectVec[ %5i ] (%6.2f %6.2f) - (%6.2f %6.2f) : SizeI (%6i %6i) Posiz (%6i %6i)",i,
00233 //             rectVec[i].min[0],rectVec[i].min[1],  rectVec[i].max[0],rectVec[i].max[1],
00234 //             sizes[i][0],sizes[i][1],  posiz[i][0],posiz[i][1]);
00235     }
00236 //    printf("globalSize (%6i %6i)\n",global_size[0],global_size[1]);
00237     coveredContainer.resize(containerNum);
00238     for(int i=0;i<containerNum;++i)
00239       coveredContainer[i] = Point2x::Construct(global_sizeVec[i]);
00240     return true;
00241   }
00242 
00243 private:
00244 
00245 
00246 class ComparisonFunctor
00247 {
00248 public:
00249   const std::vector<vcg::Point2i> & v;
00250   inline ComparisonFunctor( const std::vector<vcg::Point2i> & nv ) : v(nv) { }
00251 
00252   inline bool operator() ( int a, int b )
00253   {
00254     const Point2i &va=v[a];
00255     const Point2i &vb=v[b];
00256 
00257     return       (va[1]!=vb[1])?(va[1]>vb[1]):
00258                 (va[0]>vb[0]);
00259   }
00260 };
00261 
00262 
00263 /* This is the low level function that packs a set of int rects onto a grid.
00264 
00265    Based on the criptic code written by Claudio Rocchini
00266 
00267    Greedy algorithm.
00268    Sort the rect according their height (larger first)
00269    and then place them in the position that minimize the area of the bbox of all the placed rectangles
00270 
00271    To efficiently skip occupied areas it fills the grid with the id of the already placed rectangles.
00272   */
00273 static bool PackInt(const std::vector<vcg::Point2i> & sizes, // the sizes of the rect to be packed
00274                     const vcg::Point2i & max_size,           // the size of the container
00275                     std::vector<vcg::Point2i> & posiz,       // the found positionsof each rect
00276                     vcg::Point2i & global_size)              // the size of smallest rect covering all the packed rect
00277 {
00278   int n = (int)(sizes.size());
00279   assert(n>0 && max_size[0]>0 && max_size[1]>0);
00280 
00281   int gridSize = max_size[0]*max_size[1];               // Size dell griglia
00282   int i,j,x,y;
00283 
00284   posiz.resize(n,Point2i(-1,-1));
00285   std::vector<int> grid(gridSize,0);                    // Creazione griglia
00286 
00287   #define Grid(q,w)     (grid[(q)+(w)*max_size[0]])
00288 
00289   // Build a permutation that keeps the reordiering of the sizes vector according to their width
00290   std::vector<int> perm(n);
00291   for(i=0;i<n;i++) perm[i] = i;
00292   ComparisonFunctor cmp(sizes);
00293   sort(perm.begin(),perm.end(),cmp);
00294 
00295   if(sizes[perm[0]][0]>max_size[0] || sizes[perm[0]][1]>max_size[1] )
00296     return false;
00297 
00298   // Posiziono il primo
00299   j = perm[0];
00300   global_size = sizes[j];
00301   posiz[j] = Point2i(0,0);
00302 
00303   // Fill the grid with the id(+1) of the first
00304   for(y=0;y<global_size[1];y++)
00305     for(x=0;x<global_size[0];x++)
00306     {
00307       assert(x>=0 && x<max_size[0]);
00308       assert(y>=0 && y<max_size[1]);
00309         grid[x+y*max_size[0]] = j+1;
00310     }
00311 
00312   // Posiziono tutti gli altri
00313   for(i=1;i<n;++i)
00314   {
00315         j = perm[i];
00316     assert(j>=0 && j<n);
00317         assert(posiz[j][0]==-1);
00318 
00319     int bestx,besty,bestsx,bestsy,bestArea;
00320 
00321     bestArea = -1;
00322 
00323     int sx = sizes[j][0];       // Pe comodita' mi copio la dimensione
00324     int sy = sizes[j][1];
00325     assert(sx>0 &&  sy>0);
00326 
00327     // Calcolo la posizione limite
00328     int lx = std::min(global_size[0],max_size[0]-sx);
00329     int ly = std::min(global_size[1],max_size[1]-sy);
00330 
00331     assert(lx>0 && ly>0);
00332 
00333     int finterior = 0;
00334 
00335         for(y=0;y<=ly;y++)
00336                 {
00337           for(x=0;x<=lx;)
00338                         {
00339                                 int px;
00340                 int c = Grid(x,y+sy-1);
00341                 // Intersection check
00342                 if(!c) c = Grid(x+sx-1,y+sy-1);
00343                                 if(!c)
00344                                 {
00345                                         for(px=x;px<x+sx;px++)
00346                                         {
00347                                                 c = Grid(px,y);
00348                                                 if(c) break;
00349                                         }
00350                                 }
00351 
00352                                 if(c)   // Salto il rettangolo
00353                                 {
00354                   --c;  // we store id+1...
00355                   assert(c>=0 && c<n);
00356                                         assert(posiz[c][0]!=-1);
00357                                         x = posiz[c][0] + sizes[c][0];
00358                                 }
00359                 else // x,y are an admissible position where we can put the rectangle
00360                                 {
00361                   int nsx = std::max(global_size[0],x+sx);
00362                   int nsy = std::max(global_size[1],y+sy);
00363                   int area   = nsx*nsy;
00364 
00365                   if(bestArea==-1 || bestArea>area)
00366                                         {
00367                                                 bestx  = x;
00368                                                 besty  = y;
00369                                                 bestsx = nsx;
00370                                                 bestsy = nsy;
00371                         bestArea  = area;
00372                                                 if( bestsx==global_size[0] && bestsy==global_size[1] )
00373                                                         finterior = 1;
00374                                         }
00375                                         break;
00376                                 }
00377                                 if(finterior) break;
00378                         }
00379                         if( finterior ) break;
00380                 }
00381 
00382         if(bestArea==-1)
00383                 {
00384                         return false;
00385                 }
00386 
00387                 posiz[j][0] = bestx;
00388                 posiz[j][1] = besty;
00389                 global_size[0] = bestsx;
00390                 global_size[1] = bestsy;
00391                 for(y=posiz[j][1];y<posiz[j][1]+sy;y++)
00392                         for(x=posiz[j][0];x<posiz[j][0]+sx;x++)
00393                         {
00394                 assert(x>=0 && x<max_size[0]);
00395                 assert(y>=0 && y<max_size[1]);
00396                                 grid[x+y*max_size[0]] = j+1;
00397                         }
00398         }
00399 
00400 #undef Grid
00401 
00402         return true;
00403 }
00404 
00405 // Versione multitexture
00406 static bool PackIntMulti( const std::vector<Point2i> & sizes,
00407                           const int ntexture,
00408                           const vcg::Point2i & max_size,
00409                           std::vector<Point2i> & posiz,
00410                           std::vector<int> & texin,
00411                           std::vector<Point2i> & globalsize  )
00412 {
00413   int n = sizes.size();
00414   assert(n>0);
00415   assert(max_size[0]>0);
00416   assert(max_size[1]>0);
00417 
00418 
00419   int gdim = max_size[0]*max_size[1];           // Size dell griglia
00420 
00421   int i,j,k,x,y;
00422 
00423   globalsize.resize(ntexture);          // creazione globalsize
00424 
00425   posiz.resize(n);
00426   texin.resize(n);
00427   for(i=0;i<n;i++)                                      // Azzero le posizioni e indici
00428   {
00429     posiz[i].X() = -1;
00430     texin[i]    = -1;
00431   }
00432 
00433   std::vector< std::vector<int> > grid;                 // Creazione griglie
00434   grid.resize(ntexture);
00435   for(k=0;k<ntexture;++k)
00436   {
00437     grid[k].resize(gdim);
00438     for(i=0;i<gdim;++i)
00439       grid[k][i] = 0;
00440   }
00441 
00442 #define Grid(k,q,w)     (grid[k][(q)+(w)*max_size[0]])
00443 
00444   std::vector<int> perm(n);                     // Creazione permutazione
00445   for(i=0;i<n;i++) perm[i] = i;
00446   ComparisonFunctor conf(sizes);
00447   sort(perm.begin(),perm.end(),conf);
00448 
00449   if(sizes[perm[0]].X()>max_size[0] ||  // Un pezzo piu' grosso del contenitore
00450      sizes[perm[0]].Y()>max_size[1] )
00451     return false;
00452 
00453   if(n<ntexture)                                                // Piu' contenitore che pezzi
00454     return false;
00455 
00456   // Posiziono i primi
00457   for(k=0;k<ntexture;++k)
00458   {
00459     j = perm[k];
00460     globalsize[k].X() = sizes[j].X();
00461     globalsize[k].Y() = sizes[j].Y();
00462     posiz[j].X() = 0;
00463     posiz[j].Y() = 0;
00464     texin[j]     = k;
00465     for(y=0;y<globalsize[k].Y();y++)
00466       for(x=0;x<globalsize[k].X();x++)
00467       {
00468         assert(x>=0);
00469         assert(x<max_size[0]);
00470         assert(y>=0);
00471         assert(y<max_size[1]);
00472         Grid(k,x,y) = j+1;
00473       }
00474   }
00475 
00476   // Posiziono tutti gli altri
00477   for(i=ntexture;i<n;++i)
00478   {
00479     j = perm[i];
00480     assert(j>=0);
00481     assert(j<n);
00482     assert(posiz[j].X()==-1);
00483 
00484 
00485     int sx = sizes[j].X();      // Pe comodita' mi copio la dimensione
00486     int sy = sizes[j].Y();
00487     assert(sx>0);
00488     assert(sy>0);
00489 
00490 
00491     int gbestx,gbesty,gbestsx,gbestsy,gbestk;
00492     int gbesta = -1;
00493 
00494     for(k=0;k<ntexture;++k)
00495     {
00496       int bestx,besty,bestsx,bestsy,besta;
00497       int starta;
00498 
00499       besta = -1;
00500 
00501       // Calcolo la posizione limite
00502       int lx = std::min(globalsize[k].X(),max_size[0]-sx);
00503       int ly = std::min(globalsize[k].Y(),max_size[1]-sy);
00504 
00505       starta = globalsize[k].X()*globalsize[k].Y();
00506 
00507       assert(lx>0);
00508       assert(ly>0);
00509 
00510       int finterior = 0;
00511 
00512       for(y=0;y<=ly;y++)
00513       {
00514         for(x=0;x<=lx;)
00515         {
00516           int px;
00517           int c;
00518           // Controllo intersezione
00519           c = Grid(k,x,y+sy-1);
00520           if(!c) c = Grid(k,x+sx-1,y+sy-1);
00521           if(!c)
00522           {
00523             for(px=x;px<x+sx;px++)
00524             {
00525               c = Grid(k,px,y);
00526               if(c) break;
00527             }
00528           }
00529 
00530           if(c) // Salto il rettangolo
00531           {
00532             --c;
00533             assert(c>=0);
00534             assert(c<n);
00535             assert(posiz[c].X()!=-1);
00536             x = posiz[c].X() + sizes[c].X();
00537           }
00538           else
00539           {
00540             int nsx = std::max(globalsize[k].X(),x+sx);
00541             int nsy = std::max(globalsize[k].Y(),y+sy);
00542             int a   = nsx*nsy;
00543 
00544             if(besta==-1 || besta>a)
00545             {
00546               bestx  = x;
00547               besty  = y;
00548               bestsx = nsx;
00549               bestsy = nsy;
00550               besta  = a;
00551               if( bestsx==globalsize[k].X() && bestsy==globalsize[k].Y() )
00552                 finterior = 1;
00553             }
00554             break;
00555           }
00556           if(finterior) break;
00557         }
00558         if( finterior ) break;
00559       }
00560 
00561       if(besta==-1) continue;           // non c'e' spazio
00562 
00563       besta -= starta;
00564 
00565       if(gbesta==-1 || gbesta>besta)
00566       {
00567         gbesta  = besta;
00568         gbestx  = bestx;
00569         gbesty  = besty;
00570         gbestsx = bestsx;
00571         gbestsy = bestsy;
00572         gbestk  = k;
00573       }
00574     }
00575 
00576     if(gbesta==-1)
00577     {
00578       return false;
00579     }
00580 
00581     assert(gbestx>=0);
00582     assert(gbesty>=0);
00583     assert(gbestk>=0);
00584     assert(gbestx<=max_size[0]);
00585     assert(gbesty<=max_size[1]);
00586     assert(gbestk<ntexture);
00587 
00588     posiz[j].X() = gbestx;
00589     posiz[j].Y() = gbesty;
00590     texin[j]     = gbestk;
00591     globalsize[gbestk].X() = gbestsx;
00592     globalsize[gbestk].Y() = gbestsy;
00593     for(y=posiz[j].Y();y<posiz[j].Y()+sy;y++)
00594       for(x=posiz[j].X();x<posiz[j].X()+sx;x++)
00595       {
00596         assert(x>=0);
00597         assert(x<max_size[0]);
00598         assert(y>=0);
00599         assert(y<max_size[1]);
00600         Grid(gbestk,x,y) = j+1;
00601       }
00602   }
00603 #undef Grid
00604 
00605   return true;
00606 }
00607 
00608 }; // end class
00609 } // end namespace vcg
00610 #endif


shape_reconstruction
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:35:05