Merge branch 'et_world_coordinates' into fs_emboss

This commit is contained in:
Filip Sykala 2022-05-02 10:11:47 +02:00
commit 3e9778b46b
94 changed files with 8223 additions and 7508 deletions

View file

@ -11,6 +11,7 @@
#include <string>
#include <boost/nowide/cstdio.hpp>
#include <boost/nowide/fstream.hpp>
#include <boost/filesystem.hpp>
#include <libslic3r/ModelArrange.hpp>
@ -286,7 +287,7 @@ std::string gcode(Print & print)
print.set_status_silent();
print.process();
print.export_gcode(temp.string(), nullptr, nullptr);
std::ifstream t(temp.string());
boost::nowide::ifstream t(temp.string());
std::string str((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
boost::nowide::remove(temp.string().c_str());
return str;

View file

@ -8,6 +8,7 @@ add_executable(${_TEST_NAME}_tests
test_clipper_utils.cpp
test_color.cpp
test_config.cpp
test_curve_fitting.cpp
test_elephant_foot_compensation.cpp
test_geometry.cpp
test_placeholder_parser.cpp

View file

@ -0,0 +1,118 @@
#include <catch2/catch.hpp>
#include <test_utils.hpp>
#include <libslic3r/Geometry/Curves.hpp>
#include <libslic3r/Utils.hpp>
#include <libslic3r/SVG.hpp>
TEST_CASE("Curves: cubic b spline fit test", "[Curves]") {
using namespace Slic3r;
using namespace Slic3r::Geometry;
auto fx = [&](size_t index) {
return float(index) / 200.0f;
};
auto fy = [&](size_t index) {
return 1.0f;
};
std::vector<Vec<1, float>> observations { };
std::vector<float> observation_points { };
std::vector<float> weights { };
for (size_t index = 0; index < 200; ++index) {
observations.push_back(Vec<1, float> { fy(index) });
observation_points.push_back(fx(index));
weights.push_back(1);
}
Vec2f fmin { fx(0), fy(0) };
Vec2f fmax { fx(200), fy(200) };
auto bspline = fit_cubic_bspline(observations, observation_points, weights, 1);
Approx ap(1.0f);
ap.epsilon(0.1f);
for (int p = 0; p < 200; ++p) {
float fitted_val = bspline.get_fitted_value(fx(p))(0);
float expected = fy(p);
REQUIRE(fitted_val == ap(expected));
}
}
TEST_CASE("Curves: quadratic f cubic b spline fit test", "[Curves]") {
using namespace Slic3r;
using namespace Slic3r::Geometry;
auto fx = [&](size_t index) {
return float(index) / 100.0f;
};
auto fy = [&](size_t index) {
return (fx(index) - 1) * (fx(index) - 1);
};
std::vector<Vec<1, float>> observations { };
std::vector<float> observation_points { };
std::vector<float> weights { };
for (size_t index = 0; index < 200; ++index) {
observations.push_back(Vec<1, float> { fy(index) });
observation_points.push_back(fx(index));
weights.push_back(1);
}
Vec2f fmin { fx(0), fy(0) };
Vec2f fmax { fx(200), fy(200) };
auto bspline = fit_cubic_bspline(observations, observation_points, weights, 10);
for (int p = 0; p < 200; ++p) {
float fitted_val = bspline.get_fitted_value(fx(p))(0);
float expected = fy(p);
auto check = [](float a, float b) {
return abs(a - b) < 0.2f;
};
//Note: checking is problematic, splines will not perfectly align
REQUIRE(check(fitted_val, expected));
}
}
TEST_CASE("Curves: polynomial fit test", "[Curves]") {
using namespace Slic3r;
using namespace Slic3r::Geometry;
auto fx = [&](size_t index) {
return float(index) / 100.0f;
};
auto fy = [&](size_t index) {
return (fx(index) - 1) * (fx(index) - 1);
};
std::vector<Vec<1, float>> observations { };
std::vector<float> observation_points { };
std::vector<float> weights { };
for (size_t index = 0; index < 200; ++index) {
observations.push_back(Vec<1, float> { fy(index) });
observation_points.push_back(fx(index));
weights.push_back(1);
}
Vec2f fmin { fx(0), fy(0) };
Vec2f fmax { fx(200), fy(200) };
Approx ap(1.0f);
ap.epsilon(0.1f);
auto poly = fit_polynomial(observations, observation_points, weights, 2);
REQUIRE(poly.coefficients(0, 0) == ap(1));
REQUIRE(poly.coefficients(0, 1) == ap(-2));
REQUIRE(poly.coefficients(0, 2) == ap(1));
}

View file

@ -373,7 +373,43 @@ SCENARIO("Line distances", "[Geometry]"){
}
}
SCENARIO("Calculating angles", "[Geometry]")
{
GIVEN(("Vectors 30 degrees apart"))
{
std::vector<std::pair<Point, Point>> pts {
{ {1000, 0}, { 866, 500 } },
{ { 866, 500 }, { 500, 866 } },
{ { 500, 866 }, { 0, 1000 } },
{ { -500, 866 }, { -866, 500 } }
};
THEN("Angle detected is 30 degrees")
{
for (auto &p : pts)
REQUIRE(is_approx(angle(p.first, p.second), M_PI / 6.));
}
}
GIVEN(("Vectors 30 degrees apart"))
{
std::vector<std::pair<Point, Point>> pts {
{ { 866, 500 }, {1000, 0} },
{ { 500, 866 }, { 866, 500 } },
{ { 0, 1000 }, { 500, 866 } },
{ { -866, 500 }, { -500, 866 } }
};
THEN("Angle detected is -30 degrees")
{
for (auto &p : pts)
REQUIRE(is_approx(angle(p.first, p.second), - M_PI / 6.));
}
}
}
SCENARIO("Polygon convex/concave detection", "[Geometry]"){
static constexpr const double angle_threshold = M_PI / 3.;
GIVEN(("A Square with dimension 100")){
auto square = Slic3r::Polygon /*new_scale*/(std::vector<Point>({
Point(100,100),
@ -381,13 +417,13 @@ SCENARIO("Polygon convex/concave detection", "[Geometry]"){
Point(200,200),
Point(100,200)}));
THEN("It has 4 convex points counterclockwise"){
REQUIRE(square.concave_points(PI*4/3).size() == 0);
REQUIRE(square.convex_points(PI*2/3).size() == 4);
REQUIRE(square.concave_points(angle_threshold).size() == 0);
REQUIRE(square.convex_points(angle_threshold).size() == 4);
}
THEN("It has 4 concave points clockwise"){
square.make_clockwise();
REQUIRE(square.concave_points(PI*4/3).size() == 4);
REQUIRE(square.convex_points(PI*2/3).size() == 0);
REQUIRE(square.concave_points(angle_threshold).size() == 4);
REQUIRE(square.convex_points(angle_threshold).size() == 0);
}
}
GIVEN("A Square with an extra colinearvertex"){
@ -398,8 +434,8 @@ SCENARIO("Polygon convex/concave detection", "[Geometry]"){
Point(100,200),
Point(100,100)}));
THEN("It has 4 convex points counterclockwise"){
REQUIRE(square.concave_points(PI*4/3).size() == 0);
REQUIRE(square.convex_points(PI*2/3).size() == 4);
REQUIRE(square.concave_points(angle_threshold).size() == 0);
REQUIRE(square.convex_points(angle_threshold).size() == 4);
}
}
GIVEN("A Square with an extra collinear vertex in different order"){
@ -410,8 +446,8 @@ SCENARIO("Polygon convex/concave detection", "[Geometry]"){
Point(150,100),
Point(200,100)}));
THEN("It has 4 convex points counterclockwise"){
REQUIRE(square.concave_points(PI*4/3).size() == 0);
REQUIRE(square.convex_points(PI*2/3).size() == 4);
REQUIRE(square.concave_points(angle_threshold).size() == 0);
REQUIRE(square.convex_points(angle_threshold).size() == 4);
}
}
@ -422,8 +458,8 @@ SCENARIO("Polygon convex/concave detection", "[Geometry]"){
Point(31286371,461008)
}));
THEN("it has three convex vertices"){
REQUIRE(triangle.concave_points(PI*4/3).size() == 0);
REQUIRE(triangle.convex_points(PI*2/3).size() == 3);
REQUIRE(triangle.concave_points(angle_threshold).size() == 0);
REQUIRE(triangle.convex_points(angle_threshold).size() == 3);
}
}
@ -435,8 +471,8 @@ SCENARIO("Polygon convex/concave detection", "[Geometry]"){
Point(31286371,461012)
}));
THEN("it has three convex vertices"){
REQUIRE(triangle.concave_points(PI*4/3).size() == 0);
REQUIRE(triangle.convex_points(PI*2/3).size() == 3);
REQUIRE(triangle.concave_points(angle_threshold).size() == 0);
REQUIRE(triangle.convex_points(angle_threshold).size() == 3);
}
}
GIVEN("A polygon with concave vertices with angles of specifically 4/3pi"){
@ -453,8 +489,8 @@ SCENARIO("Polygon convex/concave detection", "[Geometry]"){
Point(38092663,692699),Point(52100125,692699)
}));
THEN("the correct number of points are detected"){
REQUIRE(polygon.concave_points(PI*4/3).size() == 6);
REQUIRE(polygon.convex_points(PI*2/3).size() == 10);
REQUIRE(polygon.concave_points(angle_threshold).size() == 6);
REQUIRE(polygon.convex_points(angle_threshold).size() == 10);
}
}
}

