mirror of
https://github.com/QIDITECH/QIDIStudio.git
synced 2026-02-07 04:11:50 +03:00
update src
This commit is contained in:
@@ -656,7 +656,7 @@ inline std::string toString(const S& /*sh*/)
|
||||
}
|
||||
|
||||
template<Formats, class S>
|
||||
inline std::string serialize(const S& /*sh*/, double /*scale*/=1, std::string fill = "none", std::string stroke = "black", float stroke_width = 1)
|
||||
inline std::string serialize(const S & /*sh*/, const std::string &name = "", double /*scale*/ = 1, std::string fill = "none", std::string stroke = "black", float stroke_width = 1)
|
||||
{
|
||||
static_assert(always_false<S>::value,
|
||||
"shapelike::serialize() unimplemented!");
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <libnest2d/geometry_traits.hpp>
|
||||
#define LARGE_COST_TO_REJECT 1e7
|
||||
#define COST_OF_NEW_PLATE 0.1
|
||||
|
||||
namespace libnest2d {
|
||||
|
||||
@@ -75,8 +76,8 @@ class _Item {
|
||||
|
||||
public:
|
||||
int itemid_{ 0 };
|
||||
std::vector<int> extrude_ids;
|
||||
int filament_temp_type = -1; // -1 means unset. otherwise should be {0,1,2}
|
||||
std::map<int, std::string> extrude_id_filament_types; // extrude id to filament type
|
||||
int filament_temp_type = -1; // -1 means unset. otherwise should be one of FilamentTempType ie {0,1,2}
|
||||
double height{ 0 };
|
||||
double print_temp{ 0 };
|
||||
double bed_temp{ 0 };
|
||||
@@ -85,7 +86,9 @@ public:
|
||||
//QDS: virtual object to mark unprintable region on heatbed
|
||||
bool is_virt_object{ false };
|
||||
bool is_wipe_tower{ false };
|
||||
bool has_tried_with_excluded{ false };
|
||||
bool is_extrusion_cali_object{ false };
|
||||
bool has_tried_without_extrusion_cali_obj{ false };
|
||||
std::vector<double> allowed_rotations{0.};
|
||||
|
||||
/// The type of the shape which was handed over as the template argument.
|
||||
using ShapeType = RawShape;
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#include "placer_boilerplate.hpp"
|
||||
|
||||
// temporary
|
||||
//#include "../tools/svgtools.hpp"
|
||||
//#include <iomanip> // setprecision
|
||||
#include "../tools/svgtools.hpp"
|
||||
#include <iomanip> // setprecision
|
||||
|
||||
#include <libnest2d/parallel.hpp>
|
||||
|
||||
@@ -130,6 +130,9 @@ struct NfpPConfig {
|
||||
|
||||
//QDS: sort function for selector
|
||||
std::function<bool(_Item<RawShape>& i1, _Item<RawShape>& i2)> sortfunc;
|
||||
|
||||
std::function<void(const std::string &)> progressFunc = {};
|
||||
|
||||
//QDS: excluded region for V4 bed
|
||||
std::vector<_Item<RawShape> > m_excluded_regions;
|
||||
_ItemGroup<RawShape> m_excluded_items;
|
||||
@@ -557,10 +560,12 @@ public:
|
||||
template<class Range = ConstItemRange<typename Base::DefaultIter>>
|
||||
PackResult trypack(Item& item,
|
||||
const Range& remaining = Range()) {
|
||||
auto result = _trypack(item, remaining);
|
||||
if (item.is_wipe_tower) {
|
||||
PackResult result1 = _trypack_with_original_pos(item);
|
||||
if (result1.score() >= 0 && result1.score() < LARGE_COST_TO_REJECT) return result1;
|
||||
}
|
||||
|
||||
// Experimental
|
||||
// if(!result) repack(item, result);
|
||||
auto result = _trypack(item, remaining);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -685,11 +690,20 @@ private:
|
||||
};
|
||||
|
||||
using Edges = EdgeCache<RawShape>;
|
||||
// item won't overlap with virtual objects if it's inside or touches NFP
|
||||
// @return 1 if current item overlaps with virtual objects, 0 otherwise
|
||||
bool overlapWithVirtObject(const Item& item, const Box& binbb){
|
||||
if (items_.empty()) return 0;
|
||||
Shapes nfps = calcnfp(item, binbb, Lvl<MaxNfpLevel::value>());
|
||||
auto v = item.referenceVertex();
|
||||
for (const RawShape &nfp : nfps) {
|
||||
if (sl::isInside(v, nfp) || sl::touches(v, nfp)) { return false; }
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
template<class Range = ConstItemRange<typename Base::DefaultIter>>
|
||||
PackResult _trypack(
|
||||
Item& item,
|
||||
const Range& remaining = Range()) {
|
||||
PackResult _trypack(Item& item, const Range& remaining = Range()) {
|
||||
|
||||
PackResult ret;
|
||||
|
||||
@@ -755,41 +769,41 @@ private:
|
||||
};
|
||||
}
|
||||
|
||||
bool first_object = std::all_of(items_.begin(), items_.end(), [&](const Item &rawShape) { return rawShape.is_virt_object && !rawShape.is_wipe_tower; });
|
||||
for (auto &it : items_) {
|
||||
config_.progressFunc((boost::format("_trypack: plate: %4%, existing object: %1%, pos: (%2%, %3%)") % it.get().name % unscale_(it.get().translation()[0]) %
|
||||
unscale_(it.get().translation()[1]) % plateID())
|
||||
.str());
|
||||
}
|
||||
|
||||
// item won't overlap with virtual objects if it's inside or touches NFP
|
||||
// @return 1 if current item overlaps with virtual objects, 0 otherwise
|
||||
auto overlapWithVirtObject = [&]() -> double {
|
||||
if (items_.empty()) return 0;
|
||||
nfps = calcnfp(item, binbb, Lvl<MaxNfpLevel::value>());
|
||||
auto v = item.referenceVertex();
|
||||
for (const RawShape &nfp : nfps) {
|
||||
if (sl::isInside(v, nfp) || sl::touches(v, nfp)) { return 0; }
|
||||
}
|
||||
return 1;
|
||||
};
|
||||
bool first_object = std::all_of(items_.begin(), items_.end(), [&](const Item &rawShape) { return rawShape.is_virt_object && !rawShape.is_wipe_tower; });
|
||||
|
||||
if (first_object) {
|
||||
setInitialPosition(item);
|
||||
auto best_tr = item.translation();
|
||||
auto best_rot = item.rotation();
|
||||
best_overfit = overfit(item.transformedShape(), bin_) + overlapWithVirtObject();
|
||||
best_overfit = std::numeric_limits<double>::max();
|
||||
|
||||
// try normal inflation first, then 0 inflation if not fit. See STUDIO-5566.
|
||||
// Note for by-object printing, bed is expanded by -config_.bed_shrink.x().
|
||||
Coord inflation_back = item.inflation();
|
||||
Coord inflations[2]={inflation_back, std::abs(config_.bed_shrink.x())};
|
||||
Coord inflations[2]={inflation_back, 0};
|
||||
for (size_t i = 0; i < 2; i++) {
|
||||
item.inflation(inflations[i]);
|
||||
for (auto rot : config_.rotations) {
|
||||
for (auto rot : item.allowed_rotations) {
|
||||
item.translation(initial_tr);
|
||||
item.rotation(initial_rot + rot);
|
||||
setInitialPosition(item);
|
||||
double of = overfit(item.transformedShape(), bin_);
|
||||
if (of + overlapWithVirtObject() < best_overfit) {
|
||||
best_overfit = of;
|
||||
best_tr = item.translation();
|
||||
best_rot = item.rotation();
|
||||
if (!overlapWithVirtObject(item, binbb)) {
|
||||
double of = overfit(item.transformedShape(), bin_);
|
||||
if (of < best_overfit) {
|
||||
best_overfit = of;
|
||||
best_tr = item.translation();
|
||||
best_rot = item.rotation();
|
||||
if (best_overfit <= 0) {
|
||||
config_.progressFunc("First object " + item.name + " can fit with rot=" + std::to_string(rot));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
can_pack = best_overfit <= 0;
|
||||
@@ -806,7 +820,7 @@ private:
|
||||
|
||||
Pile merged_pile = merged_pile_;
|
||||
|
||||
for(auto rot : config_.rotations) {
|
||||
for(auto rot : item.allowed_rotations) {
|
||||
|
||||
item.translation(initial_tr);
|
||||
item.rotation(initial_rot + rot);
|
||||
@@ -991,6 +1005,7 @@ private:
|
||||
final_rot = initial_rot + rot;
|
||||
can_pack = true;
|
||||
global_score = best_score;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -998,41 +1013,7 @@ private:
|
||||
item.rotation(final_rot);
|
||||
}
|
||||
|
||||
#ifdef SVGTOOLS_HPP
|
||||
if (config_.save_svg) {
|
||||
svg::SVGWriter<RawShape> svgwriter;
|
||||
Box binbb2(binbb.width() * 2, binbb.height() * 2, binbb.center()); // expand bbox to allow object be drawed outside
|
||||
svgwriter.setSize(binbb2);
|
||||
svgwriter.conf_.x0 = binbb.width();
|
||||
svgwriter.conf_.y0 = -binbb.height() / 2; // origin is top left corner
|
||||
svgwriter.add_comment("bed");
|
||||
svgwriter.writeShape(box2RawShape(binbb), "none", "black");
|
||||
svgwriter.add_comment("nfps");
|
||||
for (int i = 0; i < nfps.size(); i++) svgwriter.writeShape(nfps[i], "none", "blue");
|
||||
for (int i = 0; i < items_.size(); i++) {
|
||||
svgwriter.add_comment(items_[i].get().name);
|
||||
svgwriter.writeItem(items_[i], "none", "black");
|
||||
}
|
||||
svgwriter.add_comment("merged_pile_");
|
||||
for (int i = 0; i < merged_pile_.size(); i++) svgwriter.writeShape(merged_pile_[i], "none", "yellow");
|
||||
svgwriter.add_comment("current item");
|
||||
svgwriter.writeItem(item, "red", "red", 2);
|
||||
|
||||
std::stringstream ss;
|
||||
ss.setf(std::ios::fixed | std::ios::showpoint);
|
||||
ss.precision(1);
|
||||
ss << "t=" << round(item.translation().x() / 1e6) << ","
|
||||
<< round(item.translation().y() / 1e6)
|
||||
//<< "-rot=" << round(item.rotation().toDegrees())
|
||||
<< "-sco=" << round(global_score);
|
||||
svgwriter.draw_text(20, 20, ss.str(), "blue", 20);
|
||||
ss.str("");
|
||||
ss << "items.size=" << items_.size() << "-merged_pile.size=" << merged_pile_.size();
|
||||
svgwriter.draw_text(20, 40, ss.str(), "blue", 20);
|
||||
svgwriter.save(boost::filesystem::path("C:/Users/arthur.tang/AppData/Roaming/QIDIStudioInternal/SVG") /
|
||||
("nfpplacer_" + std::to_string(plate_id) + "_" + ss.str() + "_" + item.name + ".svg"));
|
||||
}
|
||||
#endif
|
||||
if (config_.save_svg) saveSVG(binbb, nfps, item, global_score, can_pack);
|
||||
|
||||
if(can_pack) {
|
||||
ret = PackResult(item);
|
||||
@@ -1045,6 +1026,87 @@ private:
|
||||
return ret;
|
||||
}
|
||||
|
||||
PackResult _trypack_with_original_pos(Item &item)
|
||||
{
|
||||
PackResult ret;
|
||||
|
||||
bool can_pack = false;
|
||||
double best_overfit = std::numeric_limits<double>::max();
|
||||
double global_score = std::numeric_limits<double>::max();
|
||||
|
||||
auto initial_tr = item.translation();
|
||||
auto initial_rot = item.rotation();
|
||||
Vertex final_tr = initial_tr;
|
||||
Radians final_rot = initial_rot;
|
||||
Shapes nfps;
|
||||
|
||||
auto binbb = sl::boundingBox(bin_);
|
||||
|
||||
for (auto &it : items_) {
|
||||
config_.progressFunc((boost::format("_trypack_with_original_pos: plate: %4%, existing object: %1%, pos: (%2%, %3%)") % it.get().name % unscale_(it.get().translation()[0]) %
|
||||
unscale_(it.get().translation()[1]) % plateID())
|
||||
.str());
|
||||
}
|
||||
|
||||
{
|
||||
for (auto rot : item.allowed_rotations) {
|
||||
item.translation(initial_tr);
|
||||
item.rotation(initial_rot + rot);
|
||||
|
||||
if (!overlapWithVirtObject(item, binbb)) {
|
||||
can_pack = true;
|
||||
final_tr = initial_tr;
|
||||
final_rot = initial_rot + rot;
|
||||
global_score = 0.3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
item.translation(final_tr);
|
||||
item.rotation(final_rot);
|
||||
}
|
||||
|
||||
if (config_.save_svg) saveSVG(binbb, nfps, item, global_score, can_pack);
|
||||
|
||||
if (can_pack) {
|
||||
ret = PackResult(item);
|
||||
ret.score_ = global_score;
|
||||
// merged_pile_ = nfp::merge(merged_pile_, item.transformedShape());
|
||||
config_.progressFunc((boost::format("_trypack_with_original_pos: item %1% can pack") % item.name).str());
|
||||
} else {
|
||||
ret = PackResult(best_overfit);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void saveSVG(Box &binbb, Shapes &nfps, Item &item, double global_score, bool can_pack)
|
||||
{
|
||||
svg::SVGWriter<RawShape> svgwriter;
|
||||
Box binbb2(binbb.width() * 2, binbb.height() * 2, binbb.center()); // expand bbox to allow object be drawed outside
|
||||
svgwriter.setSize(binbb2);
|
||||
svgwriter.conf_.x0 = binbb.width();
|
||||
svgwriter.conf_.y0 = -binbb.height() / 2; // origin is top left corner
|
||||
svgwriter.writeShape(box2RawShape(binbb), "bed", "none", "black");
|
||||
for (int i = 0; i < nfps.size(); i++) svgwriter.writeShape(nfps[i], "nfp_" + std::to_string(i), "none", "blue", 0.2);
|
||||
for (int i = 0; i < items_.size(); i++) { svgwriter.writeItem(items_[i], items_[i].get().name, "none", "black", 0.2); }
|
||||
for (int i = 0; i < merged_pile_.size(); i++) svgwriter.writeShape(merged_pile_[i], "merged_pile_" + std::to_string(i), "none", "yellow", 0.2);
|
||||
svgwriter.writeItem(item, item.name, "red", "red", 0.3);
|
||||
|
||||
std::stringstream ss;
|
||||
ss.setf(std::ios::fixed | std::ios::showpoint);
|
||||
ss.precision(1);
|
||||
ss << "t=" << round(item.translation().x() / 1e6) << ","
|
||||
<< round(item.translation().y() / 1e6)
|
||||
//<< "-rot=" << round(item.rotation().toDegrees())
|
||||
<< "-sco=" << round(global_score);
|
||||
svgwriter.draw_text(20, 20, ss.str(), "blue", 10);
|
||||
ss.str("");
|
||||
ss << "items.size=" << items_.size() << "-merged_pile.size=" << merged_pile_.size();
|
||||
svgwriter.draw_text(20, 40, ss.str(), "blue", 10);
|
||||
svgwriter.save(boost::filesystem::path("SVG") / ("plate_" + std::to_string(plate_id) + "_" + ss.str() + "_" + item.name + "_canPack=" + std::to_string(can_pack) + ".svg"));
|
||||
}
|
||||
|
||||
RawShape box2RawShape(Box& bbin)
|
||||
{
|
||||
RawShape binrsh;
|
||||
@@ -1158,16 +1220,7 @@ private:
|
||||
auto d = cb - ci;
|
||||
|
||||
// QDS make sure the item won't clash with excluded regions
|
||||
// do we have wipe tower after arranging?
|
||||
size_t n_objs = 0;
|
||||
std::set<int> extruders;
|
||||
for (const Item& item : items_) {
|
||||
if (!item.is_virt_object) {
|
||||
extruders.insert(item.extrude_ids.begin(), item.extrude_ids.end());
|
||||
n_objs++;
|
||||
}
|
||||
}
|
||||
bool need_wipe_tower = extruders.size() > 1;
|
||||
|
||||
std::vector<RawShape> objs,excludes;
|
||||
for (Item &item : items_) {
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
|
||||
std::vector<Placer> placers;
|
||||
placers.reserve(last-first);
|
||||
|
||||
|
||||
typename Base::PackGroup fixed_bins;
|
||||
std::for_each(first, last, [this, &fixed_bins](Item& itm) {
|
||||
if (itm.isFixed()) {
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
std::for_each(first, last, [this,&svgwriter](Item &itm) { svgwriter.writeShape(itm, "none", "blue"); });
|
||||
svgwriter.save(boost::filesystem::path("SVG") / "all_items.svg");
|
||||
#endif
|
||||
|
||||
|
||||
std::function<bool(Item& i1, Item& i2)> sortfunc;
|
||||
if (pconfig.sortfunc)
|
||||
sortfunc = pconfig.sortfunc;
|
||||
@@ -88,7 +88,23 @@ public:
|
||||
for (auto it = store_.begin(); it != store_.end(); ++it) {
|
||||
std::stringstream ss;
|
||||
ss << "initial order: " << it->get().name << ", p=" << it->get().priority() << ", bed_temp=" << it->get().bed_temp << ", height=" << it->get().height
|
||||
<< ", area=" << it->get().area();
|
||||
<< ", area=" << it->get().area() << ", allowed_rotations=";
|
||||
for(auto r: it->get().allowed_rotations) ss << r << ", ";
|
||||
if (this->unfitindicator_)
|
||||
this->unfitindicator_(ss.str());
|
||||
}
|
||||
// debug: write down fixed items
|
||||
for (size_t i = 0; i < fixed_bins.size(); i++) {
|
||||
if (fixed_bins[i].empty())
|
||||
continue;
|
||||
std::stringstream ss;
|
||||
ss << "fixed bin " << i << ": ";
|
||||
for (auto it = fixed_bins[i].begin(); it != fixed_bins[i].end(); ++it) {
|
||||
ss << it->get().name << ", p=" << it->get().priority() << ", bed_temp=" << it->get().bed_temp << ", height=" << it->get().height
|
||||
<< ", area=" << it->get().area() << ", allowed_rotations=";
|
||||
for(auto r: it->get().allowed_rotations) ss << r << ", ";
|
||||
ss << "; ";
|
||||
}
|
||||
if (this->unfitindicator_)
|
||||
this->unfitindicator_(ss.str());
|
||||
}
|
||||
@@ -101,8 +117,8 @@ public:
|
||||
};
|
||||
|
||||
auto& cancelled = this->stopcond_;
|
||||
|
||||
this->template remove_unpackable_items<Placer>(store_, bin, pconfig);
|
||||
|
||||
//this->template remove_unpackable_items<Placer>(store_, bin, pconfig);
|
||||
|
||||
for (auto it = store_.begin(); it != store_.end() && !cancelled(); ++it) {
|
||||
// skip unpackable item
|
||||
@@ -115,13 +131,21 @@ public:
|
||||
double score_all_plates = 0, score_all_plates_best = std::numeric_limits<double>::max();
|
||||
typename Placer::PackResult result, result_best, result_firstfit;
|
||||
int j = 0;
|
||||
while(!was_packed && !cancelled()) {
|
||||
for(; j < placers.size() && !was_packed && !cancelled(); j++) {
|
||||
while (!was_packed && !cancelled() && placers.size() <= MAX_NUM_PLATES) {
|
||||
for(; j < placers.size() && !was_packed && !cancelled() && j<MAX_NUM_PLATES; j++) {
|
||||
if (it->get().is_wipe_tower && it->get().binId() != placers[j].plateID()) {
|
||||
if (this->unfitindicator_)
|
||||
this->unfitindicator_(it->get().name + " cant be placed in plate_id=" + std::to_string(j) + "/" + std::to_string(placers.size()) + ", continue to next plate");
|
||||
continue;
|
||||
}
|
||||
result = placers[j].pack(*it, rem(it, store_));
|
||||
score = result.score();
|
||||
score_all_plates = score;
|
||||
score_all_plates = score + COST_OF_NEW_PLATE * j; // add a larger cost to larger plate id to encourace to use less plates
|
||||
for (int i = 0; i < placers.size(); i++) { score_all_plates += placers[i].score();}
|
||||
if (this->unfitindicator_) this->unfitindicator_(it->get().name + " bed_id="+std::to_string(j) + ",score=" + std::to_string(score)+", score_all_plates="+std::to_string(score_all_plates));
|
||||
if (this->unfitindicator_)
|
||||
this->unfitindicator_((boost::format("item %1% bed_id=%2%, score=%3%, score_all_plates=%4%, pos=(%5%, %6%)") % it->get().name % j % score %
|
||||
score_all_plates % unscale_(it->get().translation()[0]) % unscale_(it->get().translation()[1]))
|
||||
.str());
|
||||
|
||||
if(score >= 0 && score < LARGE_COST_TO_REJECT) {
|
||||
if (bed_id_firstfit == -1) {
|
||||
@@ -161,42 +185,42 @@ public:
|
||||
makeProgress(placers[j], j);
|
||||
}
|
||||
|
||||
if (was_packed && it->get().has_tried_with_excluded) {
|
||||
placers[j].clearItems([](const Item &itm) { return itm.isFixed() && !itm.is_wipe_tower; });
|
||||
if (fixed_bins.size() >= placers.size())
|
||||
placers[j].preload(fixed_bins[placers.size() - 1]);
|
||||
}
|
||||
bool placer_not_packed = !was_packed && !placers.empty() && j == placers.size() && placers[j - 1].getPackedSize() == 0; // large item is not placed into the bin
|
||||
// if the object can't be packed, try to pack it without extrusion calibration object
|
||||
bool placer_not_packed = !was_packed && j > 0 && j == placers.size() && placers[j - 1].getPackedSize() == 0; // large item is not placed into the bin
|
||||
if (placer_not_packed) {
|
||||
if (it->get().has_tried_with_excluded == false) {
|
||||
it->get().has_tried_with_excluded = true;
|
||||
placers[j - 1].clearItems([](const Item &itm) { return itm.isFixed()&&!itm.is_wipe_tower; });
|
||||
placers[j - 1].preload(pconfig.m_excluded_items);
|
||||
if (it->get().has_tried_without_extrusion_cali_obj == false) {
|
||||
it->get().has_tried_without_extrusion_cali_obj = true;
|
||||
placers[j - 1].clearItems([](const Item &itm) { return itm.is_extrusion_cali_object; });
|
||||
j = j - 1;
|
||||
continue;
|
||||
} else {
|
||||
placers[j - 1].clearItems([](const Item &itm) { return itm.isFixed() && !itm.is_wipe_tower; });
|
||||
placers[j - 1].preload(fixed_bins[placers.size() - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
if(!was_packed){
|
||||
if (this->unfitindicator_ && !placers.empty())
|
||||
this->unfitindicator_(it->get().name + " not fit! height=" +std::to_string(it->get().height)
|
||||
+ " ,plate_id=" + std::to_string(j-1)
|
||||
+ ", score=" + std::to_string(score)
|
||||
+ ", best_bed_id=" + std::to_string(best_bed_id)
|
||||
+ ", score_all_plates=" + std::to_string(score_all_plates)
|
||||
+", overfit=" + std::to_string(result.overfit()));
|
||||
|
||||
placers.emplace_back(bin);
|
||||
placers.back().plateID(placers.size() - 1);
|
||||
placers.back().configure(pconfig);
|
||||
if (fixed_bins.size() >= placers.size())
|
||||
placers.back().preload(fixed_bins[placers.size() - 1]);
|
||||
//placers.back().preload(pconfig.m_excluded_items);
|
||||
packed_bins_.emplace_back();
|
||||
j = placers.size() - 1;
|
||||
this->unfitindicator_(it->get().name + " not fit! plate_id=" + std::to_string(placers.back().plateID()) + ", score=" + std::to_string(score) +
|
||||
", best_bed_id=" + std::to_string(best_bed_id) + ", score_all_plates=" + std::to_string(score_all_plates) +
|
||||
", item.bed_id=" + std::to_string(it->get().binId()));
|
||||
if (!placers.empty() && placers.back().getItems().empty()) {
|
||||
it->get().binId(BIN_ID_UNFIT);
|
||||
if (this->unfitindicator_) this->unfitindicator_(it->get().name + " can't fit into a new bin. Can't fit!");
|
||||
// remove the last empty placer to force next item to be fit in existing plates first
|
||||
if (placers.size() > 1) placers.pop_back();
|
||||
break;
|
||||
}
|
||||
if (placers.size() < MAX_NUM_PLATES) {
|
||||
placers.emplace_back(bin);
|
||||
placers.back().plateID(placers.size() - 1);
|
||||
placers.back().configure(pconfig);
|
||||
if (fixed_bins.size() >= placers.size()) placers.back().preload(fixed_bins[placers.size() - 1]);
|
||||
// placers.back().preload(pconfig.m_excluded_items);
|
||||
packed_bins_.emplace_back();
|
||||
j = placers.size() - 1;
|
||||
} else {
|
||||
it->get().binId(BIN_ID_UNFIT);
|
||||
if (this->unfitindicator_) this->unfitindicator_(it->get().name + " can't fit into any bin. Can't fit!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,7 +443,7 @@ inline void offset(PolygonImpl& sh, bp2d::Coord distance)
|
||||
|
||||
#ifndef DISABLE_BOOST_SERIALIZE
|
||||
template<> inline std::string serialize<libnest2d::Formats::SVG>(
|
||||
const PolygonImpl& sh, double scale, std::string fill, std::string stroke, float stroke_width)
|
||||
const PolygonImpl& sh, const std::string& name, double scale, std::string fill, std::string stroke, float stroke_width)
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::string style = "fill: "+fill+"; stroke: "+stroke+"; stroke-width: "+std::to_string(stroke_width)+"px; ";
|
||||
@@ -478,7 +478,14 @@ template<> inline std::string serialize<libnest2d::Formats::SVG>(
|
||||
|
||||
ss << svg_data << std::endl;
|
||||
|
||||
return ss.str();
|
||||
std::string svg_content = ss.str();
|
||||
if (!name.empty()) {
|
||||
size_t pos = svg_content.find_first_of("<g ");
|
||||
if (pos != std::string::npos) { svg_content.insert(pos + 3, "id=\"" + name + "\" ");
|
||||
}
|
||||
}
|
||||
|
||||
return svg_content;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ public:
|
||||
|
||||
inline Radians angleToX() const {
|
||||
double ret = std::atan2(getY(axis_), getX(axis_));
|
||||
// horizontal or vertical up-right rectangles are not distinguished, but we need to get the horizontal one
|
||||
if (abs(ret) < EPSILON && abs(bottom_) < abs(right_)) ret += Pi / 2;
|
||||
auto s = std::signbit(ret);
|
||||
if(s) ret += Pi_2;
|
||||
return -ret;
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
double x0, y0;
|
||||
Config():
|
||||
origo_location(BOTTOMLEFT), mm_in_coord_units(1000000),
|
||||
width(500), height(500),x0(100) {}
|
||||
width(500), height(500),x0(100),y0(0) {}
|
||||
|
||||
};
|
||||
|
||||
@@ -47,14 +47,15 @@ public:
|
||||
|
||||
void setSize(const Box &box) {
|
||||
conf_.x0 = box.width() / 5;
|
||||
conf_.x0 = box.height() / 5;
|
||||
conf_.y0 = box.height() / 5;
|
||||
conf_.height = static_cast<double>(box.height() + conf_.y0*2) /
|
||||
conf_.mm_in_coord_units;
|
||||
conf_.width = static_cast<double>(box.width() + conf_.x0*2) /
|
||||
conf_.mm_in_coord_units;
|
||||
}
|
||||
|
||||
void writeShape(RawShape tsh, std::string fill = "none", std::string stroke = "black", float stroke_width = 1) {
|
||||
void writeShape(RawShape tsh, const std::string &name = "", std::string fill = "none", std::string stroke = "black", float stroke_width = 1)
|
||||
{
|
||||
if(svg_layers_.empty()) addLayer();
|
||||
if(conf_.origo_location == BOTTOMLEFT) {
|
||||
auto d = static_cast<Coord>(
|
||||
@@ -74,13 +75,14 @@ public:
|
||||
}
|
||||
}
|
||||
currentLayer() +=
|
||||
shapelike::serialize<Formats::SVG>(tsh,
|
||||
shapelike::serialize<Formats::SVG>(tsh, name,
|
||||
1.0 / conf_.mm_in_coord_units, fill, stroke, stroke_width) +
|
||||
"\n";
|
||||
}
|
||||
|
||||
void writeItem(const Item& item, std::string fill = "none", std::string stroke = "black", float stroke_width = 1) {
|
||||
writeShape(item.transformedShape(), fill, stroke, stroke_width);
|
||||
void writeItem(const Item &item, const std::string &name = "", std::string fill = "none", std::string stroke = "black", float stroke_width = 1)
|
||||
{
|
||||
writeShape(item.transformedShape(), name, fill, stroke, stroke_width);
|
||||
}
|
||||
|
||||
void writePackGroup(const PackGroup& result) {
|
||||
@@ -97,7 +99,7 @@ public:
|
||||
auto it = from;
|
||||
PackGroup pg;
|
||||
while(it != to) {
|
||||
if(it->binId() == BIN_ID_UNSET) continue;
|
||||
if (it->binId() == BIN_ID_UNFIT) continue;
|
||||
while(pg.size() <= size_t(it->binId())) pg.emplace_back();
|
||||
pg[it->binId()].emplace_back(*it);
|
||||
++it;
|
||||
@@ -159,6 +161,8 @@ public:
|
||||
currentLayer() += "<!-- " + comment + " -->\n";
|
||||
}
|
||||
|
||||
void clear() { svg_layers_.clear(); }
|
||||
|
||||
private:
|
||||
|
||||
std::string& currentLayer() { return svg_layers_.back(); }
|
||||
|
||||
Reference in New Issue
Block a user