Merge branch 'tm_arrange_perf_improve'
This commit is contained in:
commit
ec340e0726
1 changed files with 69 additions and 182 deletions
|
@ -479,13 +479,18 @@ class _NofitPolyPlacer: public PlacerBoilerplate<_NofitPolyPlacer<RawShape, TBin
|
||||||
|
|
||||||
using MaxNfpLevel = nfp::MaxNfpLevel<RawShape>;
|
using MaxNfpLevel = nfp::MaxNfpLevel<RawShape>;
|
||||||
|
|
||||||
// Norming factor for the optimization function
|
|
||||||
const double norm_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using Pile = nfp::Shapes<RawShape>;
|
using Pile = nfp::Shapes<RawShape>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Norming factor for the optimization function
|
||||||
|
const double norm_;
|
||||||
|
Pile merged_pile_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
inline explicit _NofitPolyPlacer(const BinType& bin):
|
inline explicit _NofitPolyPlacer(const BinType& bin):
|
||||||
Base(bin),
|
Base(bin),
|
||||||
norm_(std::sqrt(sl::area(bin)))
|
norm_(std::sqrt(sl::area(bin)))
|
||||||
|
@ -576,6 +581,20 @@ private:
|
||||||
|
|
||||||
using Shapes = TMultiShape<RawShape>;
|
using Shapes = TMultiShape<RawShape>;
|
||||||
|
|
||||||
|
template<nfp::NfpLevel lvl>
|
||||||
|
static Shapes calcnfp(const Shapes &pile, const RawShape &orb)
|
||||||
|
{
|
||||||
|
Shapes ret; ret.reserve(2 * pile.size());
|
||||||
|
|
||||||
|
for (auto &stat : pile) {
|
||||||
|
Shapes subnfp = nfp::noFitPolygon<lvl>(stat, orb);
|
||||||
|
for (auto &nfp : subnfp)
|
||||||
|
ret.emplace_back(subnfp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nfp::merge(ret);
|
||||||
|
}
|
||||||
|
|
||||||
Shapes calcnfp(const Item &trsh, Lvl<nfp::NfpLevel::CONVEX_ONLY>)
|
Shapes calcnfp(const Item &trsh, Lvl<nfp::NfpLevel::CONVEX_ONLY>)
|
||||||
{
|
{
|
||||||
using namespace nfp;
|
using namespace nfp;
|
||||||
|
@ -616,135 +635,9 @@ private:
|
||||||
template<class Level>
|
template<class Level>
|
||||||
Shapes calcnfp(const Item &trsh, Level)
|
Shapes calcnfp(const Item &trsh, Level)
|
||||||
{ // Function for arbitrary level of nfp implementation
|
{ // Function for arbitrary level of nfp implementation
|
||||||
using namespace nfp;
|
|
||||||
|
|
||||||
Shapes nfps;
|
// TODO: implement
|
||||||
|
return {};
|
||||||
auto& orb = trsh.transformedShape();
|
|
||||||
bool orbconvex = trsh.isContourConvex();
|
|
||||||
|
|
||||||
for(Item& sh : items_) {
|
|
||||||
nfp::NfpResult<RawShape> subnfp;
|
|
||||||
auto& stat = sh.transformedShape();
|
|
||||||
|
|
||||||
if(sh.isContourConvex() && orbconvex)
|
|
||||||
subnfp = nfp::noFitPolygon<NfpLevel::CONVEX_ONLY>(stat, orb);
|
|
||||||
else if(orbconvex)
|
|
||||||
subnfp = nfp::noFitPolygon<NfpLevel::ONE_CONVEX>(stat, orb);
|
|
||||||
else
|
|
||||||
subnfp = nfp::noFitPolygon<Level::value>(stat, orb);
|
|
||||||
|
|
||||||
correctNfpPosition(subnfp, sh, trsh);
|
|
||||||
|
|
||||||
nfps = nfp::merge(nfps, subnfp.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nfps;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Very much experimental
|
|
||||||
void repack(Item& item, PackResult& result) {
|
|
||||||
|
|
||||||
if((sl::area(bin_) - this->filledArea()) >= item.area()) {
|
|
||||||
auto prev_func = config_.object_function;
|
|
||||||
|
|
||||||
unsigned iter = 0;
|
|
||||||
ItemGroup backup_rf = items_;
|
|
||||||
std::vector<Item> backup_cpy;
|
|
||||||
for(Item& itm : items_) backup_cpy.emplace_back(itm);
|
|
||||||
|
|
||||||
auto ofn = [this, &item, &result, &iter, &backup_cpy, &backup_rf]
|
|
||||||
(double ratio)
|
|
||||||
{
|
|
||||||
auto& bin = bin_;
|
|
||||||
iter++;
|
|
||||||
config_.object_function = [bin, ratio](
|
|
||||||
nfp::Shapes<RawShape>& pile,
|
|
||||||
const Item& item,
|
|
||||||
const ItemGroup& /*remaining*/)
|
|
||||||
{
|
|
||||||
pile.emplace_back(item.transformedShape());
|
|
||||||
auto ch = sl::convexHull(pile);
|
|
||||||
auto pbb = sl::boundingBox(pile);
|
|
||||||
pile.pop_back();
|
|
||||||
|
|
||||||
double parea = 0.5*(sl::area(ch) + sl::area(pbb));
|
|
||||||
|
|
||||||
double pile_area = std::accumulate(
|
|
||||||
pile.begin(), pile.end(), item.area(),
|
|
||||||
[](double sum, const RawShape& sh){
|
|
||||||
return sum + sl::area(sh);
|
|
||||||
});
|
|
||||||
|
|
||||||
// The pack ratio -- how much is the convex hull occupied
|
|
||||||
double pack_rate = (pile_area)/parea;
|
|
||||||
|
|
||||||
// ratio of waste
|
|
||||||
double waste = 1.0 - pack_rate;
|
|
||||||
|
|
||||||
// Score is the square root of waste. This will extend the
|
|
||||||
// range of good (lower) values and shrink the range of bad
|
|
||||||
// (larger) values.
|
|
||||||
auto wscore = std::sqrt(waste);
|
|
||||||
|
|
||||||
|
|
||||||
auto ibb = item.boundingBox();
|
|
||||||
auto bbb = sl::boundingBox(bin);
|
|
||||||
auto c = ibb.center();
|
|
||||||
double norm = 0.5*pl::distance(bbb.minCorner(),
|
|
||||||
bbb.maxCorner());
|
|
||||||
|
|
||||||
double dscore = pl::distance(c, pbb.center()) / norm;
|
|
||||||
|
|
||||||
return ratio*wscore + (1.0 - ratio) * dscore;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto bb = sl::boundingBox(bin);
|
|
||||||
double norm = bb.width() + bb.height();
|
|
||||||
|
|
||||||
auto items = items_;
|
|
||||||
clearItems();
|
|
||||||
auto it = items.begin();
|
|
||||||
while(auto pr = _trypack(*it++)) {
|
|
||||||
this->accept(pr); if(it == items.end()) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto count_diff = items.size() - items_.size();
|
|
||||||
double score = count_diff;
|
|
||||||
|
|
||||||
if(count_diff == 0) {
|
|
||||||
result = _trypack(item);
|
|
||||||
|
|
||||||
if(result) {
|
|
||||||
std::cout << "Success" << std::endl;
|
|
||||||
score = 0.0;
|
|
||||||
} else {
|
|
||||||
score += result.overfit() / norm;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = PackResult();
|
|
||||||
items_ = backup_rf;
|
|
||||||
for(unsigned i = 0; i < items_.size(); i++) {
|
|
||||||
items_[i].get() = backup_cpy[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << iter << " repack result: " << score << " "
|
|
||||||
<< ratio << " " << count_diff << std::endl;
|
|
||||||
|
|
||||||
return score;
|
|
||||||
};
|
|
||||||
|
|
||||||
opt::StopCriteria stopcr;
|
|
||||||
stopcr.max_iterations = 30;
|
|
||||||
stopcr.stop_score = 1e-20;
|
|
||||||
opt::TOptimizer<opt::Method::L_SUBPLEX> solver(stopcr);
|
|
||||||
solver.optimize_min(ofn, opt::initvals(0.5),
|
|
||||||
opt::bound(0.0, 1.0));
|
|
||||||
|
|
||||||
// optimize
|
|
||||||
config_.object_function = prev_func;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Optimum {
|
struct Optimum {
|
||||||
|
@ -798,6 +691,50 @@ private:
|
||||||
Radians final_rot = initial_rot;
|
Radians final_rot = initial_rot;
|
||||||
Shapes nfps;
|
Shapes nfps;
|
||||||
|
|
||||||
|
auto& bin = bin_;
|
||||||
|
double norm = norm_;
|
||||||
|
auto pbb = sl::boundingBox(merged_pile_);
|
||||||
|
auto binbb = sl::boundingBox(bin);
|
||||||
|
|
||||||
|
// This is the kernel part of the object function that is
|
||||||
|
// customizable by the library client
|
||||||
|
std::function<double(const Item&)> _objfunc;
|
||||||
|
if(config_.object_function) _objfunc = config_.object_function;
|
||||||
|
else {
|
||||||
|
|
||||||
|
// Inside check has to be strict if no alignment was enabled
|
||||||
|
std::function<double(const Box&)> ins_check;
|
||||||
|
if(config_.alignment == Config::Alignment::DONT_ALIGN)
|
||||||
|
ins_check = [&binbb, norm](const Box& fullbb) {
|
||||||
|
double ret = 0;
|
||||||
|
if(!sl::isInside(fullbb, binbb))
|
||||||
|
ret += norm;
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
else
|
||||||
|
ins_check = [&bin](const Box& fullbb) {
|
||||||
|
double miss = overfit(fullbb, bin);
|
||||||
|
miss = miss > 0? miss : 0;
|
||||||
|
return std::pow(miss, 2);
|
||||||
|
};
|
||||||
|
|
||||||
|
_objfunc = [norm, binbb, pbb, ins_check](const Item& item)
|
||||||
|
{
|
||||||
|
auto ibb = item.boundingBox();
|
||||||
|
auto fullbb = sl::boundingBox(pbb, ibb);
|
||||||
|
|
||||||
|
double score = pl::distance(ibb.center(),
|
||||||
|
binbb.center());
|
||||||
|
score /= norm;
|
||||||
|
|
||||||
|
score += ins_check(fullbb);
|
||||||
|
|
||||||
|
return score;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Pile merged_pile = merged_pile_;
|
||||||
|
|
||||||
for(auto rot : config_.rotations) {
|
for(auto rot : config_.rotations) {
|
||||||
|
|
||||||
item.translation(initial_tr);
|
item.translation(initial_tr);
|
||||||
|
@ -822,57 +759,6 @@ private:
|
||||||
ecache.back().accuracy(config_.accuracy);
|
ecache.back().accuracy(config_.accuracy);
|
||||||
}
|
}
|
||||||
|
|
||||||
Shapes pile;
|
|
||||||
pile.reserve(items_.size()+1);
|
|
||||||
// double pile_area = 0;
|
|
||||||
for(Item& mitem : items_) {
|
|
||||||
pile.emplace_back(mitem.transformedShape());
|
|
||||||
// pile_area += mitem.area();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto merged_pile = nfp::merge(pile);
|
|
||||||
auto& bin = bin_;
|
|
||||||
double norm = norm_;
|
|
||||||
auto pbb = sl::boundingBox(merged_pile);
|
|
||||||
auto binbb = sl::boundingBox(bin);
|
|
||||||
|
|
||||||
// This is the kernel part of the object function that is
|
|
||||||
// customizable by the library client
|
|
||||||
std::function<double(const Item&)> _objfunc;
|
|
||||||
if(config_.object_function) _objfunc = config_.object_function;
|
|
||||||
else {
|
|
||||||
|
|
||||||
// Inside check has to be strict if no alignment was enabled
|
|
||||||
std::function<double(const Box&)> ins_check;
|
|
||||||
if(config_.alignment == Config::Alignment::DONT_ALIGN)
|
|
||||||
ins_check = [&binbb, norm](const Box& fullbb) {
|
|
||||||
double ret = 0;
|
|
||||||
if(!sl::isInside(fullbb, binbb))
|
|
||||||
ret += norm;
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
else
|
|
||||||
ins_check = [&bin](const Box& fullbb) {
|
|
||||||
double miss = overfit(fullbb, bin);
|
|
||||||
miss = miss > 0? miss : 0;
|
|
||||||
return std::pow(miss, 2);
|
|
||||||
};
|
|
||||||
|
|
||||||
_objfunc = [norm, binbb, pbb, ins_check](const Item& item)
|
|
||||||
{
|
|
||||||
auto ibb = item.boundingBox();
|
|
||||||
auto fullbb = sl::boundingBox(pbb, ibb);
|
|
||||||
|
|
||||||
double score = pl::distance(ibb.center(),
|
|
||||||
binbb.center());
|
|
||||||
score /= norm;
|
|
||||||
|
|
||||||
score += ins_check(fullbb);
|
|
||||||
|
|
||||||
return score;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Our object function for placement
|
// Our object function for placement
|
||||||
auto rawobjfunc = [_objfunc, iv, startpos]
|
auto rawobjfunc = [_objfunc, iv, startpos]
|
||||||
(Vertex v, Item& itm)
|
(Vertex v, Item& itm)
|
||||||
|
@ -1041,6 +927,7 @@ private:
|
||||||
|
|
||||||
item.translation(final_tr);
|
item.translation(final_tr);
|
||||||
item.rotation(final_rot);
|
item.rotation(final_rot);
|
||||||
|
merged_pile_ = nfp::merge(merged_pile, item.transformedShape());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(can_pack) {
|
if(can_pack) {
|
||||||
|
|
Loading…
Reference in a new issue