Extend libnest tests, remove some warnings, faster catch2 compilation.
Also, improve libnest2d::nest interface.
This commit is contained in:
parent
555fcc151d
commit
72ac8d68f0
@ -49,91 +49,84 @@ using BottomLeftPlacer = placers::_BottomLeftPlacer<PolygonImpl>;
|
|||||||
|
|
||||||
extern template class Nester<NfpPlacer, FirstFitSelection>;
|
extern template class Nester<NfpPlacer, FirstFitSelection>;
|
||||||
extern template class Nester<BottomLeftPlacer, FirstFitSelection>;
|
extern template class Nester<BottomLeftPlacer, FirstFitSelection>;
|
||||||
extern template PackGroup Nester<NfpPlacer, FirstFitSelection>::execute(
|
extern template std::size_t Nester<NfpPlacer, FirstFitSelection>::execute(
|
||||||
std::vector<Item>::iterator, std::vector<Item>::iterator);
|
std::vector<Item>::iterator, std::vector<Item>::iterator);
|
||||||
extern template PackGroup Nester<BottomLeftPlacer, FirstFitSelection>::execute(
|
extern template std::size_t Nester<BottomLeftPlacer, FirstFitSelection>::execute(
|
||||||
std::vector<Item>::iterator, std::vector<Item>::iterator);
|
std::vector<Item>::iterator, std::vector<Item>::iterator);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<class Placer = NfpPlacer,
|
template<class Placer = NfpPlacer, class Selector = FirstFitSelection>
|
||||||
class Selector = FirstFitSelection,
|
struct NestConfig {
|
||||||
class Iterator = std::vector<Item>::iterator>
|
typename Placer::Config placer_config;
|
||||||
void nest(Iterator from, Iterator to,
|
typename Selector::Config selector_config;
|
||||||
const typename Placer::BinType& bin,
|
using Placement = typename Placer::Config;
|
||||||
Coord dist = 0,
|
using Selection = typename Selector::Config;
|
||||||
const typename Placer::Config& pconf = {},
|
|
||||||
const typename Selector::Config& sconf = {})
|
NestConfig() = default;
|
||||||
{
|
NestConfig(const typename Placer::Config &cfg) : placer_config{cfg} {}
|
||||||
_Nester<Placer, Selector> nester(bin, dist, pconf, sconf);
|
NestConfig(const typename Selector::Config &cfg) : selector_config{cfg} {}
|
||||||
nester.execute(from, to);
|
NestConfig(const typename Placer::Config & pcfg,
|
||||||
}
|
const typename Selector::Config &scfg)
|
||||||
|
: placer_config{pcfg}, selector_config{scfg} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NestControl {
|
||||||
|
ProgressFunction progressfn;
|
||||||
|
StopCondition stopcond = []{ return false; };
|
||||||
|
|
||||||
|
NestControl() = default;
|
||||||
|
NestControl(ProgressFunction pr) : progressfn{std::move(pr)} {}
|
||||||
|
NestControl(StopCondition sc) : stopcond{std::move(sc)} {}
|
||||||
|
NestControl(ProgressFunction pr, StopCondition sc)
|
||||||
|
: progressfn{std::move(pr)}, stopcond{std::move(sc)}
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
template<class Placer = NfpPlacer,
|
template<class Placer = NfpPlacer,
|
||||||
class Selector = FirstFitSelection,
|
class Selector = FirstFitSelection,
|
||||||
class Iterator = std::vector<Item>::iterator>
|
class Iterator = std::vector<Item>::iterator>
|
||||||
void nest(Iterator from, Iterator to,
|
std::size_t nest(Iterator from, Iterator to,
|
||||||
const typename Placer::BinType& bin,
|
const typename Placer::BinType & bin,
|
||||||
ProgressFunction prg,
|
Coord dist = 0,
|
||||||
StopCondition scond = []() { return false; },
|
const NestConfig<Placer, Selector> &cfg = {},
|
||||||
Coord dist = 0,
|
NestControl ctl = {})
|
||||||
const typename Placer::Config& pconf = {},
|
|
||||||
const typename Selector::Config& sconf = {})
|
|
||||||
{
|
{
|
||||||
_Nester<Placer, Selector> nester(bin, dist, pconf, sconf);
|
_Nester<Placer, Selector> nester{bin, dist, cfg.placer_config, cfg.selector_config};
|
||||||
if(prg) nester.progressIndicator(prg);
|
if(ctl.progressfn) nester.progressIndicator(ctl.progressfn);
|
||||||
if(scond) nester.stopCondition(scond);
|
if(ctl.stopcond) nester.stopCondition(ctl.stopcond);
|
||||||
nester.execute(from, to);
|
return nester.execute(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LIBNEST2D_STATIC
|
#ifdef LIBNEST2D_STATIC
|
||||||
|
|
||||||
extern template class Nester<NfpPlacer, FirstFitSelection>;
|
extern template class Nester<NfpPlacer, FirstFitSelection>;
|
||||||
extern template class Nester<BottomLeftPlacer, FirstFitSelection>;
|
extern template class Nester<BottomLeftPlacer, FirstFitSelection>;
|
||||||
|
extern template std::size_t nest(std::vector<Item>::iterator from,
|
||||||
extern template void nest(std::vector<Item>::iterator from,
|
std::vector<Item>::iterator from to,
|
||||||
std::vector<Item>::iterator to,
|
const Box & bin,
|
||||||
const Box& bin,
|
Coord dist,
|
||||||
Coord dist = 0,
|
const NestConfig<NfpPlacer, FirstFitSelection> &cfg,
|
||||||
const NfpPlacer::Config& pconf,
|
NestControl ctl);
|
||||||
const FirstFitSelection::Config& sconf);
|
extern template std::size_t nest(std::vector<Item>::iterator from,
|
||||||
|
std::vector<Item>::iterator from to,
|
||||||
extern template void nest(std::vector<Item>::iterator from,
|
const Box & bin,
|
||||||
std::vector<Item>::iterator to,
|
Coord dist,
|
||||||
const Box& bin,
|
const NestConfig<BottomLeftPlacer, FirstFitSelection> &cfg,
|
||||||
ProgressFunction prg,
|
NestControl ctl);
|
||||||
StopCondition scond,
|
|
||||||
Coord dist = 0,
|
|
||||||
const NfpPlacer::Config& pconf,
|
|
||||||
const FirstFitSelection::Config& sconf);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<class Placer = NfpPlacer,
|
template<class Placer = NfpPlacer,
|
||||||
class Selector = FirstFitSelection,
|
class Selector = FirstFitSelection,
|
||||||
class Container = std::vector<Item>>
|
class Container = std::vector<Item>>
|
||||||
void nest(Container&& cont,
|
std::size_t nest(Container&& cont,
|
||||||
const typename Placer::BinType& bin,
|
const typename Placer::BinType & bin,
|
||||||
Coord dist = 0,
|
Coord dist = 0,
|
||||||
const typename Placer::Config& pconf = {},
|
const NestConfig<Placer, Selector> &cfg = {},
|
||||||
const typename Selector::Config& sconf = {})
|
NestControl ctl = {})
|
||||||
{
|
{
|
||||||
nest<Placer, Selector>(cont.begin(), cont.end(), bin, dist, pconf, sconf);
|
return nest<Placer, Selector>(cont.begin(), cont.end(), bin, dist, cfg, ctl);
|
||||||
}
|
|
||||||
|
|
||||||
template<class Placer = NfpPlacer,
|
|
||||||
class Selector = FirstFitSelection,
|
|
||||||
class Container = std::vector<Item>>
|
|
||||||
void nest(Container&& cont,
|
|
||||||
const typename Placer::BinType& bin,
|
|
||||||
ProgressFunction prg,
|
|
||||||
StopCondition scond = []() { return false; },
|
|
||||||
Coord dist = 0,
|
|
||||||
const typename Placer::Config& pconf = {},
|
|
||||||
const typename Selector::Config& sconf = {})
|
|
||||||
{
|
|
||||||
nest<Placer, Selector>(cont.begin(), cont.end(), bin, prg, scond, dist,
|
|
||||||
pconf, sconf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,11 @@ public:
|
|||||||
sh_(sl::create<RawShape>(std::move(contour), std::move(holes))) {}
|
sh_(sl::create<RawShape>(std::move(contour), std::move(holes))) {}
|
||||||
|
|
||||||
inline bool isFixed() const noexcept { return fixed_; }
|
inline bool isFixed() const noexcept { return fixed_; }
|
||||||
inline void markAsFixed(bool fixed = true) { fixed_ = fixed; }
|
inline void markAsFixedInBin(int binid)
|
||||||
|
{
|
||||||
|
fixed_ = binid >= 0;
|
||||||
|
binid_ = binid;
|
||||||
|
}
|
||||||
|
|
||||||
inline void binId(int idx) { binid_ = idx; }
|
inline void binId(int idx) { binid_ = idx; }
|
||||||
inline int binId() const noexcept { return binid_; }
|
inline int binId() const noexcept { return binid_; }
|
||||||
@ -748,6 +752,7 @@ template<class PlacementStrategy, class SelectionStrategy >
|
|||||||
class _Nester {
|
class _Nester {
|
||||||
using TSel = SelectionStrategyLike<SelectionStrategy>;
|
using TSel = SelectionStrategyLike<SelectionStrategy>;
|
||||||
TSel selector_;
|
TSel selector_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Item = typename PlacementStrategy::Item;
|
using Item = typename PlacementStrategy::Item;
|
||||||
using ShapeType = typename Item::ShapeType;
|
using ShapeType = typename Item::ShapeType;
|
||||||
@ -824,7 +829,7 @@ public:
|
|||||||
* the selection algorithm.
|
* the selection algorithm.
|
||||||
*/
|
*/
|
||||||
template<class It>
|
template<class It>
|
||||||
inline ItemIteratorOnly<It, void> execute(It from, It to)
|
inline ItemIteratorOnly<It, size_t> execute(It from, It to)
|
||||||
{
|
{
|
||||||
auto infl = static_cast<Coord>(std::ceil(min_obj_distance_/2.0));
|
auto infl = static_cast<Coord>(std::ceil(min_obj_distance_/2.0));
|
||||||
if(infl > 0) std::for_each(from, to, [this, infl](Item& item) {
|
if(infl > 0) std::for_each(from, to, [this, infl](Item& item) {
|
||||||
@ -837,6 +842,8 @@ public:
|
|||||||
if(min_obj_distance_ > 0) std::for_each(from, to, [infl](Item& item) {
|
if(min_obj_distance_ > 0) std::for_each(from, to, [infl](Item& item) {
|
||||||
item.inflate(-infl);
|
item.inflate(-infl);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return selector_.getResult().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a progress indicator function object for the selector.
|
/// Set a progress indicator function object for the selector.
|
||||||
|
@ -5,19 +5,17 @@ namespace libnest2d {
|
|||||||
template class Nester<NfpPlacer, FirstFitSelection>;
|
template class Nester<NfpPlacer, FirstFitSelection>;
|
||||||
template class Nester<BottomLeftPlacer, FirstFitSelection>;
|
template class Nester<BottomLeftPlacer, FirstFitSelection>;
|
||||||
|
|
||||||
template PackGroup nest(std::vector<Item>::iterator from,
|
template std::size_t nest(std::vector<Item>::iterator from,
|
||||||
std::vector<Item>::iterator to,
|
std::vector<Item>::iterator from to,
|
||||||
const Box& bin,
|
const Box & bin,
|
||||||
Coord dist = 0,
|
Coord dist,
|
||||||
const NfpPlacer::Config& pconf,
|
const NestConfig<NfpPlacer, FirstFitSelection> &cfg,
|
||||||
const FirstFitSelection::Config& sconf);
|
NestControl ctl);
|
||||||
|
|
||||||
template PackGroup nest(std::vector<Item>::iterator from,
|
template std::size_t nest(std::vector<Item>::iterator from,
|
||||||
std::vector<Item>::iterator to,
|
std::vector<Item>::iterator from to,
|
||||||
const Box& bin,
|
const Box & bin,
|
||||||
ProgressFunction prg,
|
Coord dist,
|
||||||
StopCondition scond,
|
const NestConfig<BottomLeftPlacer, FirstFitSelection> &cfg,
|
||||||
Coord dist = 0,
|
NestControl ctl);
|
||||||
const NfpPlacer::Config& pconf,
|
|
||||||
const FirstFitSelection::Config& sconf);
|
|
||||||
}
|
}
|
||||||
|
@ -375,7 +375,7 @@ public:
|
|||||||
|
|
||||||
for(unsigned idx = 0; idx < fixeditems.size(); ++idx) {
|
for(unsigned idx = 0; idx < fixeditems.size(); ++idx) {
|
||||||
Item& itm = fixeditems[idx];
|
Item& itm = fixeditems[idx];
|
||||||
itm.markAsFixed();
|
itm.markAsFixedInBin(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pck.configure(m_pconf);
|
m_pck.configure(m_pconf);
|
||||||
|
@ -1571,7 +1571,8 @@ struct Plater::priv
|
|||||||
|
|
||||||
size_t count = 0; // To know how much space to reserve
|
size_t count = 0; // To know how much space to reserve
|
||||||
for (auto obj : model.objects) count += obj->instances.size();
|
for (auto obj : model.objects) count += obj->instances.size();
|
||||||
m_selected.clear(), m_unselected.clear();
|
m_selected.clear();
|
||||||
|
m_unselected.clear();
|
||||||
m_selected.reserve(count + 1 /* for optional wti */);
|
m_selected.reserve(count + 1 /* for optional wti */);
|
||||||
m_unselected.reserve(count + 1 /* for optional wti */);
|
m_unselected.reserve(count + 1 /* for optional wti */);
|
||||||
}
|
}
|
||||||
@ -1585,11 +1586,12 @@ struct Plater::priv
|
|||||||
// Set up arrange polygon for a ModelInstance and Wipe tower
|
// Set up arrange polygon for a ModelInstance and Wipe tower
|
||||||
template<class T> ArrangePolygon get_arrange_poly(T *obj) const {
|
template<class T> ArrangePolygon get_arrange_poly(T *obj) const {
|
||||||
ArrangePolygon ap = obj->get_arrange_polygon();
|
ArrangePolygon ap = obj->get_arrange_polygon();
|
||||||
ap.priority = 0;
|
ap.priority = 0;
|
||||||
ap.bed_idx = ap.translation.x() / bed_stride();
|
ap.bed_idx = ap.translation.x() / bed_stride();
|
||||||
ap.setter = [obj, this](const ArrangePolygon &p) {
|
ap.setter = [obj, this](const ArrangePolygon &p) {
|
||||||
if (p.is_arranged()) {
|
if (p.is_arranged()) {
|
||||||
auto t = p.translation; t.x() += p.bed_idx * bed_stride();
|
auto t = p.translation;
|
||||||
|
t.x() += p.bed_idx * bed_stride();
|
||||||
obj->apply_arrange_result(t, p.rotation);
|
obj->apply_arrange_result(t, p.rotation);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1620,7 +1622,8 @@ struct Plater::priv
|
|||||||
obj_sel(model.objects.size(), nullptr);
|
obj_sel(model.objects.size(), nullptr);
|
||||||
|
|
||||||
for (auto &s : plater().get_selection().get_content())
|
for (auto &s : plater().get_selection().get_content())
|
||||||
if (s.first < int(obj_sel.size())) obj_sel[s.first] = &s.second;
|
if (s.first < int(obj_sel.size()))
|
||||||
|
obj_sel[size_t(s.first)] = &s.second;
|
||||||
|
|
||||||
// Go through the objects and check if inside the selection
|
// Go through the objects and check if inside the selection
|
||||||
for (size_t oidx = 0; oidx < model.objects.size(); ++oidx) {
|
for (size_t oidx = 0; oidx < model.objects.size(); ++oidx) {
|
||||||
@ -1630,7 +1633,8 @@ struct Plater::priv
|
|||||||
std::vector<bool> inst_sel(mo->instances.size(), false);
|
std::vector<bool> inst_sel(mo->instances.size(), false);
|
||||||
|
|
||||||
if (instlist)
|
if (instlist)
|
||||||
for (auto inst_id : *instlist) inst_sel[inst_id] = true;
|
for (auto inst_id : *instlist)
|
||||||
|
inst_sel[size_t(inst_id)] = true;
|
||||||
|
|
||||||
for (size_t i = 0; i < inst_sel.size(); ++i) {
|
for (size_t i = 0; i < inst_sel.size(); ++i) {
|
||||||
ArrangePolygon &&ap = get_arrange_poly(mo->instances[i]);
|
ArrangePolygon &&ap = get_arrange_poly(mo->instances[i]);
|
||||||
@ -2759,9 +2763,8 @@ void Plater::priv::ArrangeJob::process() {
|
|||||||
try {
|
try {
|
||||||
arrangement::arrange(m_selected, m_unselected, min_d, bedshape,
|
arrangement::arrange(m_selected, m_unselected, min_d, bedshape,
|
||||||
[this, count](unsigned st) {
|
[this, count](unsigned st) {
|
||||||
if (st >
|
if (st > 0) // will not finalize after last one
|
||||||
0) // will not finalize after last one
|
update_status(int(count - st), arrangestr);
|
||||||
update_status(count - st, arrangestr);
|
|
||||||
},
|
},
|
||||||
[this]() { return was_canceled(); });
|
[this]() { return was_canceled(); });
|
||||||
} catch (std::exception & /*e*/) {
|
} catch (std::exception & /*e*/) {
|
||||||
|
@ -11,7 +11,7 @@ add_library(Catch2::Catch2 ALIAS Catch2)
|
|||||||
include(Catch)
|
include(Catch)
|
||||||
|
|
||||||
add_library(test_catch2_common INTERFACE)
|
add_library(test_catch2_common INTERFACE)
|
||||||
target_compile_definitions(test_catch2_common INTERFACE TEST_DATA_DIR=R"\(${TEST_DATA_DIR}\)")
|
target_compile_definitions(test_catch2_common INTERFACE TEST_DATA_DIR=R"\(${TEST_DATA_DIR}\)" CATCH_CONFIG_FAST_COMPILE)
|
||||||
target_link_libraries(test_catch2_common INTERFACE Catch2::Catch2)
|
target_link_libraries(test_catch2_common INTERFACE Catch2::Catch2)
|
||||||
|
|
||||||
add_library(test_common INTERFACE)
|
add_library(test_common INTERFACE)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
|
#include <catch2/catch_reporter_teamcity.hpp>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include <libnest2d.h>
|
#include <libnest2d.h>
|
||||||
@ -225,11 +227,11 @@ TEST_CASE("Area", "[Geometry]") {
|
|||||||
|
|
||||||
RectangleItem rect(10, 10);
|
RectangleItem rect(10, 10);
|
||||||
|
|
||||||
REQUIRE(rect.area() == 100);
|
REQUIRE(rect.area() == Approx(100));
|
||||||
|
|
||||||
RectangleItem rect2 = {100, 100};
|
RectangleItem rect2 = {100, 100};
|
||||||
|
|
||||||
REQUIRE(rect2.area() == 10000);
|
REQUIRE(rect2.area() == Approx(10000));
|
||||||
|
|
||||||
Item item = {
|
Item item = {
|
||||||
{61, 97},
|
{61, 97},
|
||||||
@ -288,11 +290,9 @@ TEST_CASE("IsPointInsidePolygon", "[Geometry]") {
|
|||||||
// REQUIRE_FALSE(ShapeLike::intersects(s1, s2));
|
// REQUIRE_FALSE(ShapeLike::intersects(s1, s2));
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// Simple TEST_CASE, does not use gmock
|
|
||||||
TEST_CASE("LeftAndDownPolygon", "[Geometry]")
|
TEST_CASE("LeftAndDownPolygon", "[Geometry]")
|
||||||
{
|
{
|
||||||
using namespace libnest2d;
|
using namespace libnest2d;
|
||||||
using namespace libnest2d;
|
|
||||||
|
|
||||||
Box bin(100, 100);
|
Box bin(100, 100);
|
||||||
BottomLeftPlacer placer(bin);
|
BottomLeftPlacer placer(bin);
|
||||||
@ -339,7 +339,6 @@ TEST_CASE("LeftAndDownPolygon", "[Geometry]")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple TEST_CASE, does not use gmock
|
|
||||||
TEST_CASE("ArrangeRectanglesTight", "[Nesting]")
|
TEST_CASE("ArrangeRectanglesTight", "[Nesting]")
|
||||||
{
|
{
|
||||||
using namespace libnest2d;
|
using namespace libnest2d;
|
||||||
@ -450,7 +449,7 @@ TEST_CASE("ArrangeRectanglesLoose", "[Nesting]")
|
|||||||
return i1.binId() < i2.binId();
|
return i1.binId() < i2.binId();
|
||||||
});
|
});
|
||||||
|
|
||||||
size_t groups = max_group == rects.end() ? 0 : max_group->binId() + 1;
|
auto groups = size_t(max_group == rects.end() ? 0 : max_group->binId() + 1);
|
||||||
|
|
||||||
REQUIRE(groups == 1u);
|
REQUIRE(groups == 1u);
|
||||||
REQUIRE(
|
REQUIRE(
|
||||||
@ -477,8 +476,6 @@ using namespace libnest2d;
|
|||||||
|
|
||||||
template<long long SCALE = 1, class Bin>
|
template<long long SCALE = 1, class Bin>
|
||||||
void exportSVG(std::vector<std::reference_wrapper<Item>>& result, const Bin& bin, int idx = 0) {
|
void exportSVG(std::vector<std::reference_wrapper<Item>>& result, const Bin& bin, int idx = 0) {
|
||||||
|
|
||||||
|
|
||||||
std::string loc = "out";
|
std::string loc = "out";
|
||||||
|
|
||||||
static std::string svg_header =
|
static std::string svg_header =
|
||||||
@ -494,20 +491,20 @@ void exportSVG(std::vector<std::reference_wrapper<Item>>& result, const Bin& bin
|
|||||||
if(out.is_open()) {
|
if(out.is_open()) {
|
||||||
out << svg_header;
|
out << svg_header;
|
||||||
Item rbin( RectangleItem(bin.width(), bin.height()) );
|
Item rbin( RectangleItem(bin.width(), bin.height()) );
|
||||||
for(unsigned i = 0; i < rbin.vertexCount(); i++) {
|
for(unsigned j = 0; j < rbin.vertexCount(); j++) {
|
||||||
auto v = rbin.vertex(i);
|
auto v = rbin.vertex(j);
|
||||||
setY(v, -getY(v)/SCALE + 500 );
|
setY(v, -getY(v)/SCALE + 500 );
|
||||||
setX(v, getX(v)/SCALE);
|
setX(v, getX(v)/SCALE);
|
||||||
rbin.setVertex(i, v);
|
rbin.setVertex(j, v);
|
||||||
}
|
}
|
||||||
out << shapelike::serialize<Formats::SVG>(rbin.rawShape()) << std::endl;
|
out << shapelike::serialize<Formats::SVG>(rbin.rawShape()) << std::endl;
|
||||||
for(Item& sh : r) {
|
for(Item& sh : r) {
|
||||||
Item tsh(sh.transformedShape());
|
Item tsh(sh.transformedShape());
|
||||||
for(unsigned i = 0; i < tsh.vertexCount(); i++) {
|
for(unsigned j = 0; j < tsh.vertexCount(); j++) {
|
||||||
auto v = tsh.vertex(i);
|
auto v = tsh.vertex(j);
|
||||||
setY(v, -getY(v)/SCALE + 500);
|
setY(v, -getY(v)/SCALE + 500);
|
||||||
setX(v, getX(v)/SCALE);
|
setX(v, getX(v)/SCALE);
|
||||||
tsh.setVertex(i, v);
|
tsh.setVertex(j, v);
|
||||||
}
|
}
|
||||||
out << shapelike::serialize<Formats::SVG>(tsh.rawShape()) << std::endl;
|
out << shapelike::serialize<Formats::SVG>(tsh.rawShape()) << std::endl;
|
||||||
}
|
}
|
||||||
@ -570,7 +567,7 @@ TEST_CASE("convexHull", "[Geometry]") {
|
|||||||
REQUIRE(chull.size() == poly.size());
|
REQUIRE(chull.size() == poly.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NestPrusaPartsShouldFitIntoTwoBins", "[Nesting]") {
|
TEST_CASE("PrusaPartsShouldFitIntoTwoBins", "[Nesting]") {
|
||||||
|
|
||||||
// Get the input items and define the bin.
|
// Get the input items and define the bin.
|
||||||
std::vector<Item> input = prusaParts();
|
std::vector<Item> input = prusaParts();
|
||||||
@ -579,21 +576,15 @@ TEST_CASE("NestPrusaPartsShouldFitIntoTwoBins", "[Nesting]") {
|
|||||||
// Do the nesting. Check in each step if the remaining items are less than
|
// Do the nesting. Check in each step if the remaining items are less than
|
||||||
// in the previous step. (Some algorithms can place more items in one step)
|
// in the previous step. (Some algorithms can place more items in one step)
|
||||||
size_t pcount = input.size();
|
size_t pcount = input.size();
|
||||||
libnest2d::nest(input, bin, [&pcount](unsigned cnt) {
|
|
||||||
REQUIRE(cnt < pcount);
|
|
||||||
pcount = cnt;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Get the number of logical bins: search for the max binId...
|
size_t bins = libnest2d::nest(input, bin, 0, {},
|
||||||
auto max_binid_it = std::max_element(input.begin(), input.end(),
|
ProgressFunction{[&pcount](unsigned cnt) {
|
||||||
[](const Item &i1, const Item &i2) {
|
REQUIRE(cnt < pcount);
|
||||||
return i1.binId() < i2.binId();
|
pcount = cnt;
|
||||||
});
|
}});
|
||||||
|
|
||||||
auto bins = size_t(max_binid_it == input.end() ? 0 :
|
|
||||||
max_binid_it->binId() + 1);
|
|
||||||
|
|
||||||
// For prusa parts, 2 bins should be enough...
|
// For prusa parts, 2 bins should be enough...
|
||||||
|
REQUIRE(bins > 0u);
|
||||||
REQUIRE(bins <= 2u);
|
REQUIRE(bins <= 2u);
|
||||||
|
|
||||||
// All parts should be processed by the algorithm
|
// All parts should be processed by the algorithm
|
||||||
@ -617,29 +608,83 @@ TEST_CASE("NestPrusaPartsShouldFitIntoTwoBins", "[Nesting]") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NestEmptyItemShouldBeUntouched", "[Nesting]") {
|
TEST_CASE("EmptyItemShouldBeUntouched", "[Nesting]") {
|
||||||
auto bin = Box(250000000, 210000000); // dummy bin
|
auto bin = Box(250000000, 210000000); // dummy bin
|
||||||
|
|
||||||
std::vector<Item> items;
|
std::vector<Item> items;
|
||||||
items.emplace_back(Item{}); // Emplace empty item
|
items.emplace_back(Item{}); // Emplace empty item
|
||||||
items.emplace_back(Item{0, 200, 0}); // Emplace zero area item
|
items.emplace_back(Item{0, 200, 0}); // Emplace zero area item
|
||||||
|
|
||||||
libnest2d::nest(items, bin);
|
size_t bins = libnest2d::nest(items, bin);
|
||||||
|
|
||||||
|
REQUIRE(bins == 0u);
|
||||||
for (auto &itm : items) REQUIRE(itm.binId() == BIN_ID_UNSET);
|
for (auto &itm : items) REQUIRE(itm.binId() == BIN_ID_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NestLargeItemShouldBeUntouched", "[Nesting]") {
|
TEST_CASE("LargeItemShouldBeUntouched", "[Nesting]") {
|
||||||
auto bin = Box(250000000, 210000000); // dummy bin
|
auto bin = Box(250000000, 210000000); // dummy bin
|
||||||
|
|
||||||
std::vector<Item> items;
|
std::vector<Item> items;
|
||||||
items.emplace_back(RectangleItem{250000001, 210000001}); // Emplace large item
|
items.emplace_back(RectangleItem{250000001, 210000001}); // Emplace large item
|
||||||
|
|
||||||
libnest2d::nest(items, bin);
|
size_t bins = libnest2d::nest(items, bin);
|
||||||
|
|
||||||
|
REQUIRE(bins == 0u);
|
||||||
REQUIRE(items.front().binId() == BIN_ID_UNSET);
|
REQUIRE(items.front().binId() == BIN_ID_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Items can be preloaded", "[Nesting]") {
|
||||||
|
auto bin = Box({0, 0}, {250000000, 210000000}); // dummy bin
|
||||||
|
|
||||||
|
std::vector<Item> items;
|
||||||
|
items.reserve(2);
|
||||||
|
|
||||||
|
NestConfig<> cfg;
|
||||||
|
cfg.placer_config.alignment = NestConfig<>::Placement::Alignment::DONT_ALIGN;
|
||||||
|
|
||||||
|
items.emplace_back(RectangleItem{10000000, 10000000});
|
||||||
|
Item &fixed_rect = items.back();
|
||||||
|
fixed_rect.translate(bin.center());
|
||||||
|
|
||||||
|
items.emplace_back(RectangleItem{20000000, 20000000});
|
||||||
|
Item &movable_rect = items.back();
|
||||||
|
movable_rect.translate(bin.center());
|
||||||
|
|
||||||
|
SECTION("Preloaded Item should be untouched") {
|
||||||
|
fixed_rect.markAsFixedInBin(0);
|
||||||
|
|
||||||
|
size_t bins = libnest2d::nest(items, bin, 0, cfg);
|
||||||
|
|
||||||
|
REQUIRE(bins == 1);
|
||||||
|
|
||||||
|
REQUIRE(fixed_rect.binId() == 0);
|
||||||
|
REQUIRE(fixed_rect.translation().X == bin.center().X);
|
||||||
|
REQUIRE(fixed_rect.translation().Y == bin.center().Y);
|
||||||
|
|
||||||
|
REQUIRE(movable_rect.binId() == 0);
|
||||||
|
REQUIRE(movable_rect.translation().X != bin.center().X);
|
||||||
|
REQUIRE(movable_rect.translation().Y != bin.center().Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Preloaded Item should not affect free bins") {
|
||||||
|
fixed_rect.markAsFixedInBin(1);
|
||||||
|
|
||||||
|
size_t bins = libnest2d::nest(items, bin, 0, cfg);
|
||||||
|
|
||||||
|
REQUIRE(bins == 2);
|
||||||
|
|
||||||
|
REQUIRE(fixed_rect.binId() == 1);
|
||||||
|
REQUIRE(fixed_rect.translation().X == bin.center().X);
|
||||||
|
REQUIRE(fixed_rect.translation().Y == bin.center().Y);
|
||||||
|
|
||||||
|
REQUIRE(movable_rect.binId() == 0);
|
||||||
|
|
||||||
|
auto bb = movable_rect.boundingBox();
|
||||||
|
REQUIRE(bb.center().X == bin.center().X);
|
||||||
|
REQUIRE(bb.center().Y == bin.center().Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct ItemPair {
|
struct ItemPair {
|
||||||
@ -970,7 +1015,7 @@ TEST_CASE("mergePileWithPolygon", "[Geometry]") {
|
|||||||
|
|
||||||
RectangleItem ref(45, 15);
|
RectangleItem ref(45, 15);
|
||||||
|
|
||||||
REQUIRE(shapelike::area(result.front()) == ref.area());
|
REQUIRE(shapelike::area(result.front()) == Approx(ref.area()));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
Loading…
Reference in New Issue
Block a user