Added function to pack at fixed scale into a given number of container

This commit is contained in:
Andrea Maggiordomo 2019-02-01 10:53:31 +01:00
parent 19adc39387
commit 5ab1b189a0
1 changed files with 88 additions and 41 deletions

View File

@ -175,15 +175,16 @@ public:
template <class ScalarType> template <class ScalarType>
class ComparisonFunctor class ComparisonFunctor
{ {
typedef std::vector<vcg::Point2<ScalarType>> Outline2Type;
public: public:
std::vector<RasterizedOutline2> & v; const std::vector<Outline2Type> & v;
inline ComparisonFunctor( std::vector<RasterizedOutline2> & nv ) : v(nv) { } inline ComparisonFunctor(const std::vector<Outline2Type> & nv ) : v(nv) { }
inline bool operator() ( int a, int b ) inline bool operator() ( int a, int b )
{ {
float area1 = tri::OutlineUtil<ScalarType>::Outline2Area(v[a].getPoints()); float area1 = tri::OutlineUtil<ScalarType>::Outline2Area(v[a]);
float area2 = tri::OutlineUtil<ScalarType>::Outline2Area(v[b].getPoints()); float area2 = tri::OutlineUtil<ScalarType>::Outline2Area(v[b]);
return area1 > area2; return area1 > area2;
} }
@ -702,7 +703,6 @@ public:
float optimalScale = sqrt(gridArea / totalArea); float optimalScale = sqrt(gridArea / totalArea);
std::vector<std::vector<int>> trials;
//create the vector of polys, starting for the poly points we received as parameter //create the vector of polys, starting for the poly points we received as parameter
std::vector<RasterizedOutline2> polyVec(polyPointsVec.size()); std::vector<RasterizedOutline2> polyVec(polyPointsVec.size());
@ -710,36 +710,7 @@ public:
polyVec[i].setPoints(polyPointsVec[i]); polyVec[i].setPoints(polyPointsVec[i]);
} }
{ std::vector<std::vector<int>> trials = InitializePermutationVectors(polyPointsVec, packingPar);
// Build a permutation that holds the indexes of the polys ordered by their area
std::vector<int> perm(polyVec.size());
for(size_t i = 0; i < polyVec.size(); i++)
perm[i] = i;
sort(perm.begin(), perm.end(), ComparisonFunctor<float>(polyVec));
trials.push_back(perm);
// if using permutations, determine the number of random permutations and compute them
if (packingPar.permutations) {
int minObjNum = std::min(5, int(perm.size()));
float largestArea = tri::OutlineUtil<SCALAR_TYPE>::Outline2Area(polyPointsVec[perm[0]]);
float thresholdArea = largestArea * 0.5;
std::size_t i;
for (i = 0; i < polyVec.size(); ++i)
if (tri::OutlineUtil<SCALAR_TYPE>::Outline2Area(polyPointsVec[perm[i]]) < thresholdArea)
break;
int numPermutedObjects = std::max(minObjNum, int(i));
//int permutationCount = numPermutedObjects < 5 ? 20 : numPermutedObjects * 20;
int permutationCount = numPermutedObjects * 5;
std::cout << "PACKING: trying " << permutationCount << " random permutations of the largest "
<< numPermutedObjects << " elements" << std::endl;
std::srand(12345);
for (int k = 0; k < permutationCount; ++k) {
std::random_shuffle(perm.begin(), perm.begin() + numPermutedObjects);
trials.push_back(perm);
}
}
}
double bestEfficiency = 0; double bestEfficiency = 0;
for (std::size_t i = 0; i < trials.size(); ++i) { for (std::size_t i = 0; i < trials.size(); ++i) {
@ -803,6 +774,71 @@ public:
return true; return true;
} }
static std::vector<std::vector<int>>
InitializePermutationVectors(const std::vector<std::vector<Point2x>>& polyPointsVec,
const Parameters& packingPar)
{
std::vector<std::vector<int>> trials;
// Build a permutation that holds the indexes of the polys ordered by their area
std::vector<int> perm(polyPointsVec.size());
for(size_t i = 0; i < polyPointsVec.size(); i++)
perm[i] = i;
sort(perm.begin(), perm.end(), ComparisonFunctor<float>(polyPointsVec));
trials.push_back(perm);
// if packing with random permutations, compute a small number of randomized
// sequences. Each random sequence is generated from the initial permutation
// by shuffling only the larger polygons
if (packingPar.permutations) {
int minObjNum = std::min(5, int(perm.size()));
float largestArea = tri::OutlineUtil<SCALAR_TYPE>::Outline2Area(polyPointsVec[perm[0]]);
float thresholdArea = largestArea * 0.5;
std::size_t i;
for (i = 0; i < polyPointsVec.size(); ++i)
if (tri::OutlineUtil<SCALAR_TYPE>::Outline2Area(polyPointsVec[perm[i]]) < thresholdArea)
break;
int numPermutedObjects = std::max(minObjNum, int(i));
int permutationCount = numPermutedObjects * 5;
//printf("PACKING: trying %d random permutations of the largest %d elements\n", permutationCount, numPermutedObjects);
for (int k = 0; k < permutationCount; ++k) {
std::random_shuffle(perm.begin(), perm.begin() + numPermutedObjects);
trials.push_back(perm);
}
}
return trials;
}
static bool PackAtFixedScale(std::vector<std::vector<Point2x>> &polyPointsVec,
const std::vector<Point2i> &containerSizes,
std::vector<Similarity2x> &trVec,
std::vector<int> &polyToContainer,
const Parameters &packingPar,
float scale)
{
//create the vector of polys, starting for the poly points we received as parameter
std::vector<RasterizedOutline2> polyVec(polyPointsVec.size());
for(size_t i=0;i<polyVec.size();i++) {
polyVec[i].setPoints(polyPointsVec[i]);
}
std::vector<std::vector<int>> trials = InitializePermutationVectors(polyPointsVec, packingPar);
for (std::size_t i = 0; i < trials.size(); ++i) {
std::vector<Similarity2x> trVecIter;
std::vector<int> polyToContainerIter;
if (PolyPacking(polyPointsVec, containerSizes, trVecIter, polyToContainerIter, packingPar, scale, polyVec, trials[i])) {
trVec = trVecIter;
polyToContainer = polyToContainerIter;
return true;
}
}
return false;
}
/* Function parameters: /* Function parameters:
* outline2Vec (IN) vector of outlines to pack * outline2Vec (IN) vector of outlines to pack
* containerSizes (IN) vector of container (grid) sizes * containerSizes (IN) vector of container (grid) sizes
@ -810,6 +846,8 @@ public:
* polyToContainer (OUT) vector of outline-to-container mappings. If polyToContainer[i] == -1 * polyToContainer (OUT) vector of outline-to-container mappings. If polyToContainer[i] == -1
* then outline i did not fit in the packing grids, and the transformation trVec[i] is meaningless * then outline i did not fit in the packing grids, and the transformation trVec[i] is meaningless
* *
* Returns true if it packed at least one polygon into the container
*
* The idea is that this function packs what it can in the given space without transforming the * The idea is that this function packs what it can in the given space without transforming the
* outlines, and returns enough information to the caller in order to decide what to do */ * outlines, and returns enough information to the caller in order to decide what to do */
static bool static bool
@ -824,14 +862,23 @@ public:
polyVec[i].setPoints(outline2Vec[i]); polyVec[i].setPoints(outline2Vec[i]);
} }
std::vector<int> perm(polyVec.size()); polyToContainer.resize(outline2Vec.size(), -1);
for(size_t i = 0; i < polyVec.size(); i++)
perm[i] = i;
sort(perm.begin(), perm.end(), ComparisonFunctor<float>(polyVec));
PolyPacking(outline2Vec, containerSizes, trVec, polyToContainer, packingPar, 1.0, polyVec, perm, true); std::vector<std::vector<int>> trials = InitializePermutationVectors(outline2Vec, packingPar);
int bestNumPlaced = 0;
for (std::size_t i = 0; i < trials.size(); ++i) {
// TODO this should probably attempt at maximizing the occupancy and/or the number of placed polygons
std::vector<Similarity2x> trVecIter;
std::vector<int> polyToContainerIter;
PolyPacking(outline2Vec, containerSizes, trVecIter, polyToContainerIter, packingPar, 1.0, polyVec, trials[i], true);
int numPlaced = outline2Vec.size() - std::count(polyToContainerIter.begin(), polyToContainerIter.end(), -1);
if (numPlaced > bestNumPlaced) {
trVec = trVecIter;
polyToContainer = polyToContainerIter;
}
}
return true; return bestNumPlaced > 0;
} }
//tries to pack polygons using the given gridSize and scaleFactor //tries to pack polygons using the given gridSize and scaleFactor