View file

@ -4,7 +4,7 @@ add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp
sla_test_utils.hpp sla_test_utils.cpp
sla_supptgen_tests.cpp
sla_raycast_tests.cpp
sla_archive_export_tests.cpp)
sla_archive_readwrite_tests.cpp)
target_link_libraries(${_TEST_NAME}_tests test_common libslic3r)
set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests")

View file

@ -1,40 +0,0 @@
#include <catch2/catch.hpp>
#include <test_utils.hpp>
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/Format/SLAArchive.hpp"
#include <boost/filesystem.hpp>
using namespace Slic3r;
TEST_CASE("Archive export test", "[sla_archives]") {
constexpr const char *PNAME = "20mm_cube";
for (auto &archname : SLAArchive::registered_archives()) {
INFO(std::string("Testing archive type: ") + archname);
SLAPrint print;
SLAFullPrintConfig fullcfg;
auto m = Model::read_from_file(TEST_DATA_DIR PATH_SEPARATOR + std::string(PNAME) + ".obj", nullptr);
fullcfg.set("sla_archive_format", archname);
fullcfg.set("supports_enable", false);
fullcfg.set("pad_enable", false);
DynamicPrintConfig cfg;
cfg.apply(fullcfg);
print.set_status_callback([](const PrintBase::SlicingStatus&) {});
print.apply(m, cfg);
print.process();
ThumbnailsList thumbnails;
auto outputfname = std::string("output.") + SLAArchive::get_extension(archname);
print.export_print(outputfname, thumbnails, PNAME);
// Not much can be checked about the archives...
REQUIRE(boost::filesystem::exists(outputfname));
}
}

