From f156a5a82c6ab770ec1183073e69cc663d32183f Mon Sep 17 00:00:00 2001 From: cignoni Date: Wed, 13 Mar 2013 19:09:50 +0000 Subject: [PATCH] Updated version of the oldpolyrect packer. Reasonably extended to multiple domain. To be tested/replaced --- apps/sample/space_packer/space_packer.cpp | 68 +++-- vcg/space/rect_packer.h | 327 +++++++++++++++++++++- wrap/qt/PolyToQImage.cpp | 37 ++- wrap/qt/PolyToQImage.h | 6 +- 4 files changed, 412 insertions(+), 26 deletions(-) diff --git a/apps/sample/space_packer/space_packer.cpp b/apps/sample/space_packer/space_packer.cpp index 8f0bb8a6..c3a4366e 100644 --- a/apps/sample/space_packer/space_packer.cpp +++ b/apps/sample/space_packer/space_packer.cpp @@ -22,6 +22,7 @@ ****************************************************************************/ #include #include +#include #include #include #include @@ -98,31 +99,58 @@ void buildRandPolySet(int polyNum, vector< vector > &polyVec) int main( int argc, char **argv ) { - QApplication pippo(argc,argv); + vector trVec; + vector trPolyVec; + vector< vector > polySet; + vector< vector > multiPolySet; + Point2f finalSize; + std::vector finalSizeVec; + const Point2f containerSize(1000,1000); + PolyDumperParam pp; + std::vector contInd; vector rectVec; - buildRandRectSet(1000, rectVec); - vector trVec; - vector< vector > polySet; - Point2f finalSize; + buildRandRectSet(10,rectVec); +// RectPacker::Pack(rectVec,containerSize,trVec,finalSize); + RectPacker::PackMulti(rectVec,containerSize,3,trVec,contInd,finalSizeVec); + RectPacker::Stat s = RectPacker::stat(); + printf("RectPacker attempt %i time %5.3f %5.3f\n",s.pack_attempt_num,s.pack_total_time,s.pack_attempt_time); + +// PolyDumper::rectSetToPolySet(rectVec,polySet); + +// PolyDumper::multiRectSetToSinglePolySet(rectVec,trVec,contInd,0,polySet,trPolyVec); +// PolyDumper::dumpPolySetPNG("testpolyEq0.png",polySet,trPolyVec,pp); +// PolyDumper::multiRectSetToSinglePolySet(rectVec,trVec,contInd,1,polySet,trPolyVec); +// PolyDumper::dumpPolySetPNG("testpolyEq1.png",polySet,trPolyVec,pp); +// PolyDumper::multiRectSetToSinglePolySet(rectVec,trVec,contInd,2,polySet,trPolyVec); +// PolyDumper::dumpPolySetPNG("testpolyEq2.png",polySet,trPolyVec,pp); + + +// buildRandPolySet(100,polySet); +// PolyPacker::PackMultiAsObjectOrientedRect(polySet,containerSize,3,trVec,contInd,finalSizeVec); + +// PolyDumper::multiPolySetToSinglePolySet(polySet,trVec,contInd,0,multiPolySet,trPolyVec); +// PolyDumper::dumpPolySetPNG("testpolyEq0.png",multiPolySet,trPolyVec,pp); + +// PolyDumper::multiPolySetToSinglePolySet(polySet,trVec,contInd,1,multiPolySet,trPolyVec); +// PolyDumper::dumpPolySetPNG("testpolyEq1.png",multiPolySet,trPolyVec,pp); + +// PolyDumper::multiPolySetToSinglePolySet(polySet,trVec,contInd,2,multiPolySet,trPolyVec); +// PolyDumper::dumpPolySetPNG("testpolyEq2.png",multiPolySet,trPolyVec,pp); + + // PolyDumper::dumpPolySetPNG("testpolyOO.png",polySet,trVec,pp); + + buildRandPolySet(100,polySet); - PolyDumperParam pp; - /* PolyPacker::PackAsEqualSquares(polySet,Point2f(1024.0f,1024.0f),trVec,finalSize); - dumpPolySet("testpolyEq.png",polySet,trVec,pp); - PolyPacker::PackAsAxisAlignedRect(polySet,Point2f(1024.0f,1024.0f),trVec,finalSize); - dumpPolySet("testpolyAA.png",polySet,trVec,pp); - PolyPacker::PackAsObjectOrientedRect(polySet,Point2f(1024.0f,1024.0f),trVec,finalSize); - dumpPolySet("testpolyOO.png",polySet,trVec,pp);*/ - //PolyPacker::PackAsAxisAlignedRect(polySet,Point2f(1024.0f,1024.0f),trVec,finalSize); - PolyPacker::PackAsObjectOrientedRect(polySet,Point2f(1024.0f,1024.0f),trVec,finalSize); - //dumpPolySetPNG("testpolyEq.png",polySet,trVec,pp); - PolyDumper::dumpPolySetSVG("testpolyEq.svg",polySet,trVec,pp); + PolyPacker::PackAsEqualSquares(polySet,containerSize,trVec,finalSize); + PolyDumper::dumpPolySetPNG("testpolyEq.png",polySet,trVec,pp); - /*PolyPacker::PackAsAxisAlignedRect(polySet,Point2f(1024.0f,1024.0f),trVec,finalSize); - dumpPolySetSVG("testpolyAA.svg",polySet,trVec,pp); - PolyPacker::PackAsObjectOrientedRect(polySet,Point2f(1024.0f,1024.0f),trVec,finalSize); - dumpPolySetSVG("testpolyOO.svg",polySet,trVec,pp);*/ + PolyPacker::PackAsAxisAlignedRect(polySet,containerSize,trVec,finalSize); + PolyDumper::dumpPolySetPNG("testpolyAA.png",polySet,trVec,pp); + + PolyPacker::PackAsObjectOrientedRect(polySet,containerSize,trVec,finalSize); + PolyDumper::dumpPolySetPNG("testpolyOO.png",polySet,trVec,pp); return 0; } diff --git a/vcg/space/rect_packer.h b/vcg/space/rect_packer.h index e9320cb8..cd925eb4 100644 --- a/vcg/space/rect_packer.h +++ b/vcg/space/rect_packer.h @@ -39,8 +39,25 @@ 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 Point2x 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 @@ -49,11 +66,15 @@ public: 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); @@ -63,6 +84,7 @@ public: 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; } @@ -123,6 +145,100 @@ static bool PackOccupancy(const std::vector & rectVec, /// the set of coveredContainer = Point2x::Construct(global_size); return true; } +static bool PackMulti(const std::vector & rectVec, /// the set of rectangles that have to be packed (generic floats, no req.) + const Point2x containerSizeX, /// 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,containerSizeX,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 Point2x 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 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()); + 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 @@ -283,8 +399,211 @@ static bool PackInt(const std::vector & sizes, // the sizes of the #undef Grid return true; - } + +// 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 &rectVec, vector< vector &rectVec, vector &trVec, vector &indVec, + int ind, vector< vector > &polyVec, vector &trPolyVec) +{ + polyVec.clear(); + trPolyVec.clear(); + + for(size_t i=0;i > &multiPolyVec, std::vector &multiTrVec, std::vector &indVec, + int ind, std::vector< std::vector > &singlePolyVec, std::vector &singleTrVec) +{ + singlePolyVec.clear(); + singleTrVec.clear(); + + for(size_t i=0;i > &polyVec, vector &trVec, PolyDumperParam &pp) { vector< vector< vector > > polyVecVec(polyVec.size()); @@ -270,7 +305,7 @@ void PolyDumper::dumpPolySetPNG(const char * imageName, ///FIND THE BARYCENTER int radius; Point2f bc; - bc=GetIncenter(polyVecVec[i],trVec[i],radius,100); + bc=GetIncenter(polyVecVec[i],trVec[i],radius,10); if (pp.randomColor) bb.setColor(vcg::ColorConverter::ToQColor(Color4b::Scatter(polyVecVec.size(),i))); diff --git a/wrap/qt/PolyToQImage.h b/wrap/qt/PolyToQImage.h index 238df86b..bdf26797 100644 --- a/wrap/qt/PolyToQImage.h +++ b/wrap/qt/PolyToQImage.h @@ -70,10 +70,14 @@ class PolyDumper ///this is used to write labels within the polygon, it handle polygons with holes too static vcg::Point2f GetIncenter(const std::vector< std::vector > &polyVec, const vcg::Similarity2f &tra1,int &radius,int resolution=100); +public: static void rectSetToPolySet(std::vector< vcg::Box2f > &rectVec, std::vector< std::vector > &polyVec); + static void multiRectSetToSinglePolySet(std::vector< vcg::Box2f > &rectVec, std::vector &trVec, std::vector &indVec, + int ind, std::vector< std::vector > &polyVec, std::vector &trPolyVec); + static void multiPolySetToSinglePolySet(std::vector< std::vector< vcg::Point2f> > &multipolyVec, std::vector< vcg::Similarity2f> &trVec, std::vector &indVec, + int ind, std::vector< std::vector< vcg::Point2f> > &polyVec, std::vector< vcg::Similarity2f> &trPolyVec); -public: ///write a polygon on a PNG file, format of the polygon is vector of vector of contours...nested contours are holes ///takes the name of the image in input, the set of polygons, the set of per polygons transformation, ///the label to be written and the global parameter for drawing style