/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004-2016 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef __VCG_RectPacker__ #define __VCG_RectPacker__ #include #include #include #include #include #include #include namespace vcg { template class RectPacker { typedef typename vcg::Box2 Box2x; typedef typename vcg::Point2 Point2x; typedef typename vcg::Similarity2 Similarity2x; public: class Stat { public: void clear() { pack_attempt_num=0; pack_attempt_time=0; pack_total_time=0; } int pack_attempt_num; float pack_attempt_time; float pack_total_time; }; static Stat &stat() { static Stat _s; return _s; } static bool Pack(const std::vector & rectVec, /// the set of rectangles that have to be packed (generic floats, no req.) const Point2i containerSizeX, /// the size of the container where they has to be fitted (usually in pixel size) std::vector &trVec, /// the result, a set of similarity transformation that have to be applied to the rect to get their position Point2x &coveredContainer) /// the sub portion of the container covered by the solution. { float bestOccupancy=0,currOccupancy=0.1f; std::vector currTrVec; Point2x currCovered; int start_t=clock(); stat().clear(); bool ret=true; while(ret) { stat().pack_attempt_num++; int t0=clock(); ret=PackOccupancy(rectVec,containerSizeX,currOccupancy,currTrVec,currCovered); stat().pack_attempt_time = float(clock()-t0)/float(CLOCKS_PER_SEC); if(ret) { assert(currOccupancy>bestOccupancy); bestOccupancy = currOccupancy; trVec=currTrVec; coveredContainer=currCovered; currOccupancy = (2.0f*currOccupancy+1.0f)/3.0f; } } stat().pack_total_time=float(clock()-start_t)/float(CLOCKS_PER_SEC);; if(bestOccupancy>0) return true; return false; } static bool PackOccupancy(const std::vector & rectVec, /// the set of rectangles that have to be packed const Point2i containerSizeX, /// the size of the container where they has to be fitted (usually in pixel size) const SCALAR_TYPE occupancyRatio, /// the expected percentage of the container that has to be covered std::vector &trVec, /// the result, a set of similarity transformation that have to be applied to the rect to get their position Point2x &coveredContainer) /// the sub portion of the container covered by the solution. { Point2x maxSize(0,0); const vcg::Point2i containerSize=Point2i::Construct(containerSizeX); SCALAR_TYPE areaSum=0; SCALAR_TYPE areaContainer = containerSize[0]*containerSize[1]; for (size_t i=0;i sizes(rectVec.size()); for (size_t i=0;i posiz; vcg::Point2i global_size; bool res = PackInt(sizes,containerSize,posiz,global_size); if(!res) return false; trVec.resize(rectVec.size()); for (size_t i=0;i & rectVec, /// the set of rectangles that have to be packed (generic floats, no req.) const Point2i containerSizeI, /// the size of the container where they has to be fitted (usually in pixel size) const int containerNum, std::vector &trVec, /// the result, a set of similarity transformation that have to be applied to the rect to get their position std::vector &indVec, std::vector &coveredContainer) /// the sub portion of the container covered by the solution. { float bestOccupancy=0,currOccupancy=0.1f; std::vector currTrVec; std::vector currIndVec; std::vector currCovered; int start_t=clock(); stat().clear(); bool ret=true; while(ret && bestOccupancy < 0.99f) { stat().pack_attempt_num++; int t0=clock(); ret=PackOccupancyMulti(rectVec,containerSizeI,containerNum,currOccupancy,currTrVec, currIndVec, currCovered); stat().pack_attempt_time = float(clock()-t0)/float(CLOCKS_PER_SEC); if(ret) { printf("CurrOccupancy %f\n",currOccupancy); assert(currOccupancy>bestOccupancy); bestOccupancy = currOccupancy; trVec=currTrVec; indVec=currIndVec; coveredContainer=currCovered; currOccupancy = (2.0*currOccupancy+1.0)/3.0; } } stat().pack_total_time=float(clock()-start_t)/float(CLOCKS_PER_SEC);; if(bestOccupancy>0) return true; return false; } static bool PackOccupancyMulti(const std::vector & rectVec, /// the set of rectangles that have to be packed const Point2i containerSizeX, /// the size of the container where they has to be fitted (usually in pixel size) const int containerNum, const SCALAR_TYPE occupancyRatio, /// the expected percentage of the container that has to be covered std::vector &trVec, /// the result, a set of similarity transformation that have to be applied to the rect to get their position std::vector &indVec, std::vector &coveredContainer) /// the sub portion of the container covered by the solution. { Point2x maxSize(0,0); const vcg::Point2i containerSize=Point2i::Construct(containerSizeX); SCALAR_TYPE areaSum=0; SCALAR_TYPE areaContainer = containerSize[0]*containerSize[1]*containerNum; for (size_t i=0;i sizes(rectVec.size()); for (size_t i=0;i posiz; std::vector global_sizeVec; bool res = PackIntMulti(sizes,containerNum,containerSize,posiz,indVec,global_sizeVec); if(!res) return false; trVec.resize(rectVec.size()); for (size_t i=0;i & sizes, // the sizes of the rect to be packed const vcg::Point2i & max_size, // the size of the container std::vector & posiz, // the found positionsof each rect vcg::Point2i & global_size) // the size of smallest rect covering all the packed rect { int n = (int)(sizes.size()); assert(n>0 && max_size[0]>0 && max_size[1]>0); int gridSize = max_size[0] * max_size[1]; // Size dell griglia int i, j, x, y; posiz.resize(n, Point2i(-1, -1)); std::vector grid(gridSize, 0); // Creazione griglia #define Grid(q,w) (grid[(q)+(w)*max_size[0]]) // Build a permutation that keeps the reordiering of the sizes vector according to their width std::vector perm(n); for (i = 0; imax_size[0] || sizes[perm[0]][1]>max_size[1]) return false; // Posiziono il primo j = perm[0]; global_size = sizes[j]; posiz[j] = Point2i(0, 0); // Fill the grid with the id(+1) of the first for (y = 0; y= 0 && x= 0 && y= 0 && j0 && sy>0); // Calcolo la posizione limite int lx = std::min(global_size[0], max_size[0] - sx); int ly = std::min(global_size[1], max_size[1] - sy); assert(lx>0 && ly>0); int finterior = 0; for (y = 0; y <= ly; y++) { for (x = 0; x <= lx;) { int px; int c = Grid(x, y + sy - 1); // Intersection check if (!c) c = Grid(x + sx - 1, y + sy - 1); if (!c) { for (px = x; px= 0 && carea) { bestx = x; besty = y; bestsx = nsx; bestsy = nsy; bestArea = area; if (bestsx == global_size[0] && bestsy == global_size[1]) finterior = 1; } break; } if (finterior) break; } if (finterior) break; } if (bestArea == -1) { return false; } posiz[j][0] = bestx; posiz[j][1] = besty; global_size[0] = bestsx; global_size[1] = bestsy; for (y = posiz[j][1]; y= 0 && x= 0 && y & v; inline ComparisonFunctor( const std::vector & nv ) : v(nv) { } inline bool operator() ( int a, int b ) { const Point2i &va=v[a]; const Point2i &vb=v[b]; return (va[1]!=vb[1])?(va[1]>vb[1]): (va[0]>vb[0]); } }; // Versione multitexture static bool PackIntMulti( const std::vector & sizes, const int ntexture, const vcg::Point2i & max_size, std::vector & posiz, std::vector & texin, std::vector & globalsize ) { int n = sizes.size(); assert(n>0); assert(max_size[0]>0); assert(max_size[1]>0); int gdim = max_size[0]*max_size[1]; // Size dell griglia int i,j,k,x,y; globalsize.resize(ntexture); // creazione globalsize posiz.resize(n); texin.resize(n); for(i=0;i > grid; // Creazione griglie grid.resize(ntexture); for(k=0;k perm(n); // Creazione permutazione for(i=0;imax_size[0] || // Un pezzo piu' grosso del contenitore sizes[perm[0]].Y()>max_size[1] ) return false; if(n=0); assert(x=0); assert(y=0); assert(j0); assert(sy>0); int gbestx,gbesty,gbestsx,gbestsy,gbestk; int gbesta = -1; for(k=0;k0); assert(ly>0); int finterior = 0; for(y=0;y<=ly;y++) { for(x=0;x<=lx;) { int px; int c; // Controllo intersezione c = Grid(k,x,y+sy-1); if(!c) c = Grid(k,x+sx-1,y+sy-1); if(!c) { for(px=x;px=0); assert(ca) { bestx = x; besty = y; bestsx = nsx; bestsy = nsy; besta = a; if( bestsx==globalsize[k].X() && bestsy==globalsize[k].Y() ) finterior = 1; } break; } if(finterior) break; } if( finterior ) break; } if(besta==-1) continue; // non c'e' spazio besta -= starta; if(gbesta==-1 || gbesta>besta) { gbesta = besta; gbestx = bestx; gbesty = besty; gbestsx = bestsx; gbestsy = bestsy; gbestk = k; } } if(gbesta==-1) { return false; } assert(gbestx>=0); assert(gbesty>=0); assert(gbestk>=0); assert(gbestx<=max_size[0]); assert(gbesty<=max_size[1]); assert(gbestk=0); assert(x=0); assert(y