View file

@ -0,0 +1,71 @@
#include <catch2/catch.hpp>
#include <test_utils.hpp>
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/TriangleMesh.hpp"
#include "libslic3r/Format/SLAArchiveWriter.hpp"
#include "libslic3r/Format/SLAArchiveReader.hpp"
#include <boost/filesystem.hpp>
using namespace Slic3r;
TEST_CASE("Archive export test", "[sla_archives]") {
for (const char * pname : {"20mm_cube", "extruder_idler"})
for (auto &archname : SLAArchiveWriter::registered_archives()) {
INFO(std::string("Testing archive type: ") + archname + " -- writing...");
SLAPrint print;
SLAFullPrintConfig fullcfg;
auto m = Model::read_from_file(TEST_DATA_DIR PATH_SEPARATOR + std::string(pname) + ".obj", nullptr);
fullcfg.printer_technology.setInt(ptSLA); // FIXME this should be ensured
fullcfg.set("sla_archive_format", archname);
fullcfg.set("supports_enable", false);
fullcfg.set("pad_enable", false);
DynamicPrintConfig cfg;
cfg.apply(fullcfg);
print.set_status_callback([](const PrintBase::SlicingStatus&) {});
print.apply(m, cfg);
print.process();
ThumbnailsList thumbnails;
auto outputfname = std::string("output_") + pname + "." + SLAArchiveWriter::get_extension(archname);
print.export_print(outputfname, thumbnails, pname);
// Not much can be checked about the archives...
REQUIRE(boost::filesystem::exists(outputfname));
double vol_written = m.mesh().volume();
auto readable_formats = SLAArchiveReader::registered_archives();
if (std::any_of(readable_formats.begin(), readable_formats.end(),
[&archname](const std::string &a) { return a == archname; })) {
INFO(std::string("Testing archive type: ") + archname + " -- reading back...");
indexed_triangle_set its;
DynamicPrintConfig cfg;
try {
// Leave format_id deliberetaly empty, guessing should always
// work here.
import_sla_archive(outputfname, "", its, cfg);
} catch (...) {
REQUIRE(false);
}
// its_write_obj(its, (outputfname + ".obj").c_str());
REQUIRE(!cfg.empty());
REQUIRE(!its.empty());
double vol_read = its_volume(its);
double rel_err = std::abs(vol_written - vol_read) / vol_written;
REQUIRE(rel_err < 0.1);
}
}
}