mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Add libnest tests for various basic object functions
This commit is contained in:
		
							parent
							
								
									8c04536514
								
							
						
					
					
						commit
						69c02a407b
					
				
					 4 changed files with 133 additions and 32 deletions
				
			
		| 
						 | 
					@ -982,6 +982,9 @@ template<class S> inline double area(const S& poly, const PolygonTag& )
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<class RawShapes>
 | 
				
			||||||
 | 
					inline double area(const RawShapes& shapes, const MultiPolygonTag&);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<class S> // Dispatching function
 | 
					template<class S> // Dispatching function
 | 
				
			||||||
inline double area(const S& sh)
 | 
					inline double area(const S& sh)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@ using Coord = TCoord<PointImpl>;
 | 
				
			||||||
using Box = _Box<PointImpl>;
 | 
					using Box = _Box<PointImpl>;
 | 
				
			||||||
using Segment = _Segment<PointImpl>;
 | 
					using Segment = _Segment<PointImpl>;
 | 
				
			||||||
using Circle = _Circle<PointImpl>;
 | 
					using Circle = _Circle<PointImpl>;
 | 
				
			||||||
 | 
					using MultiPolygon = TMultiShape<PolygonImpl>; 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Item = _Item<PolygonImpl>;
 | 
					using Item = _Item<PolygonImpl>;
 | 
				
			||||||
using Rectangle = _Rectangle<PolygonImpl>;
 | 
					using Rectangle = _Rectangle<PolygonImpl>;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@
 | 
				
			||||||
