Merge branch 'master' into fs_emboss
# Conflicts: # src/slic3r/GUI/GLCanvas3D.cpp
This commit is contained in:
commit
05354eda0c
146 changed files with 3246 additions and 5960 deletions
|
@ -13,6 +13,7 @@ add_executable(${_TEST_NAME}_tests
|
|||
test_geometry.cpp
|
||||
test_placeholder_parser.cpp
|
||||
test_polygon.cpp
|
||||
test_polyline.cpp
|
||||
test_mutable_polygon.cpp
|
||||
test_mutable_priority_queue.cpp
|
||||
test_stl.cpp
|
||||
|
|
|
@ -188,6 +188,46 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") {
|
|||
REQUIRE(intersection.front().area() == Approx(match.area()));
|
||||
}
|
||||
}
|
||||
|
||||
ExPolygons expolygons { ExPolygon { square, hole_in_square } };
|
||||
WHEN("Clipping line 1") {
|
||||
Polylines intersection = intersection_pl({ Polyline { { 15, 18 }, { 15, 15 } } }, expolygons);
|
||||
THEN("line is clipped to square with hole") {
|
||||
REQUIRE((Vec2f(15, 18) - Vec2f(15, 16)).norm() == Approx(intersection.front().length()));
|
||||
}
|
||||
}
|
||||
WHEN("Clipping line 2") {
|
||||
Polylines intersection = intersection_pl({ Polyline { { 15, 15 }, { 15, 12 } } }, expolygons);
|
||||
THEN("line is clipped to square with hole") {
|
||||
REQUIRE((Vec2f(15, 14) - Vec2f(15, 12)).norm() == Approx(intersection.front().length()));
|
||||
}
|
||||
}
|
||||
WHEN("Clipping line 3") {
|
||||
Polylines intersection = intersection_pl({ Polyline { { 12, 18 }, { 18, 18 } } }, expolygons);
|
||||
THEN("line is clipped to square with hole") {
|
||||
REQUIRE((Vec2f(18, 18) - Vec2f(12, 18)).norm() == Approx(intersection.front().length()));
|
||||
}
|
||||
}
|
||||
WHEN("Clipping line 4") {
|
||||
Polylines intersection = intersection_pl({ Polyline { { 5, 15 }, { 30, 15 } } }, expolygons);
|
||||
THEN("line is clipped to square with hole") {
|
||||
REQUIRE((Vec2f(14, 15) - Vec2f(10, 15)).norm() == Approx(intersection.front().length()));
|
||||
REQUIRE((Vec2f(20, 15) - Vec2f(16, 15)).norm() == Approx(intersection[1].length()));
|
||||
}
|
||||
}
|
||||
WHEN("Clipping line 5") {
|
||||
Polylines intersection = intersection_pl({ Polyline { { 30, 15 }, { 5, 15 } } }, expolygons);
|
||||
THEN("reverse line is clipped to square with hole") {
|
||||
REQUIRE((Vec2f(20, 15) - Vec2f(16, 15)).norm() == Approx(intersection.front().length()));
|
||||
REQUIRE((Vec2f(14, 15) - Vec2f(10, 15)).norm() == Approx(intersection[1].length()));
|
||||
}
|
||||
}
|
||||
WHEN("Clipping line 6") {
|
||||
Polylines intersection = intersection_pl({ Polyline { { 10, 18 }, { 20, 18 } } }, expolygons);
|
||||
THEN("tangent line is clipped to square with hole") {
|
||||
REQUIRE((Vec2f(20, 18) - Vec2f(10, 18)).norm() == Approx(intersection.front().length()));
|
||||
}
|
||||
}
|
||||
}
|
||||
GIVEN("square with hole 2") {
|
||||
// CCW oriented contour
|
||||
|
@ -223,6 +263,49 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") {
|
|||
}
|
||||
}
|
||||
}
|
||||
GIVEN("circle") {
|
||||
Slic3r::ExPolygon circle_with_hole { Polygon::new_scale({
|
||||
{ 151.8639,288.1192 }, {133.2778,284.6011}, { 115.0091,279.6997 }, { 98.2859,270.8606 }, { 82.2734,260.7933 },
|
||||
{ 68.8974,247.4181 }, { 56.5622,233.0777 }, { 47.7228,216.3558 }, { 40.1617,199.0172 }, { 36.6431,180.4328 },
|
||||
{ 34.932,165.2312 }, { 37.5567,165.1101 }, { 41.0547,142.9903 }, { 36.9056,141.4295 }, { 40.199,124.1277 },
|
||||
{ 47.7776,106.7972 }, { 56.6335,90.084 }, { 68.9831,75.7557 }, { 82.3712,62.3948 }, { 98.395,52.3429 },
|
||||
{ 115.1281,43.5199 }, { 133.4004,38.6374 }, { 151.9884,35.1378 }, { 170.8905,35.8571 }, { 189.6847,37.991 },
|
||||
{ 207.5349,44.2488 }, { 224.8662,51.8273 }, { 240.0786,63.067 }, { 254.407,75.4169 }, { 265.6311,90.6406 },
|
||||
{ 275.6832,106.6636 }, { 281.9225,124.52 }, { 286.8064,142.795 }, { 287.5061,161.696 }, { 286.7874,180.5972 },
|
||||
{ 281.8856,198.8664 }, { 275.6283,216.7169 }, { 265.5604,232.7294 }, { 254.3211,247.942 }, { 239.9802,260.2776 },
|
||||
{ 224.757,271.5022 }, { 207.4179,279.0635 }, { 189.5605,285.3035 }, { 170.7649,287.4188 }
|
||||
}) };
|
||||
circle_with_hole.holes = { Polygon::new_scale({
|
||||
{ 158.227,215.9007 }, { 164.5136,215.9007 }, { 175.15,214.5007 }, { 184.5576,210.6044 }, { 190.2268,207.8743 },
|
||||
{ 199.1462,201.0306 }, { 209.0146,188.346 }, { 213.5135,177.4829 }, { 214.6979,168.4866 }, { 216.1025,162.3325 },
|
||||
{ 214.6463,151.2703 }, { 213.2471,145.1399 }, { 209.0146,134.9203 }, { 199.1462,122.2357 }, { 189.8944,115.1366 },
|
||||
{ 181.2504,111.5567 }, { 175.5684,108.8205 }, { 164.5136,107.3655 }, { 158.2269,107.3655 }, { 147.5907,108.7656 },
|
||||
{ 138.183,112.6616 }, { 132.5135,115.3919 }, { 123.5943,122.2357 }, { 113.7259,134.92 }, { 109.2269,145.7834 },
|
||||
{ 108.0426,154.7799 }, { 106.638,160.9339 }, { 108.0941,171.9957 }, { 109.4933,178.1264 }, { 113.7259,188.3463 },
|
||||
{ 123.5943,201.0306 }, { 132.8461,208.1296 }, { 141.4901,211.7094 }, { 147.172,214.4458 }
|
||||
}) };
|
||||
THEN("contour is counter-clockwise") {
|
||||
REQUIRE(circle_with_hole.contour.is_counter_clockwise());
|
||||
}
|
||||
THEN("hole is counter-clockwise") {
|
||||
REQUIRE(circle_with_hole.holes.size() == 1);
|
||||
REQUIRE(circle_with_hole.holes.front().is_clockwise());
|
||||
}
|
||||
|
||||
WHEN("clipping a line") {
|
||||
auto line = Polyline::new_scale({ { 152.742,288.086671142818 }, { 152.742,34.166466971035 } });
|
||||
Polylines intersection = intersection_pl(line, Polygons{ circle_with_hole });
|
||||
THEN("clipped to two pieces") {
|
||||
REQUIRE(intersection.front().length() == Approx((Vec2d(152742000, 215178843) - Vec2d(152742000, 288086661)).norm()));
|
||||
REQUIRE(intersection[1].length() == Approx((Vec2d(152742000, 35166477) - Vec2d(152742000, 108087507)).norm()));
|
||||
}
|
||||
}
|
||||
}
|
||||
GIVEN("line") {
|
||||
THEN("expand by 5") {
|
||||
REQUIRE(offset(Polyline({10,10}, {20,10}), 5).front().area() == Polygon({ {10,5}, {20,5}, {20,15}, {10,15} }).area());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<e_ordering o = e_ordering::OFF, class P, class Tree>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <catch2/catch.hpp>
|
||||
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/LocalesUtils.hpp"
|
||||
|
||||
|
@ -13,20 +14,20 @@ using namespace Slic3r;
|
|||
SCENARIO("Generic config validation performs as expected.", "[Config]") {
|
||||
GIVEN("A config generated from default options") {
|
||||
Slic3r::DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||
WHEN( "perimeter_extrusion_width is set to 250%, a valid value") {
|
||||
WHEN("perimeter_extrusion_width is set to 250%, a valid value") {
|
||||
config.set_deserialize_strict("perimeter_extrusion_width", "250%");
|
||||
THEN( "The config is read as valid.") {
|
||||
REQUIRE(config.validate().empty());
|
||||
}
|
||||
}
|
||||
WHEN( "perimeter_extrusion_width is set to -10, an invalid value") {
|
||||
WHEN("perimeter_extrusion_width is set to -10, an invalid value") {
|
||||
config.set("perimeter_extrusion_width", -10);
|
||||
THEN( "Validate returns error") {
|
||||
REQUIRE(! config.validate().empty());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN( "perimeters is set to -10, an invalid value") {
|
||||
WHEN("perimeters is set to -10, an invalid value") {
|
||||
config.set("perimeters", -10);
|
||||
THEN( "Validate returns error") {
|
||||
REQUIRE(! config.validate().empty());
|
||||
|
@ -36,8 +37,7 @@ SCENARIO("Generic config validation performs as expected.", "[Config]") {
|
|||
}
|
||||
|
||||
SCENARIO("Config accessor functions perform as expected.", "[Config]") {
|
||||
GIVEN("A config generated from default options") {
|
||||
Slic3r::DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||
auto test = [](ConfigBase &config) {
|
||||
WHEN("A boolean option is set to a boolean value") {
|
||||
REQUIRE_NOTHROW(config.set("gcode_comments", true));
|
||||
THEN("The underlying value is set correctly.") {
|
||||
|
@ -70,8 +70,8 @@ SCENARIO("Config accessor functions perform as expected.", "[Config]") {
|
|||
}
|
||||
}
|
||||
#if 0
|
||||
//FIXME better design accessors for vector elements.
|
||||
WHEN("An integer-based option is set through the integer interface") {
|
||||
//FIXME better design accessors for vector elements.
|
||||
WHEN("An integer-based option is set through the integer interface") {
|
||||
config.set("bed_temperature", 100);
|
||||
THEN("The underlying value is set correctly.") {
|
||||
REQUIRE(config.opt<ConfigOptionInts>("bed_temperature")->get_at(0) == 100);
|
||||
|
@ -193,6 +193,14 @@ SCENARIO("Config accessor functions perform as expected.", "[Config]") {
|
|||
REQUIRE(config.opt_float("layer_height") == 0.5);
|
||||
}
|
||||
}
|
||||
};
|
||||
GIVEN("DynamicPrintConfig generated from default options") {
|
||||
auto config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||
test(config);
|
||||
}
|
||||
GIVEN("FullPrintConfig generated from default options") {
|
||||
Slic3r::FullPrintConfig config;
|
||||
test(config);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -162,14 +162,34 @@ TEST_CASE("Splitting a Polygon generates a polyline correctly", "[Geometry]"){
|
|||
}
|
||||
|
||||
|
||||
TEST_CASE("Bounding boxes are scaled appropriately", "[Geometry]"){
|
||||
BoundingBox bb(std::vector<Point>({Point(0, 1), Point(10, 2), Point(20, 2)}));
|
||||
bb.scale(2);
|
||||
REQUIRE(bb.min == Point(0,2));
|
||||
REQUIRE(bb.max == Point(40,4));
|
||||
SCENARIO("BoundingBox", "[Geometry]") {
|
||||
WHEN("Bounding boxes are scaled") {
|
||||
BoundingBox bb(std::vector<Point>({Point(0, 1), Point(10, 2), Point(20, 2)}));
|
||||
bb.scale(2);
|
||||
REQUIRE(bb.min == Point(0,2));
|
||||
REQUIRE(bb.max == Point(40,4));
|
||||
}
|
||||
WHEN("BoundingBox constructed from points") {
|
||||
BoundingBox bb(Points{ {100,200}, {100, 200}, {500, -600} });
|
||||
THEN("minimum is correct") {
|
||||
REQUIRE(bb.min == Point{100,-600});
|
||||
}
|
||||
THEN("maximum is correct") {
|
||||
REQUIRE(bb.max == Point{500,200});
|
||||
}
|
||||
}
|
||||
WHEN("BoundingBox constructed from a single point") {
|
||||
BoundingBox bb;
|
||||
bb.merge({10, 10});
|
||||
THEN("minimum equals to the only defined point") {
|
||||
REQUIRE(bb.min == Point{10,10});
|
||||
}
|
||||
THEN("maximum equals to the only defined point") {
|
||||
REQUIRE(bb.max == Point{10,10});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Offseting a line generates a polygon correctly", "[Geometry]"){
|
||||
Slic3r::Polyline tmp = { Point(10,10), Point(20,10) };
|
||||
Slic3r::Polygon area = offset(tmp,5).at(0);
|
||||
|
|
|
@ -148,3 +148,65 @@ SCENARIO("Remove collinear points from Polygon", "[Polygon]") {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("Simplify polygon", "[Polygon]")
|
||||
{
|
||||
GIVEN("gear") {
|
||||
auto gear = Polygon::new_scale({
|
||||
{144.9694,317.1543}, {145.4181,301.5633}, {146.3466,296.921}, {131.8436,294.1643}, {131.7467,294.1464},
|
||||
{121.7238,291.5082}, {117.1631,290.2776}, {107.9198,308.2068}, {100.1735,304.5101}, {104.9896,290.3672},
|
||||
{106.6511,286.2133}, {93.453,279.2327}, {81.0065,271.4171}, {67.7886,286.5055}, {60.7927,280.1127},
|
||||
{69.3928,268.2566}, {72.7271,264.9224}, {61.8152,253.9959}, {52.2273,242.8494}, {47.5799,245.7224},
|
||||
{34.6577,252.6559}, {30.3369,245.2236}, {42.1712,236.3251}, {46.1122,233.9605}, {43.2099,228.4876},
|
||||
{35.0862,211.5672}, {33.1441,207.0856}, {13.3923,212.1895}, {10.6572,203.3273}, {6.0707,204.8561},
|
||||
{7.2775,204.4259}, {29.6713,196.3631}, {25.9815,172.1277}, {25.4589,167.2745}, {19.8337,167.0129},
|
||||
{5.0625,166.3346}, {5.0625,156.9425}, {5.3701,156.9282}, {21.8636,156.1628}, {25.3713,156.4613},
|
||||
{25.4243,155.9976}, {29.3432,155.8157}, {30.3838,149.3549}, {26.3596,147.8137}, {27.1085,141.2604},
|
||||
{29.8466,126.8337}, {24.5841,124.9201}, {10.6664,119.8989}, {13.4454,110.9264}, {33.1886,116.0691},
|
||||
{38.817,103.1819}, {45.8311,89.8133}, {30.4286,76.81}, {35.7686,70.0812}, {48.0879,77.6873},
|
||||
{51.564,81.1635}, {61.9006,69.1791}, {72.3019,58.7916}, {60.5509,42.5416}, {68.3369,37.1532},
|
||||
{77.9524,48.1338}, {80.405,52.2215}, {92.5632,44.5992}, {93.0123,44.3223}, {106.3561,37.2056},
|
||||
{100.8631,17.4679}, {108.759,14.3778}, {107.3148,11.1283}, {117.0002,32.8627}, {140.9109,27.3974},
|
||||
{145.7004,26.4994}, {145.1346,6.1011}, {154.502,5.4063}, {156.9398,25.6501}, {171.0557,26.2017},
|
||||
{181.3139,27.323}, {186.2377,27.8532}, {191.6031,8.5474}, {200.6724,11.2756}, {197.2362,30.2334},
|
||||
{220.0789,39.1906}, {224.3261,41.031}, {236.3506,24.4291}, {243.6897,28.6723}, {234.2956,46.7747},
|
||||
{245.6562,55.1643}, {257.2523,65.0901}, {261.4374,61.5679}, {273.1709,52.8031}, {278.555,59.5164},
|
||||
{268.4334,69.8001}, {264.1615,72.3633}, {268.2763,77.9442}, {278.8488,93.5305}, {281.4596,97.6332},
|
||||
{286.4487,95.5191}, {300.2821,90.5903}, {303.4456,98.5849}, {286.4523,107.7253}, {293.7063,131.1779},
|
||||
{294.9748,135.8787}, {314.918,133.8172}, {315.6941,143.2589}, {300.9234,146.1746}, {296.6419,147.0309},
|
||||
{297.1839,161.7052}, {296.6136,176.3942}, {302.1147,177.4857}, {316.603,180.3608}, {317.1658,176.7341},
|
||||
{315.215,189.6589}, {315.1749,189.6548}, {294.9411,187.5222}, {291.13,201.7233}, {286.2615,215.5916},
|
||||
{291.1944,218.2545}, {303.9158,225.1271}, {299.2384,233.3694}, {285.7165,227.6001}, {281.7091,225.1956},
|
||||
{273.8981,237.6457}, {268.3486,245.2248}, {267.4538,246.4414}, {264.8496,250.0221}, {268.6392,253.896},
|
||||
{278.5017,265.2131}, {272.721,271.4403}, {257.2776,258.3579}, {234.4345,276.5687}, {242.6222,294.8315},
|
||||
{234.9061,298.5798}, {227.0321,286.2841}, {225.2505,281.8301}, {211.5387,287.8187}, {202.3025,291.0935},
|
||||
{197.307,292.831}, {199.808,313.1906}, {191.5298,315.0787}, {187.3082,299.8172}, {186.4201,295.3766},
|
||||
{180.595,296.0487}, {161.7854,297.4248}, {156.8058,297.6214}, {154.3395,317.8592}
|
||||
});
|
||||
|
||||
WHEN("simplified") {
|
||||
size_t num_points = gear.size();
|
||||
Polygons simplified = gear.simplify(1000.);
|
||||
THEN("gear simplified to a single polygon") {
|
||||
REQUIRE(simplified.size() == 1);
|
||||
}
|
||||
THEN("gear was reduced using Douglas-Peucker") {
|
||||
//note printf "original points: %d\nnew points: %d", $num_points, scalar(@{$simplified->[0]});
|
||||
REQUIRE(simplified.front().size() < num_points);
|
||||
}
|
||||
}
|
||||
}
|
||||
GIVEN("hole in square") {
|
||||
// CW oriented
|
||||
auto hole_in_square = Polygon{ {140, 140}, {140, 160}, {160, 160}, {160, 140} };
|
||||
WHEN("simplified") {
|
||||
Polygons simplified = hole_in_square.simplify(2.);
|
||||
THEN("hole simplification returns one polygon") {
|
||||
REQUIRE(simplified.size() == 1);
|
||||
}
|
||||
THEN("hole simplification turns cw polygon into ccw polygon") {
|
||||
REQUIRE(simplified.front().is_counter_clockwise());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
28
tests/libslic3r/test_polyline.cpp
Normal file
28
tests/libslic3r/test_polyline.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include <catch2/catch.hpp>
|
||||
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Polyline.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
SCENARIO("Simplify polyline", "[Polyline]")
|
||||
{
|
||||
GIVEN("polyline 1") {
|
||||
auto polyline = Polyline{ {0,0},{1,0},{2,0},{2,1},{2,2},{1,2},{0,2},{0,1},{0,0} };
|
||||
WHEN("simplified with Douglas-Peucker") {
|
||||
polyline.simplify(1.);
|
||||
THEN("simplified correctly") {
|
||||
REQUIRE(polyline == Polyline{ {0,0}, {2,0}, {2,2}, {0,2}, {0,0} });
|
||||
}
|
||||
}
|
||||
}
|
||||
GIVEN("polyline 2") {
|
||||
auto polyline = Polyline{ {0,0}, {50,50}, {100,0}, {125,-25}, {150,50} };
|
||||
WHEN("simplified with Douglas-Peucker") {
|
||||
polyline.simplify(25.);
|
||||
THEN("not simplified") {
|
||||
REQUIRE(polyline == Polyline{ {0,0}, {50,50}, {125,-25}, {150,50} });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue