00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00115
00116 SCALAR_TYPE scaleFactor = (sqrt(areaContainer)/sqrt(areaSum))*sqrt(occupancyRatio);
00117
00118
00119
00120
00121
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
00142
00143
00144 }
00145
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
00210
00211
00212
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
00233
00234
00235 }
00236
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
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273 static bool PackInt(const std::vector<vcg::Point2i> & sizes,
00274 const vcg::Point2i & max_size,
00275 std::vector<vcg::Point2i> & posiz,
00276 vcg::Point2i & global_size)
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];
00282 int i,j,x,y;
00283
00284 posiz.resize(n,Point2i(-1,-1));
00285 std::vector<int> grid(gridSize,0);
00286
00287 #define Grid(q,w) (grid[(q)+(w)*max_size[0]])
00288
00289
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
00299 j = perm[0];
00300 global_size = sizes[j];
00301 posiz[j] = Point2i(0,0);
00302
00303
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
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];
00324 int sy = sizes[j][1];
00325 assert(sx>0 && sy>0);
00326
00327
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
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)
00353 {
00354 --c;
00355 assert(c>=0 && c<n);
00356 assert(posiz[c][0]!=-1);
00357 x = posiz[c][0] + sizes[c][0];
00358 }
00359 else
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
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];
00420
00421 int i,j,k,x,y;
00422
00423 globalsize.resize(ntexture);
00424
00425 posiz.resize(n);
00426 texin.resize(n);
00427 for(i=0;i<n;i++)
00428 {
00429 posiz[i].X() = -1;
00430 texin[i] = -1;
00431 }
00432
00433 std::vector< std::vector<int> > grid;
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);
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] ||
00450 sizes[perm[0]].Y()>max_size[1] )
00451 return false;
00452
00453 if(n<ntexture)
00454 return false;
00455
00456
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
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();
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
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
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)
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;
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 };
00609 }
00610 #endif