#include <fstream>
 | 
					#include <fstream>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <libnest2d/libnest2d.hpp>
 | 
					#include <libnest2d/nester.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace libnest2d { namespace svg {
 | 
					namespace libnest2d { namespace svg {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,9 +49,8 @@ public:
 | 
				
			||||||
                conf_.mm_in_coord_units;
 | 
					                conf_.mm_in_coord_units;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    void writeItem(const Item& item) {
 | 
					    void writeShape(RawShape tsh) {
 | 
				
			||||||
        if(svg_layers_.empty()) addLayer();
 | 
					        if(svg_layers_.empty()) addLayer();
 | 
				
			||||||
        auto tsh = item.transformedShape();
 | 
					 | 
				
			||||||
        if(conf_.origo_location == BOTTOMLEFT) {
 | 
					        if(conf_.origo_location == BOTTOMLEFT) {
 | 
				
			||||||
            auto d = static_cast<Coord>(
 | 
					            auto d = static_cast<Coord>(
 | 
				
			||||||
                std::round(conf_.height*conf_.mm_in_coord_units) );
 | 
					                std::round(conf_.height*conf_.mm_in_coord_units) );
 | 
				
			||||||
| 
						 | 
					@ -63,8 +62,14 @@ public:
 | 
				
			||||||
            for(auto& h : holes) for(auto& v : h) setY(v, -getY(v) + d);
 | 
					            for(auto& h : holes) for(auto& v : h) setY(v, -getY(v) + d);
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        currentLayer() += shapelike::serialize<Formats::SVG>(tsh,
 | 
					        currentLayer() +=
 | 
				
			||||||
                                            1.0/conf_.mm_in_coord_units) + "\n";
 | 
					            shapelike::serialize<Formats::SVG>(tsh,
 | 
				
			||||||
 | 
					                                               1.0 / conf_.mm_in_coord_units) +
 | 
				
			||||||
 | 
					            "\n";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void writeItem(const Item& item) {
 | 
				
			||||||
 | 
					        writeShape(item.transformedShape());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void writePackGroup(const PackGroup& result) {
 | 
					    void writePackGroup(const PackGroup& result) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -472,32 +472,30 @@ TEST_CASE("ArrangeRectanglesLoose", "[Nesting]")
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
using namespace libnest2d;
 | 
					using namespace libnest2d;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<long long SCALE = 1, class Bin>
 | 
					template<long long SCALE = 1, class It>
 | 
				
			||||||
void exportSVG(std::vector<std::reference_wrapper<Item>>& result, const Bin& bin, int idx = 0) {
 | 
					void exportSVG(const char *loc, It from, It to) {
 | 
				
			||||||
    std::string loc = "out";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static std::string svg_header =
 | 
					    static const char* svg_header =
 | 
				
			||||||
R"raw(<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 | 
					R"raw(<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 | 
				
			||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
 | 
					<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
 | 
				
			||||||
<svg height="500" width="500" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 | 
					<svg height="500" width="500" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 | 
				
			||||||
)raw";
 | 
					)raw";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int i = idx;
 | 
					 | 
				
			||||||
    auto r = result;
 | 
					 | 
				
			||||||
    //    for(auto r : result) {
 | 
					    //    for(auto r : result) {
 | 
				
			||||||
    std::fstream out(loc + std::to_string(i) + ".svg", std::fstream::out);
 | 
					    std::fstream out(loc, std::fstream::out);
 | 
				
			||||||
    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 j = 0; j < rbin.vertexCount(); j++) {
 | 
					//        for(unsigned j = 0; j < rbin.vertexCount(); j++) {
 | 
				
			||||||
            auto v = rbin.vertex(j);
 | 
					//            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(j, 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(auto it = from; it != to; ++it) {
 | 
				
			||||||
            Item tsh(sh.transformedShape());
 | 
					            const Item &itm = *it;
 | 
				
			||||||
 | 
					            Item tsh(itm.transformedShape());
 | 
				
			||||||
            for(unsigned j = 0; j < tsh.vertexCount(); j++) {
 | 
					            for(unsigned j = 0; j < tsh.vertexCount(); j++) {
 | 
				
			||||||
                auto v = tsh.vertex(j);
 | 
					                auto v = tsh.vertex(j);
 | 
				
			||||||
                setY(v, -getY(v)/SCALE + 500);
 | 
					                setY(v, -getY(v)/SCALE + 500);
 | 
				
			||||||
| 
						 | 
					@ -513,6 +511,12 @@ void exportSVG(std::vector<std::reference_wrapper<Item>>& result, const Bin& bin
 | 
				
			||||||
    //        i++;
 | 
					    //        i++;
 | 
				
			||||||
    //    }
 | 
					    //    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<long long SCALE = 1>
 | 
				
			||||||
 | 
					void exportSVG(std::vector<std::reference_wrapper<Item>>& result, int idx = 0) {
 | 
				
			||||||
 | 
					    exportSVG((std::string("out") + std::to_string(idx) + ".svg").c_str(),
 | 
				
			||||||
 | 
					              result.begin(), result.end());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_CASE("BottomLeftStressTest", "[Geometry]") {
 | 
					TEST_CASE("BottomLeftStressTest", "[Geometry]") {
 | 
				
			||||||
| 
						 | 
					@ -541,7 +545,7 @@ TEST_CASE("BottomLeftStressTest", "[Geometry]") {
 | 
				
			||||||
            valid = (valid && !r1.isInside(r2) && !r2.isInside(r1));
 | 
					            valid = (valid && !r1.isInside(r2) && !r2.isInside(r1));
 | 
				
			||||||
            if(!valid) {
 | 
					            if(!valid) {
 | 
				
			||||||
                std::cout << "error index: " << i << std::endl;
 | 
					                std::cout << "error index: " << i << std::endl;
 | 
				
			||||||
                exportSVG(result, bin, i);
 | 
					                exportSVG<SCALE>(result, i);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            REQUIRE(valid);
 | 
					            REQUIRE(valid);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
| 
						 | 
					@ -894,7 +898,7 @@ void testNfp(const std::vector<ItemPair>& testdata) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int TEST_CASEcase = 0;
 | 
					    int TEST_CASEcase = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto& exportfun = exportSVG<SCALE, Box>;
 | 
					    auto& exportfun = exportSVG<SCALE>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto onetest = [&](Item& orbiter, Item& stationary, unsigned /*testidx*/){
 | 
					    auto onetest = [&](Item& orbiter, Item& stationary, unsigned /*testidx*/){
 | 
				
			||||||
        TEST_CASEcase++;
 | 
					        TEST_CASEcase++;
 | 
				
			||||||
| 
						 | 
					@ -941,7 +945,7 @@ void testNfp(const std::vector<ItemPair>& testdata) {
 | 
				
			||||||
                    std::ref(stationary), std::ref(tmp), std::ref(infp)
 | 
					                    std::ref(stationary), std::ref(tmp), std::ref(infp)
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                exportfun(inp, bin, TEST_CASEcase*i++);
 | 
					                exportfun(inp, TEST_CASEcase*i++);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            REQUIRE(touching);
 | 
					            REQUIRE(touching);
 | 
				
			||||||
| 
						 | 
					@ -1096,3 +1100,91 @@ TEST_CASE("MinAreaBBWithRotatingCalipers", "[Geometry]") {
 | 
				
			||||||
        REQUIRE(succ);
 | 
					        REQUIRE(succ);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<class It> MultiPolygon merged_pile(It from, It to, int bin_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    MultiPolygon pile;
 | 
				
			||||||
 | 
					    pile.reserve(size_t(to - from));
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    for (auto it = from; it != to; ++it) {
 | 
				
			||||||
 | 
					        if (it->binId() == bin_id) pile.emplace_back(it->transformedShape());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return nfp::merge(pile);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("Test for bed center distance optimization", "[Nesting], [NestKernels]")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    static const constexpr ClipperLib::cInt W = 10000000;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Get the input items and define the bin.
 | 
				
			||||||
 | 
					    std::vector<RectangleItem> input(9, {W, W});
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    auto bin = Box::infinite();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    NfpPlacer::Config pconfig;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    pconfig.object_function = [](const Item &item) -> double {
 | 
				
			||||||
 | 
					        return pl::magnsq<PointImpl, double>(item.boundingBox().center());
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    size_t bins = nest(input, bin, 0, NestConfig{pconfig});
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    REQUIRE(bins == 1);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Gather the items into piles of arranged polygons...
 | 
				
			||||||
 | 
					    MultiPolygon pile;
 | 
				
			||||||
 | 
					    pile.reserve(input.size());
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    for (auto &itm : input) {
 | 
				
			||||||
 | 
					        REQUIRE(itm.binId() == 0);
 | 
				
			||||||
 | 
					        pile.emplace_back(itm.transformedShape());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    MultiPolygon m = merged_pile(input.begin(), input.end(), 0);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    REQUIRE(m.size() == 1);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    REQUIRE(sl::area(m) == Approx(9. * W * W));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("Test for biggest bounding box area", "[Nesting], [NestKernels]")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    static const constexpr ClipperLib::cInt W = 10000000;
 | 
				
			||||||
 | 
					    static const constexpr size_t N = 100;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Get the input items and define the bin.
 | 
				
			||||||
 | 
					    std::vector<RectangleItem> input(N, {W, W});
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    auto bin = Box::infinite();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    NfpPlacer::Config pconfig;
 | 
				
			||||||
 | 
					    pconfig.rotations = {0.};
 | 
				
			||||||
 | 
					    Box pile_box;
 | 
				
			||||||
 | 
					    pconfig.before_packing =
 | 
				
			||||||
 | 
					        [&pile_box](const MultiPolygon &pile,
 | 
				
			||||||
 | 
					                    const _ItemGroup<PolygonImpl> &/*packed_items*/,
 | 
				
			||||||
 | 
					                    const _ItemGroup<PolygonImpl> &/*remaining_items*/) {
 | 
				
			||||||
 | 
					        pile_box = sl::boundingBox(pile);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pconfig.object_function = [&pile_box](const Item &item) -> double {
 | 
				
			||||||
 | 
					        Box b = sl::boundingBox(item.boundingBox(), pile_box);
 | 
				
			||||||
 | 
					        double area = b.area<double>() / (W * W);
 | 
				
			||||||
 | 
					        return -area;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    size_t bins = nest(input, bin, 0, NestConfig{pconfig});
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // To debug:
 | 
				
			||||||
 | 
					    exportSVG<1000000>("out", input.begin(), input.end());
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    REQUIRE(bins == 1);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    MultiPolygon pile = merged_pile(input.begin(), input.end(), 0);
 | 
				
			||||||
 | 
					    Box bb = sl::boundingBox(pile);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Here the result shall be a stairway of boxes
 | 
				
			||||||
 | 
					    REQUIRE(pile.size() == N);
 | 
				
			||||||
 | 
					    REQUIRE(bb.area() == N * N * W * W);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue