rasterized_outline2_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) 2013                                                \/)\/    *
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 
00024 #ifndef __RASTERIZED_OUTLINE2_PACKER_H__
00025 #define __RASTERIZED_OUTLINE2_PACKER_H__
00026 
00027 #include <vcg/space/rect_packer.h>
00028 #include <vcg/complex/algorithms/outline_support.h>
00029 
00030 namespace vcg
00031 {
00032 
00033 
00034 class RasterizedOutline2
00035 {
00036 private:
00037     //the grid is the "bounding grid" of the polygon, which is returned by the rasterization process
00038     //this is a vector of "bounding grids", there is one for each rasterization (different rotation or whatever)
00039     std::vector < std::vector< std::vector<int> > > grids;
00040 
00041     //points: the points which make the polygon
00042     std::vector<Point2f> points;
00043 
00044     //top: a vector containing the number of cells (for the i-th column starting from left) from the
00045     //FIRST NON-EMTPY cell at the bottom to the LAST NON-EMPTY CELL at the top (there is one top vector for each rasterization)
00046     std::vector< std::vector<int> > deltaY;
00047 
00048     //bottom: a vector containing the number of EMPTY cells found starting from the bottom
00049     //until the first NON-EMPTY cell is found (there is one bottom vector for each rasterization)
00050     std::vector< std::vector<int> > bottom;
00051 
00052     //right: a vector containing the number of cells (for the i-th row starting from bottom) from the
00053     //FIRST NON-EMTPY cell at the left to the LAST NON-EMPTY CELL at the right (there is one right vector for each rasterization)
00054     std::vector< std::vector<int> > deltaX;
00055 
00056     //left: a vector containing the number of EMPTY cells found starting from the left (at the i-th row starting from the bottom)
00057     //until the first NON-EMPTY cell is found (there is one left vector for each rasterization)
00058     std::vector< std::vector<int> > left;
00059 
00060     //the area, measured in cells, of the discrete representations of the polygons
00061     std::vector<int> discreteAreas;
00062 
00063 public:
00064     RasterizedOutline2() { }
00065     int gridHeight(int i) { return grids.at(i).size(); }
00066     int gridWidth( int i) { return grids.at(i).at(0).size(); }
00067 
00068     std::vector<Point2f>&  getPoints()           { return points; }
00069     const std::vector<Point2f>&  getPointsConst() const{ return points; }
00070     std::vector< std::vector<int> >& getGrids(int rast_i)  { return grids[rast_i]; }
00071 
00072     //get top/bottom/left/right vectors of the i-th rasterization
00073     std::vector<int>& getDeltaY(int i) { return deltaY[i]; }
00074     std::vector<int>& getBottom(int i) { return bottom[i]; }
00075     std::vector<int>& getDeltaX(int i) { return deltaX[i]; }
00076     std::vector<int>& getLeft(int i) { return left[i]; }
00077     int& getDiscreteArea(int i) { return discreteAreas[i]; }
00078     void addPoint(Point2f& newpoint) { points.push_back(newpoint); }
00079     void setPoints(std::vector<Point2f>& newpoints) { points = newpoints; }
00080 
00081     //resets the state of the poly and resizes all the states vectors
00082     void resetState(int totalRasterizationsNum) {
00083         discreteAreas.clear();
00084         deltaY.clear();
00085         bottom.clear();
00086         deltaX.clear();
00087         left.clear();
00088         grids.clear();
00089 
00090         discreteAreas.resize(totalRasterizationsNum);
00091         deltaY.resize(totalRasterizationsNum);
00092         bottom.resize(totalRasterizationsNum);
00093         deltaX.resize(totalRasterizationsNum);
00094         left.resize(totalRasterizationsNum);
00095         grids.resize(totalRasterizationsNum);
00096     }
00097 
00098     void initFromGrid(int rast_i) {
00099         std::vector< std::vector<int> >& tetrisGrid = grids[rast_i];
00100         int gridWidth = tetrisGrid[0].size();
00101         int gridHeight = tetrisGrid.size();
00102         //compute bottom,
00103         //where bottom[i] = empty cells from the bottom in the column i
00104         for (int col = 0; col < gridWidth; col++) {
00105             int bottom_i = 0;
00106             for (int row = gridHeight - 1; row >= 0; row--) {
00107                 if (tetrisGrid[row][col] == 0) {
00108                     bottom_i++;
00109                 }
00110                 else {
00111                     bottom[rast_i].push_back(bottom_i);
00112                     break;
00113                 }
00114             }
00115         }
00116         if (bottom[rast_i].size() == 0) assert("ERROR: EMPTY BOTTOM VECTOR"==0);
00117 
00118         //compute top
00119         //IT ASSUMES THAT THERE IS AT LEAST ONE NON-0 ELEMENT (which should always be the case, even if the poly is just a point)
00120         //deltaY[i] = for the column i, it stores the number of cells which are between the bottom and the top side of the poly
00121         for (int col = 0; col < gridWidth; col++) {
00122             int deltay_i = gridHeight - bottom[rast_i][col];
00123             for (int row = 0; row < gridHeight; row++) {
00124                 if (tetrisGrid[row][col] == 0) {
00125                     deltay_i--;
00126                 }
00127                 else {
00128                     break;
00129                 }
00130             }
00131             deltaY[rast_i].push_back(deltay_i);
00132         }
00133         if (deltaY[rast_i].size() == 0) assert("ERROR: EMPTY deltaY VECTOR"==0);
00134 
00135         //same meaning as bottom, but for the left side
00136         //we want left/right sides vector to be ordered so that index 0 is at poly's bottom
00137         int left_i;
00138         for (int row = gridHeight-1; row >= 0; --row) {
00139             //for (int row = 0; row < gridHeight; ++row) {
00140             left_i = 0;
00141             for (int col = 0; col < gridWidth; col++) {
00142                 if (tetrisGrid[row][col] == 0) ++left_i;
00143                 else {
00144                     left[rast_i].push_back(left_i);
00145                     break;
00146                 }
00147             }
00148         }
00149         if (left[rast_i].size() == 0) assert("ERROR: EMPTY leftSide VECTOR"==0);
00150 
00151         //we want left/right sides vector to be ordered so that index 0 is at poly's bottom
00152         int deltax_i;
00153         for (int row = gridHeight-1; row >= 0; --row) {
00154             //for (int row = 0; row < gridHeight; ++row) {
00155             deltax_i = gridWidth - left[rast_i][gridHeight - 1 - row];
00156             for (int col = gridWidth - 1; col >= 0; --col) {
00157                 if (tetrisGrid[row][col] == 0) --deltax_i;
00158                 else {
00159                     break;
00160                 }
00161             }
00162             deltaX[rast_i].push_back(deltax_i);
00163         }
00164         if (deltaX[rast_i].size() == 0) assert("ERROR: EMPTY rightSide VECTOR"==0);
00165 
00166         //compute the discreteArea: IT IS THE AREA (measured in grid cells) BETWEEN THE TOP AND BOTTOM SIDES...
00167         int discreteArea = 0;
00168         for (size_t i = 0; i < deltaY[rast_i].size(); i++) {
00169             discreteArea += deltaY[rast_i][i];
00170         }
00171         discreteAreas[rast_i] = discreteArea;
00172     }
00173 
00174 
00175 };
00176 
00177 template <class ScalarType>
00178 class ComparisonFunctor
00179 {
00180 
00181 public:
00182     std::vector<RasterizedOutline2> & v;
00183     inline ComparisonFunctor( std::vector<RasterizedOutline2> & nv ) : v(nv) { }
00184 
00185     inline bool operator() ( int a, int b )
00186     {
00187         float area1 = tri::OutlineUtil<ScalarType>::Outline2Area(v[a].getPoints());
00188         float area2 = tri::OutlineUtil<ScalarType>::Outline2Area(v[b].getPoints());
00189 
00190         return area1 > area2;
00191     }
00192 };
00193 
00194 template <class SCALAR_TYPE, class RASTERIZER_TYPE>
00195 class RasterizedOutline2Packer
00196 {
00197     typedef typename vcg::Box2<SCALAR_TYPE> Box2x;
00198     typedef typename vcg::Point2<SCALAR_TYPE> Point2x;
00199     typedef typename vcg::Similarity2<SCALAR_TYPE> Similarity2x;
00200 public:
00201   class Parameters
00202   {
00203   public:
00204       //size of one cell of the grid (square cells at the moment)
00205       int cellSize;
00206 
00207       //the number of rasterizations to create for each polygon; It must be a multiple of 4.
00208       int rotationNum;
00209 
00210       //THE PACKING ALGO TO USE:
00211       //0 - BOTTOM PACKING: it just uses bottom horizon and computes cost using the num of empty cells between the bottom side of the poly and the bottom horizon
00212       //1 - BOTTOM PACKING WITH PENALTY: it uses both bottom and left horizons, and it makes so that polys are placed the closest possible to the left horizon
00213       //2 - CORNER PACKING: 1) tries to drop poly from right to left and computes cost relative to the left horizon
00214       //                    2) tries to drop poly from top to bottom and computes cost relative to the bottom horizon
00215       //                    3) chooses the X,Y which minimize the cost
00216       //                    NOTE: IN THIS ALGO THE COST HAVE TO INCLUDE THE PENALTY, OTHERWISE THE TWO STRATEGIES (dropping from right and from top)
00217       //                          WILL COMPETE CAUSING A LOW PACKING EFFICIENCY
00218       enum costFuncEnum {
00219           MinWastedSpace,
00220           LowestHorizon,
00221           MixedCost
00222       };
00223       costFuncEnum costFunction;
00224       bool doubleHorizon;
00225 
00227       Parameters()
00228       {
00229           costFunction = LowestHorizon;
00230           doubleHorizon=true;
00231           rotationNum = 16;
00232           cellSize = 8;
00233       }
00234   };
00235 
00236 
00237   //THE CLASS WHICH HANDLES THE PACKING AND THE UPDATED STATE OF THE PACKING ALGORITHMS
00238   class packingfield
00239   {
00240 
00241   private:
00242       //the bottomHorizon stores the length of the i-th row in the current solution
00243       std::vector<int> mLeftHorizon;
00244 
00245       //the bottomHorizon stores the height of the i-th column in the current solution
00246       std::vector<int> mBottomHorizon;
00247 
00248       //the size of the packing grid
00249       vcg::Point2i mSize;
00250 
00251       //packing parameters
00252       Parameters params;
00253 
00254   public:
00255       packingfield(vcg::Point2i size, const Parameters& par)
00256       {
00257           mBottomHorizon.resize(size.X(), 0);
00258           mLeftHorizon.resize(size.Y(), 0);
00259           params = par;
00260           mSize = Point2i(size.X(), size.Y());
00261       }
00262 
00263       std::vector<int>& bottomHorizon() { return mBottomHorizon; }
00264       std::vector<int>& leftHorizon() { return mLeftHorizon; }
00265       vcg::Point2i& size() { return mSize; }
00266 
00267       //returns the score relative to the left horizon of that poly in that particular position, taking into account the choosen algo
00268       int getCostX(RasterizedOutline2& poly, Point2i pos, int rast_i) {
00269           switch (params.costFunction) {
00270           case 0: return emptyCellBetweenPolyAndLeftHorizon(poly, pos, rast_i);
00271           case 1: return maxXofPoly(poly, pos, rast_i);
00272           case 2: return costXWithPenaltyOnY(poly, pos, rast_i);
00273           }
00274           return 0;
00275       }
00276 
00277       //returns the score relative to the bottom horizon of that poly in that particular position, taking into account the choosen algo
00278       int getCostY(RasterizedOutline2& poly, Point2i pos, int rast_i) {
00279           switch (params.costFunction) {
00280           case 0: return emptyCellBetweenPolyAndBottomHorizon(poly, pos, rast_i);
00281           case 1: return maxYofPoly(poly, pos, rast_i);
00282           case 2: return costYWithPenaltyOnX(poly, pos, rast_i);
00283           }
00284           return 0;
00285       }
00286 
00287       //given a poly and the column at which it is placed,
00288       //this returns the Y at which the wasted space is minimum
00289       //i.e. the Y at which the polygon touches the horizon
00290       int dropY(RasterizedOutline2& poly, int col, int rast_i) {
00291           int tmp = INT_MAX;
00292           int adjacentIndex = 0;
00293           std::vector<int>& bottom = poly.getBottom(rast_i);
00294 
00295           //look for for index of the column at which the poly touches the bottom horizon first
00296           for (size_t i = 0; i < bottom.size(); ++i) {
00297               int diff = bottom[i] - mBottomHorizon[col + i];
00298               if (diff < tmp) {
00299                   adjacentIndex = i;
00300                   tmp = diff;
00301               }
00302           }
00303           //return the lowest Y of the dropped poly
00304           return mBottomHorizon[col + adjacentIndex] - bottom[adjacentIndex];
00305       }
00306 
00307       //given a poly and the row at which it is placed,
00308       //this returns the X at which the wasted space is minimum
00309       //i.e. the X at which the polygon touches the left horizon
00310       int dropX(RasterizedOutline2& poly, int row, int rast_i) {
00311           int tmp = INT_MAX;
00312           int adjacentIndex = 0;
00313           std::vector<int>& left = poly.getLeft(rast_i);
00314 
00315           //look for for index of the column at which the poly touches the left horizon first
00316           for (size_t i = 0; i < left.size(); ++i) {
00317               int diff = left[i] - mLeftHorizon[row + i];
00318               if (diff < tmp) {
00319                   adjacentIndex = i;
00320                   tmp = diff;
00321               }
00322           }
00323           //and return the lowest X of the dropped poly
00324           return mLeftHorizon[row + adjacentIndex] - left[adjacentIndex];
00325       }
00326 
00327       int costYWithPenaltyOnX(RasterizedOutline2& poly, Point2i pos, int rast_i) {
00328           std::vector<int>& left = poly.getLeft(rast_i);
00329 
00330           //get the standard cost on X axis
00331           int score = emptyCellBetweenPolyAndBottomHorizon(poly, pos, rast_i);
00332 
00333           //apply a penalty if the poly is the poly is far from the left horizon
00334           //thus preferring poly which are closer to the left horizon
00335           for (size_t i = 0; i < left.size(); ++i) {
00336               //ASSUMPTION: if the poly is (partially/fully) under the left horizon,
00337               //then we will count this as a good thing (subtracting a quantity from the cost) but since we don't have
00338               //a grid holding the current state of the packing field, we don't know the position of the polygons at our left side,
00339               //so we ASSUME that there isn't any polygon between the poly we're considering and the Y axis of the packing field,
00340               //and count the number of cells between us and the RIGHT end the packing field
00341               //(NOTE: ^^^^^^^ this implies that the closer we are to the left horizon, the lower the cost will get)
00342               if (pos.X() + left[i] < mLeftHorizon[pos.Y() + i])
00343                   //number of cells between us and the RIGHT end the packing field
00344                   score -= mSize.X() - pos.X() - left[i];
00345               else         //the number of cells between the bottom side of the poly at the (posY+i)-th row and the value of the horizon in that row
00346                   score += pos.X() + left[i] - mLeftHorizon[pos.Y() + i];
00347           }
00348           return score;
00349       }
00350 
00351       //returns the number of empty cells between poly's bottom side and the bottom horizon
00352       int emptyCellBetweenPolyAndBottomHorizon(RasterizedOutline2& poly, Point2i pos, int rast_i)
00353       {
00354           std::vector<int>& bottom = poly.getBottom(rast_i);
00355           int score = 0;
00356           int min = INT_MAX;
00357 
00358           //count the number of empty cells between poly's bottom side and the bottom horizon
00359           for (size_t i = 0; i < bottom.size(); ++i) {
00360               int diff = bottom[i] - mBottomHorizon[pos.X() + i];
00361               score += diff;
00362               if (diff < min) min = diff;
00363           }
00364           score += (-min*bottom.size());
00365 
00366           return score;
00367       }
00368 
00369       int costXWithPenaltyOnY(RasterizedOutline2& poly, Point2i pos, int rast_i) {
00370           std::vector<int>& bottom = poly.getBottom(rast_i);
00371 
00372           //get the standard cost on X axis
00373           int score = emptyCellBetweenPolyAndLeftHorizon(poly, pos, rast_i);
00374 
00375           //apply a penalty if the poly is the poly is far from the bottom horizon
00376           //thus preferring poly which are closer to the bottom horizon
00377           for (size_t i = 0; i < bottom.size(); ++i) {
00378               //ASSUMPTION: if the poly is (partially/fully) under the bottom horizon,
00379               //then we will count this as a good thing (subtracting a quantity from the cost) but since we don't have
00380               //a grid holding the current state of the packing field, we don't know the position of the polygons beneath us,
00381               //so we ASSUME that there isn't any polygon between the poly we're considering and the X axis of the packing field,
00382               //and count the number of cells between us and the TOP end the packing field
00383               //(NOTE: ^^^^^^^ this implies that the closer we are to the bottom horizon, the lower the cost will get)
00384               if (pos.Y() + bottom[i] < mBottomHorizon[pos.X() + i])
00385                   //number of cells between us and the TOP side the packing field
00386                   score -= (mSize.Y() - pos.Y() - bottom[i]);
00387               else         //the number of cells between the left side of the poly at the (posX+i)-th column and the value of the horizon in that column
00388                   score += pos.X() + bottom[i] - mBottomHorizon[pos.X() + i];
00389           }
00390           return score;
00391       }
00392 
00393       int maxYofPoly(RasterizedOutline2& poly, Point2i pos, int rast_i)
00394       {
00395           return pos.Y() + poly.gridHeight(rast_i);
00396       }
00397 
00398       int maxXofPoly(RasterizedOutline2& poly, Point2i pos, int rast_i)
00399       {
00400           return pos.X() + poly.gridWidth(rast_i);
00401       }
00402 
00403       //returns the number of empty cells between poly's left side and the left horizon
00404       int emptyCellBetweenPolyAndLeftHorizon(RasterizedOutline2& poly, Point2i pos, int rast_i)
00405       {
00406           std::vector<int>& left = poly.getLeft(rast_i);
00407 
00408           int score = 0;
00409           int min = INT_MAX;
00410 
00411           //count the number of empty cells between poly's left side and the left horizon
00412           for (size_t i = 0; i < left.size(); ++i) {
00413               int diff = left[i] - mLeftHorizon[pos.Y() + i];
00414               score += diff;
00415               if (diff < min) min = diff;
00416           }
00417           score += (-min*left.size());
00418 
00419           return score;
00420       }
00421 
00422       //updates the horizons according to the chosen position
00423       void placePoly(RasterizedOutline2& poly, Point2i pos, int rast_i) {
00424 
00425           std::vector<int>& bottom = poly.getBottom(rast_i);
00426           std::vector<int>& deltaY = poly.getDeltaY(rast_i);
00427           std::vector<int>& left = poly.getLeft(rast_i);
00428           std::vector<int>& deltaX = poly.getDeltaX(rast_i);
00429 
00430           //update bottom horizon
00431           for (int i = 0; i < poly.gridWidth(rast_i); i++) {
00432               //tmpHor = the highest Y reached by the poly, RELATIVE TO the packing field coords system
00433               int tmpHor = pos.Y() + bottom[i] + deltaY[i];
00434               //only update the horizon if it's higher than this value
00435               if (tmpHor > mBottomHorizon[pos.X() + i]) mBottomHorizon[pos.X() + i] = tmpHor;
00436           }
00437 
00438           if (params.costFunction != Parameters::MixedCost
00439                   && !params.doubleHorizon) return;
00440 
00441           //update leftHorizon
00442           for (int i = 0; i < poly.gridHeight(rast_i); i++) {
00443               //tmpHor = the highest X reached by the poly, RELATIVE TO the packing field coords system
00444               int tmpHor = pos.X() + left[i] + deltaX[i];
00445               //only update the horizon if it's higher than this value
00446               if (tmpHor > mLeftHorizon[pos.Y() + i]) mLeftHorizon[pos.Y() + i] = tmpHor;
00447           }
00448       }
00449   };
00450 
00451 
00452     static bool Pack(std::vector< std::vector< Point2x>  > &polyPointsVec,
00453                      Point2i containerSize,
00454                      std::vector<Similarity2x> &trVec,
00455                      const Parameters &packingPar)
00456     {
00457       std::vector<Point2i> containerSizes(1,containerSize);
00458       std::vector<int> polyToContainer;
00459       return Pack(polyPointsVec,containerSizes,trVec,polyToContainer,packingPar);
00460     }
00461 
00462     static bool Pack(std::vector< std::vector< Point2x>  > &polyPointsVec,
00463                      const std::vector<Point2i> &containerSizes,
00464                      std::vector<Similarity2x> &trVec,
00465                      std::vector<int> &polyToContainer,
00466                      const Parameters &packingPar)
00467     {
00468 
00469       int containerNum=containerSizes.size();
00470 
00471         float gridArea = 0;
00472         //if containerSize isn't multiple of cell size, crop the grid (leaving containerSize as it is)
00473         for (int i = 0; i < containerNum; i++) {
00474             Point2i gridSize(containerSizes[i].X() / packingPar.cellSize,
00475                              containerSizes[i].Y() / packingPar.cellSize);
00476 
00477             gridArea += (gridSize.X()*packingPar.cellSize * gridSize.Y()*packingPar.cellSize);
00478         }
00479 
00480         float totalArea = 0;
00481         for (size_t j = 0; j < polyPointsVec.size(); j++) {
00482             float curArea = tri::OutlineUtil<SCALAR_TYPE>::Outline2Area(polyPointsVec[j]);
00483             if(curArea<0) tri::OutlineUtil<SCALAR_TYPE>::ReverseOutline2(polyPointsVec[j]);
00484             totalArea += fabs(curArea);
00485         }
00486 
00487         //we first set it to the "optimal" scale
00488         float optimalScale = sqrt(gridArea/ totalArea);
00489         float currScale = optimalScale;
00490         float latestFailScale = 0;
00491 
00492         bool ret = false;
00493         //we look for the first scale factor which makes the packing algo succeed
00494         //we will use this value in the bisection method afterwards
00495         ret = PolyPacking(polyPointsVec, containerSizes, trVec, polyToContainer, packingPar, currScale);
00496         while (!ret) {
00497             latestFailScale = currScale;
00498             currScale *= 0.60;
00499             ret = PolyPacking(polyPointsVec, containerSizes, trVec, polyToContainer, packingPar, currScale);
00500         }
00501         //if it managed to pack with the optimal scale (VERY unlikely), just leave
00502         if (currScale == optimalScale) return true;
00503 
00504         //BISECTION METHOD
00505         float latestSuccessScale = currScale;
00506         float tmpScale = (latestSuccessScale + latestFailScale) / 2;
00507         while ( (latestFailScale / latestSuccessScale) - 1 > 0.001
00508                 || ((latestFailScale / latestSuccessScale) - 1 < 0.001 && !ret) ) {
00509 
00510             tmpScale = (latestSuccessScale + latestFailScale) / 2;
00511             ret = PolyPacking(polyPointsVec, containerSizes, trVec, polyToContainer, packingPar, tmpScale);
00512             if (ret) latestSuccessScale = tmpScale;
00513             else latestFailScale = tmpScale;
00514         }
00515 
00516         float finalArea = 0;
00517         //compute occupied area
00518         for (size_t j = 0; j < polyPointsVec.size(); j++) {
00519             std::vector<Point2f> oldPoints = polyPointsVec[j];
00520             for (size_t k = 0; k < oldPoints.size(); k++) {
00521                 oldPoints[k].Scale(latestSuccessScale, latestSuccessScale);
00522             }
00523             finalArea +=  tri::OutlineUtil<SCALAR_TYPE>::Outline2Area(oldPoints);
00524         }
00525 //        printf("PACKING EFFICIENCY: %f with scale %f\n", finalArea/gridArea, latestSuccessScale);
00526     }
00527 
00528     //tries to pack polygons using the given gridSize and scaleFactor
00529     //stores the result, i.e. the vector of similarities, in trVec
00530     static bool PolyPacking(std::vector< std::vector< Point2x>  > &outline2Vec,
00531                             const std::vector<Point2i> &containerSizes,
00532                             std::vector<Similarity2x> &trVec,
00533                             std::vector<int> &polyToContainer,
00534                             const Parameters &packingPar,
00535                             float scaleFactor)
00536     {
00537         int containerNum = containerSizes.size();
00538 
00539         polyToContainer.clear();
00540         polyToContainer.resize(outline2Vec.size());
00541         trVec.resize(outline2Vec.size());
00542 
00543         //create packing fields, one for each container
00544         std::vector<Point2i> gridSizes;
00545         std::vector<packingfield> packingFields;
00546         for (int i=0; i < containerNum; i++) {
00547             //if containerSize isn't multiple of cell size, crop the grid (leaving containerSize as it is)
00548             gridSizes.push_back(Point2i(containerSizes[i].X() / packingPar.cellSize,
00549                                         containerSizes[i].Y() / packingPar.cellSize));
00550 
00551             packingfield one(gridSizes[i], packingPar);
00552             packingFields.push_back(one);
00553         }
00554 
00555         //create the vector of polys, starting for the poly points we received as parameter
00556         std::vector<RasterizedOutline2> polyVec(outline2Vec.size());
00557         for(size_t i=0;i<polyVec.size();i++) {
00558             polyVec[i].setPoints(outline2Vec[i]);
00559         }
00560 
00561         // Build a permutation that holds the indexes of the polys ordered by their area
00562         std::vector<int> perm(polyVec.size());
00563         for(size_t i=0;i<polyVec.size();i++) perm[i] = i;
00564         sort(perm.begin(),perm.end(),ComparisonFunctor<float>(polyVec));
00565 
00566 //        printf("BEGIN OF PACKING\n");
00567 
00568         // **** First Step: Rasterize all the polygons ****
00569         for (size_t i = 0; i < polyVec.size(); i++) {
00570             polyVec[i].resetState(packingPar.rotationNum);
00571             for (int rast_i = 0; rast_i < packingPar.rotationNum/4; rast_i++) {
00572                 //create the rasterization (i.e. fills bottom/top/grids/internalWastedCells arrays)
00573                 RASTERIZER_TYPE::rasterize(polyVec[i],scaleFactor, rast_i,packingPar.rotationNum,packingPar.cellSize);
00574             }
00575         }
00576 
00577         // **** Second Step: iterate on the polys, and try to find the best position ****
00578         for (size_t currPoly = 0; currPoly < polyVec.size(); currPoly++) {
00579 
00580             int i = perm[currPoly];
00581             int bestRastIndex = -1;
00582             int bestCost = INT_MAX;
00583             int bestPolyX = -1;
00584             int bestPolyY = -1;
00585             int bestContainer = -1; //the container where the poly fits best
00586 
00587             //try all the rasterizations and choose the best fitting one
00588             for (int rast_i = 0; rast_i < packingPar.rotationNum; rast_i++) {
00589 
00590                 //try to fit the poly in all containers, in all valid positions
00591                 for (int grid_i = 0; grid_i < containerNum; grid_i++) {
00592                     int maxCol = gridSizes[grid_i].X() - polyVec[i].gridWidth(rast_i);
00593                     int maxRow = gridSizes[grid_i].Y() - polyVec[i].gridHeight(rast_i);
00594 
00595                     //look for the best position, dropping from top
00596                     for (int col = 0; col < maxCol; col++) {
00597                         //get the Y at which the poly touches the horizontal horizon
00598                         int currPolyY = packingFields[grid_i].dropY(polyVec[i],col, rast_i);
00599 
00600                         if (currPolyY + polyVec[i].gridHeight(rast_i) > gridSizes[grid_i].Y()) {
00601                             //skip this column, as the poly would go outside the grid if placed here
00602                             continue;
00603                         }
00604 
00605                         int currCost = packingFields[grid_i].getCostX(polyVec[i], Point2i(col, currPolyY), rast_i) +
00606                                 packingFields[grid_i].getCostY(polyVec[i], Point2i(col, currPolyY), rast_i);
00607 
00608                         //if this rasterization is better than what we found so far
00609                         if (currCost < bestCost) {
00610                             bestContainer = grid_i;
00611                             bestCost = currCost;
00612                             bestRastIndex = rast_i;
00613                             bestPolyX = col;
00614                             bestPolyY = currPolyY;
00615                         }
00616                     }
00617 
00618                     if (!packingPar.doubleHorizon) continue;
00619 
00620                     for (int row = 0; row < maxRow; row++) {
00621                         //get the Y at which the poly touches the horizontal horizon
00622                         int currPolyX = packingFields[grid_i].dropX(polyVec[i],row, rast_i);
00623 
00624                         if (currPolyX + polyVec[i].gridWidth(rast_i) > gridSizes[grid_i].X()) {
00625                             //skip this column, as the poly would go outside the grid if placed here
00626                             continue;
00627                         }
00628 
00629                         int currCost = packingFields[grid_i].getCostY(polyVec[i], Point2i(currPolyX, row), rast_i) +
00630                                 packingFields[grid_i].getCostX(polyVec[i], Point2i(currPolyX, row), rast_i);
00631 
00632                         //if this rasterization fits better than those we tried so far
00633                         if (currCost < bestCost) {
00634                             bestContainer = grid_i;
00635                             bestCost = currCost;
00636                             bestRastIndex = rast_i;
00637                             bestPolyX = currPolyX;
00638                             bestPolyY = row;
00639                         }
00640                     }
00641                 }
00642             }
00643 
00644             //if we couldn't find a valid position for the poly return false, as we couldn't pack with the current scaleFactor
00645             if (bestRastIndex == -1) {
00646 //                printf("Items didn't fit using %f as scaleFactor\n", scaleFactor);
00647                 return false;
00648             }
00649 
00650             //we found the best position for a given poly,
00651             //let's place it, so that the horizons are updated accordingly
00652             packingFields[bestContainer].placePoly(polyVec[i], Point2i(bestPolyX, bestPolyY), bestRastIndex);
00653 
00654             //create the rotated bb which we will use to set the similarity translation prop
00655             float angleRad = float(bestRastIndex)*(M_PI*2.0)/float(packingPar.rotationNum);
00656             Box2f bb;
00657             std::vector<Point2f> points = polyVec[i].getPoints();
00658             for(size_t i=0;i<points.size();++i) {
00659                 Point2f pp=points[i];
00660                 pp.Rotate(angleRad);
00661                 bb.Add(pp);
00662             }
00663 
00664             //associate the poly to the container where it fitted best
00665             polyToContainer[i] = bestContainer;
00666 
00667             //now we have bestPolyX/bestRastIndex
00668             //we have to update the similarities vector accordingly!
00669             float polyXInImgCoords = bestPolyX*packingPar.cellSize;
00670             float scaledBBWidth = bb.DimX()*scaleFactor;
00671             float polyWidthInImgCoords = polyVec[i].gridWidth(bestRastIndex)*packingPar.cellSize;
00672             float offsetX = (polyWidthInImgCoords - ceil(scaledBBWidth))/2.0;
00673             float scaledBBMinX = bb.min.X()*scaleFactor;
00674 
00675             //note: bestPolyY is 0 if the poly is at the bottom of the grid
00676             float imgHeight = containerSizes[bestContainer].Y();
00677             float polyYInImgCoords = bestPolyY*packingPar.cellSize;
00678             float polyHeightInImgCoords = polyVec[i].gridHeight(bestRastIndex)*packingPar.cellSize;
00679             float topPolyYInImgCoords = polyYInImgCoords + polyHeightInImgCoords;
00680             float scaledBBHeight = bb.DimY()*scaleFactor;
00681             float offsetY = (polyHeightInImgCoords - ceil(scaledBBHeight))/2.0;
00682             float scaledBBMinY = bb.min.Y()*scaleFactor;
00683             trVec[i].tra = Point2f(polyXInImgCoords - scaledBBMinX + offsetX,
00684                                    imgHeight - topPolyYInImgCoords - scaledBBMinY + offsetY);
00685             trVec[i].rotRad = angleRad;
00686             trVec[i].sca = scaleFactor;
00687         }
00688 
00689         //sort polyToContainer and trVec so that we have them ordered for dumping
00690 //        printf("SUCCESSFULLY PACKED with scaleFactor %f\n", scaleFactor);
00691         return true;
00692     }
00693 
00694     static void printVector(std::vector<int>& vec) {
00695         for (size_t i = 0; i < vec.size(); i++) {
00696             printf("%d", vec[i]);
00697         }
00698         printf("\n");
00699     }
00700 }; // end class
00701 
00702 
00703 
00704 } // end namespace vcg
00705 
00706 #endif // NEW_POLYPACKER_H


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