00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00038
00039 std::vector < std::vector< std::vector<int> > > grids;
00040
00041
00042 std::vector<Point2f> points;
00043
00044
00045
00046 std::vector< std::vector<int> > deltaY;
00047
00048
00049
00050 std::vector< std::vector<int> > bottom;
00051
00052
00053
00054 std::vector< std::vector<int> > deltaX;
00055
00056
00057
00058 std::vector< std::vector<int> > left;
00059
00060
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
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
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
00103
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
00119
00120
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
00136
00137 int left_i;
00138 for (int row = gridHeight-1; row >= 0; --row) {
00139
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
00152 int deltax_i;
00153 for (int row = gridHeight-1; row >= 0; --row) {
00154
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
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
00205 int cellSize;
00206
00207
00208 int rotationNum;
00209
00210
00211
00212
00213
00214
00215
00216
00217
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
00238 class packingfield
00239 {
00240
00241 private:
00242
00243 std::vector<int> mLeftHorizon;
00244
00245
00246 std::vector<int> mBottomHorizon;
00247
00248
00249 vcg::Point2i mSize;
00250
00251
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
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
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
00288
00289
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
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
00304 return mBottomHorizon[col + adjacentIndex] - bottom[adjacentIndex];
00305 }
00306
00307
00308
00309
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
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
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
00331 int score = emptyCellBetweenPolyAndBottomHorizon(poly, pos, rast_i);
00332
00333
00334
00335 for (size_t i = 0; i < left.size(); ++i) {
00336
00337
00338
00339
00340
00341
00342 if (pos.X() + left[i] < mLeftHorizon[pos.Y() + i])
00343
00344 score -= mSize.X() - pos.X() - left[i];
00345 else
00346 score += pos.X() + left[i] - mLeftHorizon[pos.Y() + i];
00347 }
00348 return score;
00349 }
00350
00351
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
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
00373 int score = emptyCellBetweenPolyAndLeftHorizon(poly, pos, rast_i);
00374
00375
00376
00377 for (size_t i = 0; i < bottom.size(); ++i) {
00378
00379
00380
00381
00382
00383
00384 if (pos.Y() + bottom[i] < mBottomHorizon[pos.X() + i])
00385
00386 score -= (mSize.Y() - pos.Y() - bottom[i]);
00387 else
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
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
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
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
00431 for (int i = 0; i < poly.gridWidth(rast_i); i++) {
00432
00433 int tmpHor = pos.Y() + bottom[i] + deltaY[i];
00434
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
00442 for (int i = 0; i < poly.gridHeight(rast_i); i++) {
00443
00444 int tmpHor = pos.X() + left[i] + deltaX[i];
00445
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
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
00488 float optimalScale = sqrt(gridArea/ totalArea);
00489 float currScale = optimalScale;
00490 float latestFailScale = 0;
00491
00492 bool ret = false;
00493
00494
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
00502 if (currScale == optimalScale) return true;
00503
00504
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
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
00526 }
00527
00528
00529
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
00544 std::vector<Point2i> gridSizes;
00545 std::vector<packingfield> packingFields;
00546 for (int i=0; i < containerNum; i++) {
00547
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
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
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
00567
00568
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
00573 RASTERIZER_TYPE::rasterize(polyVec[i],scaleFactor, rast_i,packingPar.rotationNum,packingPar.cellSize);
00574 }
00575 }
00576
00577
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;
00586
00587
00588 for (int rast_i = 0; rast_i < packingPar.rotationNum; rast_i++) {
00589
00590
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
00596 for (int col = 0; col < maxCol; col++) {
00597
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
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
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
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
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
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
00645 if (bestRastIndex == -1) {
00646
00647 return false;
00648 }
00649
00650
00651
00652 packingFields[bestContainer].placePoly(polyVec[i], Point2i(bestPolyX, bestPolyY), bestRastIndex);
00653
00654
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
00665 polyToContainer[i] = bestContainer;
00666
00667
00668
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
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
00690
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 };
00701
00702
00703
00704 }
00705
00706 #endif // NEW_POLYPACKER_H