Performance improvements and cleanup
This commit is contained in:
parent
0bfbe18a3c
commit
2f65bcc83f
@ -479,13 +479,18 @@ class _NofitPolyPlacer: public PlacerBoilerplate<_NofitPolyPlacer<RawShape, TBin
|
||||
|
||||
using MaxNfpLevel = nfp::MaxNfpLevel<RawShape>;
|
||||
|
||||
// Norming factor for the optimization function
|
||||
const double norm_;
|
||||
|
||||
public:
|
||||
|
||||
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):
|
||||
Base(bin),
|
||||
norm_(std::sqrt(sl::area(bin)))
|
||||
@ -576,6 +581,20 @@ private:
|
||||
|
||||
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>)
|
||||
{
|
||||
using namespace nfp;
|
||||
@ -616,135 +635,9 @@ private:
|
||||
template<class Level>
|
||||
Shapes calcnfp(const Item &trsh, Level)
|
||||
{ // Function for arbitrary level of nfp implementation
|
||||
using namespace nfp;
|
||||
|
||||
Shapes nfps;
|
||||
|
||||
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;
|
||||
}
|
||||
// TODO: implement
|
||||
return {};
|
||||
}
|
||||
|
||||
struct Optimum {
|
||||
@ -798,6 +691,50 @@ private:
|
||||
Radians final_rot = initial_rot;
|
||||
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) {
|
||||
|
||||
item.translation(initial_tr);
|
||||
@ -822,57 +759,6 @@ private:
|
||||
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
|
||||
auto rawobjfunc = [_objfunc, iv, startpos]
|
||||
(Vertex v, Item& itm)
|
||||
@ -1041,6 +927,7 @@ private:
|
||||
|
||||
item.translation(final_tr);
|
||||
item.rotation(final_rot);
|
||||
merged_pile_ = nfp::merge(merged_pile, item.transformedShape());
|
||||
}
|
||||
|
||||
if(can_pack) {
|
||||
|
Loading…
Reference in New Issue
Block a user