mirror of
https://github.com/QIDITECH/QIDISlicer.git
synced 2026-01-30 23:48:44 +03:00
update test
This commit is contained in:
@@ -5,7 +5,7 @@ add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp
|
||||
../data/qidiparts.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(${_TEST_NAME}_tests test_common libslic3r)
|
||||
target_link_libraries(${_TEST_NAME}_tests test_common slic3r-arrange-wrapper)
|
||||
set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests")
|
||||
|
||||
if (WIN32)
|
||||
|
||||
@@ -3,21 +3,17 @@
|
||||
|
||||
#include <libslic3r/Execution/ExecutionSeq.hpp>
|
||||
|
||||
#include <libslic3r/Arrange/Core/ArrangeBase.hpp>
|
||||
#include <libslic3r/Arrange/Core/ArrangeFirstFit.hpp>
|
||||
#include <libslic3r/Arrange/Core/NFP/PackStrategyNFP.hpp>
|
||||
#include <libslic3r/Arrange/Core/NFP/RectangleOverfitPackingStrategy.hpp>
|
||||
#include <arrange/ArrangeBase.hpp>
|
||||
#include <arrange/ArrangeFirstFit.hpp>
|
||||
#include <arrange/NFP/PackStrategyNFP.hpp>
|
||||
#include <arrange/NFP/RectangleOverfitPackingStrategy.hpp>
|
||||
#include <arrange/NFP/Kernels/GravityKernel.hpp>
|
||||
#include <arrange/NFP/Kernels/TMArrangeKernel.hpp>
|
||||
#include <arrange/NFP/NFPConcave_Tesselate.hpp>
|
||||
|
||||
#include <libslic3r/Arrange/Core/NFP/Kernels/GravityKernel.hpp>
|
||||
#include <libslic3r/Arrange/Core/NFP/Kernels/TMArrangeKernel.hpp>
|
||||
|
||||
#include <libslic3r/Arrange/Core/NFP/NFPConcave_CGAL.hpp>
|
||||
#include <libslic3r/Arrange/Core/NFP/NFPConcave_Tesselate.hpp>
|
||||
#include <libslic3r/Arrange/Core/NFP/CircularEdgeIterator.hpp>
|
||||
|
||||
#include <libslic3r/Arrange/Items/SimpleArrangeItem.hpp>
|
||||
#include <libslic3r/Arrange/Items/ArrangeItem.hpp>
|
||||
#include <libslic3r/Arrange/Items/TrafoOnlyArrangeItem.hpp>
|
||||
#include <arrange-wrapper/Items/SimpleArrangeItem.hpp>
|
||||
#include <arrange-wrapper/Items/ArrangeItem.hpp>
|
||||
#include <arrange-wrapper/Items/TrafoOnlyArrangeItem.hpp>
|
||||
|
||||
#include <libslic3r/Model.hpp>
|
||||
|
||||
@@ -386,7 +382,7 @@ template<> inline Slic3r::arr2::RectangleBed init_bed<Slic3r::arr2::RectangleBed
|
||||
|
||||
template<> inline Slic3r::arr2::CircleBed init_bed<Slic3r::arr2::CircleBed>()
|
||||
{
|
||||
return Slic3r::arr2::CircleBed{Slic3r::Point::Zero(), scaled(300.)};
|
||||
return Slic3r::arr2::CircleBed{Slic3r::Point::Zero(), scaled(300.), Slic3r::Vec2crd{0, 0}};
|
||||
}
|
||||
|
||||
template<> inline Slic3r::arr2::IrregularBed init_bed<Slic3r::arr2::IrregularBed>()
|
||||
@@ -640,6 +636,7 @@ struct RectangleItem {
|
||||
|
||||
void set_bed_index(int idx) { bed_index = idx; }
|
||||
int get_bed_index() const noexcept { return bed_index; }
|
||||
std::optional<int> get_bed_constraint() const { return std::nullopt; }
|
||||
|
||||
void set_translation(const Vec2crd &tr) { translation = tr; }
|
||||
const Vec2crd & get_translation() const noexcept { return translation; }
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
#include <catch2/catch.hpp>
|
||||
#include "test_utils.hpp"
|
||||
|
||||
#include <libslic3r/Arrange/Arrange.hpp>
|
||||
#include <libslic3r/Arrange/Items/ArrangeItem.hpp>
|
||||
#include <libslic3r/Arrange/Tasks/ArrangeTask.hpp>
|
||||
|
||||
#include <libslic3r/Arrange/SceneBuilder.hpp>
|
||||
#include <arrange-wrapper/Arrange.hpp>
|
||||
#include <arrange-wrapper/Items/ArrangeItem.hpp>
|
||||
#include <arrange-wrapper/Tasks/ArrangeTask.hpp>
|
||||
#include <arrange-wrapper/SceneBuilder.hpp>
|
||||
#include <arrange-wrapper/ModelArrange.hpp>
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Geometry/ConvexHull.hpp"
|
||||
#include "libslic3r/Format/3mf.hpp"
|
||||
#include "libslic3r/ModelArrange.hpp"
|
||||
|
||||
static Slic3r::Model get_example_model_with_20mm_cube()
|
||||
{
|
||||
@@ -135,7 +134,7 @@ TEST_CASE("ModelInstance should be retrievable when imbued into ArrangeItem",
|
||||
arr2::ArrangeItem itm;
|
||||
arr2::PhysicalOnlyVBedHandler vbedh;
|
||||
auto vbedh_ptr = static_cast<arr2::VirtualBedHandler *>(&vbedh);
|
||||
auto arrbl = arr2::ArrangeableModelInstance{mi, vbedh_ptr, nullptr, {0, 0}};
|
||||
auto arrbl = arr2::ArrangeableModelInstance{mi, vbedh_ptr, nullptr, {0, 0}, std::nullopt};
|
||||
arr2::imbue_id(itm, arrbl.id());
|
||||
|
||||
std::optional<ObjectID> id_returned = arr2::retrieve_id(itm);
|
||||
@@ -330,7 +329,7 @@ auto create_vbed_handler<Slic3r::arr2::YStriderVBedHandler>(const Slic3r::Boundi
|
||||
template<>
|
||||
auto create_vbed_handler<Slic3r::arr2::GridStriderVBedHandler>(const Slic3r::BoundingBox &bedbb, coord_t gap)
|
||||
{
|
||||
return Slic3r::arr2::GridStriderVBedHandler{bedbb, gap};
|
||||
return Slic3r::arr2::GridStriderVBedHandler{bedbb, {gap, gap}};
|
||||
}
|
||||
|
||||
TEMPLATE_TEST_CASE("Common virtual bed handlers",
|
||||
@@ -628,7 +627,7 @@ TEMPLATE_TEST_CASE("Bed needs to be completely filled with 1cm cubes",
|
||||
|
||||
ModelObject* new_object = m.add_object();
|
||||
new_object->name = "10mm_box";
|
||||
new_object->add_instance();
|
||||
ModelInstance *instance = new_object->add_instance();
|
||||
TriangleMesh mesh = make_cube(10., 10., 10.);
|
||||
ModelVolume* new_volume = new_object->add_volume(mesh);
|
||||
new_volume->name = new_object->name;
|
||||
@@ -641,11 +640,15 @@ TEMPLATE_TEST_CASE("Bed needs to be completely filled with 1cm cubes",
|
||||
|
||||
arr2::FixedSelection sel({{true}});
|
||||
|
||||
arr2::BedConstraints constraints;
|
||||
constraints.insert({instance->id(), 0});
|
||||
|
||||
arr2::Scene scene{arr2::SceneBuilder{}
|
||||
.set_model(m)
|
||||
.set_arrange_settings(settings)
|
||||
.set_selection(&sel)
|
||||
.set_bed(cfg)};
|
||||
.set_bed_constraints(std::move(constraints))
|
||||
.set_bed(cfg, Point::new_scale(10, 10))};
|
||||
|
||||
auto task = arr2::FillBedTask<ArrItem>::create(scene);
|
||||
auto result = task->process_native(arr2::DummyCtl{});
|
||||
@@ -654,7 +657,7 @@ TEMPLATE_TEST_CASE("Bed needs to be completely filled with 1cm cubes",
|
||||
store_3mf("fillbed_10mm_result.3mf", &m, &cfg, false);
|
||||
|
||||
Points bedpts = get_bed_shape(cfg);
|
||||
arr2::ArrangeBed bed = arr2::to_arrange_bed(bedpts);
|
||||
arr2::ArrangeBed bed = arr2::to_arrange_bed(bedpts, Point::new_scale(10, 10));
|
||||
|
||||
REQUIRE(bed.which() == 1); // Rectangle bed
|
||||
|
||||
@@ -799,7 +802,7 @@ TEST_CASE("Testing arrangement involving virtual beds", "[arrange2][integration]
|
||||
DynamicPrintConfig cfg;
|
||||
cfg.load_from_ini(std::string(TEST_DATA_DIR PATH_SEPARATOR) + "default_fff.ini",
|
||||
ForwardCompatibilitySubstitutionRule::Enable);
|
||||
auto bed = arr2::to_arrange_bed(get_bed_shape(cfg));
|
||||
auto bed = arr2::to_arrange_bed(get_bed_shape(cfg), Point::new_scale(10, 10));
|
||||
auto bedbb = bounding_box(bed);
|
||||
auto bedsz = unscaled(bedbb.size());
|
||||
|
||||
@@ -815,7 +818,7 @@ TEST_CASE("Testing arrangement involving virtual beds", "[arrange2][integration]
|
||||
arr2::Scene scene{arr2::SceneBuilder{}
|
||||
.set_model(model)
|
||||
.set_arrange_settings(settings)
|
||||
.set_bed(cfg)};
|
||||
.set_bed(cfg, Point::new_scale(10, 10))};
|
||||
|
||||
auto itm_conv = arr2::ArrangeableToItemConverter<arr2::ArrangeItem>::create(scene);
|
||||
|
||||
@@ -883,7 +886,7 @@ public:
|
||||
};
|
||||
|
||||
class MocWTH : public WipeTowerHandler {
|
||||
std::function<bool()> m_sel_pred;
|
||||
std::function<bool(int)> m_sel_pred;
|
||||
ObjectID m_id;
|
||||
|
||||
public:
|
||||
@@ -891,18 +894,22 @@ public:
|
||||
|
||||
void visit(std::function<void(Arrangeable &)> fn) override
|
||||
{
|
||||
MocWT wt{m_id, Polygon{}, m_sel_pred};
|
||||
MocWT wt{m_id, Polygon{}, 0, m_sel_pred};
|
||||
fn(wt);
|
||||
}
|
||||
void visit(std::function<void(const Arrangeable &)> fn) const override
|
||||
{
|
||||
MocWT wt{m_id, Polygon{}, m_sel_pred};
|
||||
MocWT wt{m_id, Polygon{}, 0, m_sel_pred};
|
||||
fn(wt);
|
||||
}
|
||||
void set_selection_predicate(std::function<bool()> pred) override
|
||||
void set_selection_predicate(std::function<bool(int)> pred) override
|
||||
{
|
||||
m_sel_pred = std::move(pred);
|
||||
}
|
||||
|
||||
ObjectID get_id() const override {
|
||||
return m_id;
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::arr2
|
||||
@@ -974,7 +981,7 @@ TEST_CASE("Test SceneBuilder", "[arrange2][integration]")
|
||||
|
||||
WHEN("a scene is built with a bed initialized from this DynamicPrintConfig")
|
||||
{
|
||||
arr2::Scene scene(arr2::SceneBuilder{}.set_bed(cfg));
|
||||
arr2::Scene scene(arr2::SceneBuilder{}.set_bed(cfg, Point::new_scale(10, 10)));
|
||||
|
||||
auto bedbb = bounding_box(get_bed_shape(cfg));
|
||||
|
||||
@@ -1001,7 +1008,10 @@ TEST_CASE("Test SceneBuilder", "[arrange2][integration]")
|
||||
arr2::SceneBuilder bld;
|
||||
Model mdl;
|
||||
bld.set_model(mdl);
|
||||
bld.set_wipe_tower_handler(std::make_unique<arr2::MocWTH>(mdl.wipe_tower.id()));
|
||||
|
||||
std::vector<AnyPtr<arr2::WipeTowerHandler>> handlers;
|
||||
handlers.push_back(std::make_unique<arr2::MocWTH>(wipe_tower_instance_id(0)));
|
||||
bld.set_wipe_tower_handlers(std::move(handlers));
|
||||
|
||||
WHEN("the selection mask is initialized as a fallback default in the created scene")
|
||||
{
|
||||
@@ -1014,7 +1024,7 @@ TEST_CASE("Test SceneBuilder", "[arrange2][integration]")
|
||||
|
||||
bool wt_selected = false;
|
||||
scene.model()
|
||||
.visit_arrangeable(mdl.wipe_tower.id(),
|
||||
.visit_arrangeable(wipe_tower_instance_id(0),
|
||||
[&wt_selected](
|
||||
const arr2::Arrangeable &arrbl) {
|
||||
wt_selected = arrbl.is_selected();
|
||||
|
||||
@@ -20,6 +20,7 @@ add_executable(${_TEST_NAME}_tests
|
||||
test_seam_aligned.cpp
|
||||
test_seam_rear.cpp
|
||||
test_seam_random.cpp
|
||||
test_seam_scarf.cpp
|
||||
benchmark_seams.cpp
|
||||
test_gcodefindreplace.cpp
|
||||
test_gcodewriter.cpp
|
||||
@@ -38,7 +39,7 @@ add_executable(${_TEST_NAME}_tests
|
||||
test_thin_walls.cpp
|
||||
test_trianglemesh.cpp
|
||||
)
|
||||
target_link_libraries(${_TEST_NAME}_tests test_common libslic3r)
|
||||
target_link_libraries(${_TEST_NAME}_tests test_common slic3r-arrange-wrapper)
|
||||
set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests")
|
||||
target_compile_definitions(${_TEST_NAME}_tests PUBLIC CATCH_CONFIG_ENABLE_BENCHMARKING)
|
||||
|
||||
|
||||
@@ -105,13 +105,14 @@ TEST_CASE_METHOD(Slic3r::Test::SeamsFixture, "Seam benchmarks", "[Seams][.Benchm
|
||||
using namespace Slic3r;
|
||||
Placer placer;
|
||||
placer.init(print->objects(), params, [](){});
|
||||
std::vector<std::pair<const Layer*, const ExtrusionLoop*>> loops;
|
||||
std::vector<std::tuple<const Layer*, const ExtrusionLoop*, const PrintRegion *>> loops;
|
||||
|
||||
const PrintObject* object{print->objects().front()};
|
||||
for (const Layer* layer :object->layers()) {
|
||||
for (const LayerSlice& lslice : layer->lslices_ex) {
|
||||
for (const LayerIsland &island : lslice.islands) {
|
||||
const LayerRegion &layer_region = *layer->get_region(island.perimeters.region());
|
||||
const PrintRegion ®ion = print->get_print_region(layer_region.region().print_region_id());
|
||||
for (uint32_t perimeter_id : island.perimeters) {
|
||||
const auto *entity_collection{static_cast<const ExtrusionEntityCollection*>(layer_region.perimeters().entities[perimeter_id])};
|
||||
if (entity_collection != nullptr) {
|
||||
@@ -120,7 +121,7 @@ TEST_CASE_METHOD(Slic3r::Test::SeamsFixture, "Seam benchmarks", "[Seams][.Benchm
|
||||
if (loop == nullptr) {
|
||||
continue;
|
||||
}
|
||||
loops.emplace_back(layer, loop);
|
||||
loops.emplace_back(layer, loop, ®ion);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,8 +130,8 @@ TEST_CASE_METHOD(Slic3r::Test::SeamsFixture, "Seam benchmarks", "[Seams][.Benchm
|
||||
}
|
||||
BENCHMARK_ADVANCED("Place seam benchy")(Catch::Benchmark::Chronometer meter) {
|
||||
meter.measure([&] {
|
||||
for (const auto &[layer, loop] : loops) {
|
||||
placer.place_seam(layer, *loop, {0, 0});
|
||||
for (const auto &[layer, loop, region] : loops) {
|
||||
placer.place_seam(layer, region, *loop, false, {0, 0});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "libslic3r/Format/OBJ.hpp"
|
||||
#include "libslic3r/Format/STL.hpp"
|
||||
|
||||
#include <arrange-wrapper/ModelArrange.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
@@ -14,7 +16,6 @@
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <libslic3r/ModelArrange.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -254,7 +255,7 @@ void init_print(std::vector<TriangleMesh> &&meshes, Slic3r::Print &print, Slic3r
|
||||
double distance = min_object_distance(config);
|
||||
arr2::ArrangeSettings arrange_settings{};
|
||||
arrange_settings.set_distance_from_objects(distance);
|
||||
arr2::ArrangeBed bed{arr2::to_arrange_bed(get_bed_shape(config))};
|
||||
arr2::ArrangeBed bed{arr2::to_arrange_bed(get_bed_shape(config), Vec2crd{0, 0})};
|
||||
if (duplicate_count > 1) {
|
||||
duplicate(model, duplicate_count, bed, arrange_settings);
|
||||
}
|
||||
|
||||
@@ -165,7 +165,8 @@ inline std::unique_ptr<Print> process_3mf(const std::filesystem::path &path) {
|
||||
Model model;
|
||||
|
||||
ConfigSubstitutionContext context{ForwardCompatibilitySubstitutionRule::Disable};
|
||||
load_3mf(path.string().c_str(), config, context, &model, false);
|
||||
boost::optional<Semver> version;
|
||||
load_3mf(path.string().c_str(), config, context, &model, false, version);
|
||||
|
||||
Slic3r::Test::init_print(std::vector<TriangleMesh>{}, *print, model, config);
|
||||
print->process();
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "libslic3r/GCode.hpp"
|
||||
#include "libslic3r/Geometry/ConvexHull.hpp"
|
||||
#include "libslic3r/ModelArrange.hpp"
|
||||
#include "test_data.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/ModelArrange.hpp"
|
||||
#include <arrange-wrapper/ModelArrange.hpp>
|
||||
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -43,7 +43,7 @@ SCENARIO("Model construction", "[Model]") {
|
||||
}
|
||||
model_object->add_instance();
|
||||
arrange_objects(model,
|
||||
arr2::to_arrange_bed(get_bed_shape(config)),
|
||||
arr2::to_arrange_bed(get_bed_shape(config), Point::new_scale(10, 10)),
|
||||
arr2::ArrangeSettings{}.set_distance_from_objects(
|
||||
min_object_distance(config)));
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ SCENARIO("Perimeter nesting", "[Perimeters]")
|
||||
//B56
|
||||
ExPolygons fill_expolygons_no_overlap;
|
||||
Flow flow(1., 1., 1.);
|
||||
PerimeterRegions perimeter_regions;
|
||||
PerimeterGenerator::Parameters perimeter_generator_params(
|
||||
1., // layer height
|
||||
-1, // layer ID
|
||||
@@ -55,6 +56,7 @@ SCENARIO("Perimeter nesting", "[Perimeters]")
|
||||
static_cast<const PrintRegionConfig&>(config),
|
||||
static_cast<const PrintObjectConfig&>(config),
|
||||
static_cast<const PrintConfig&>(config),
|
||||
perimeter_regions,
|
||||
false); // spiral_vase
|
||||
Polygons lower_layer_polygons_cache;
|
||||
Polygons upper_layer_polygons_cache;
|
||||
|
||||
@@ -143,3 +143,30 @@ TEST_CASE("Calculate overhangs", "[Seams][SeamGeometry]") {
|
||||
0.0, M_PI / 4.0, M_PI / 4.0, 0.0
|
||||
}));
|
||||
}
|
||||
|
||||
const Linesf lines{to_unscaled_linesf({ExPolygon{
|
||||
scaled(Vec2d{0.0, 0.0}),
|
||||
scaled(Vec2d{1.0, 0.0}),
|
||||
scaled(Vec2d{1.0, 1.0}),
|
||||
scaled(Vec2d{0.0, 1.0})
|
||||
}})};
|
||||
|
||||
TEST_CASE("Offset along loop lines forward", "[Seams][SeamGeometry]") {
|
||||
const std::optional<Seams::Geometry::PointOnLine> result{Seams::Geometry::offset_along_lines(
|
||||
{0.5, 0.0}, 0, lines, 3.9, Seams::Geometry::Direction1D::forward
|
||||
)};
|
||||
REQUIRE(result);
|
||||
const auto &[point, line_index] = *result;
|
||||
CHECK((scaled(point) - Point::new_scale(0.4, 0.0)).norm() < scaled(EPSILON));
|
||||
CHECK(line_index == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Offset along loop lines backward", "[Seams][SeamGeometry]") {
|
||||
const std::optional<Seams::Geometry::PointOnLine> result{Seams::Geometry::offset_along_lines(
|
||||
{1.0, 0.5}, 1, lines, 1.8, Seams::Geometry::Direction1D::backward
|
||||
)};
|
||||
REQUIRE(result);
|
||||
const auto &[point, line_index] = *result;
|
||||
CHECK((scaled(point) - Point::new_scale(0.0, 0.3)).norm() < scaled(EPSILON));
|
||||
CHECK(line_index == 3);
|
||||
}
|
||||
|
||||
@@ -124,44 +124,48 @@ constexpr const char *to_string(Perimeters::AngleType angle_type) {
|
||||
throw std::runtime_error("Unreachable");
|
||||
}
|
||||
|
||||
void serialize_shell(std::ostream &output, const Shells::Shell<Perimeters::Perimeter> &shell) {
|
||||
void serialize_shells(std::ostream &output, const Shells::Shells<> &shells) {
|
||||
output << "x,y,z,point_type,point_classification,angle_type,layer_index,"
|
||||
"point_index,distance,distance_to_previous,is_degenerate"
|
||||
"point_index,distance,distance_to_previous,is_degenerate,shell_index"
|
||||
<< std::endl;
|
||||
|
||||
for (std::size_t perimeter_index{0}; perimeter_index < shell.size(); ++perimeter_index) {
|
||||
const Shells::Slice<> &slice{shell[perimeter_index]};
|
||||
const Perimeters::Perimeter &perimeter{slice.boundary};
|
||||
const std::vector<Vec2d> &points{perimeter.positions};
|
||||
for (std::size_t shell_index{0}; shell_index < shells.size(); ++shell_index) {
|
||||
const Shells::Shell<> &shell{shells[shell_index]};
|
||||
for (std::size_t perimeter_index{0}; perimeter_index < shell.size(); ++perimeter_index) {
|
||||
const Shells::Slice<> &slice{shell[perimeter_index]};
|
||||
const Perimeters::Perimeter &perimeter{slice.boundary};
|
||||
const std::vector<Vec2d> &points{perimeter.positions};
|
||||
|
||||
double total_distance{0.0};
|
||||
for (std::size_t point_index{0}; point_index < perimeter.point_types.size(); ++point_index) {
|
||||
const Vec3d point{to_3d(points[point_index], perimeter.slice_z)};
|
||||
const Perimeters::PointType point_type{perimeter.point_types[point_index]};
|
||||
const Perimeters::PointClassification point_classification{
|
||||
perimeter.point_classifications[point_index]};
|
||||
const Perimeters::AngleType angle_type{perimeter.angle_types[point_index]};
|
||||
const std::size_t layer_index{slice.layer_index};
|
||||
const std::size_t previous_index{point_index == 0 ? points.size() - 1 : point_index - 1};
|
||||
const double distance_to_previous{(points[point_index] - points[previous_index]).norm()};
|
||||
total_distance += point_index == 0 ? 0.0 : distance_to_previous;
|
||||
const double distance{total_distance};
|
||||
const bool is_degenerate{perimeter.is_degenerate};
|
||||
double total_distance{0.0};
|
||||
for (std::size_t point_index{0}; point_index < perimeter.point_types.size(); ++point_index) {
|
||||
const Vec3d point{to_3d(points[point_index], perimeter.slice_z)};
|
||||
const Perimeters::PointType point_type{perimeter.point_types[point_index]};
|
||||
const Perimeters::PointClassification point_classification{
|
||||
perimeter.point_classifications[point_index]};
|
||||
const Perimeters::AngleType angle_type{perimeter.angle_types[point_index]};
|
||||
const std::size_t layer_index{slice.layer_index};
|
||||
const std::size_t previous_index{point_index == 0 ? points.size() - 1 : point_index - 1};
|
||||
const double distance_to_previous{(points[point_index] - points[previous_index]).norm()};
|
||||
total_distance += point_index == 0 ? 0.0 : distance_to_previous;
|
||||
const double distance{total_distance};
|
||||
const bool is_degenerate{perimeter.is_degenerate};
|
||||
|
||||
// clang-format off
|
||||
output
|
||||
<< point.x() << ","
|
||||
<< point.y() << ","
|
||||
<< point.z() << ","
|
||||
<< to_string(point_type) << ","
|
||||
<< to_string(point_classification) << ","
|
||||
<< to_string(angle_type) << ","
|
||||
<< layer_index << ","
|
||||
<< point_index << ","
|
||||
<< distance << ","
|
||||
<< distance_to_previous << ","
|
||||
<< is_degenerate << std::endl;
|
||||
// clang-format on
|
||||
// clang-format off
|
||||
output
|
||||
<< point.x() << ","
|
||||
<< point.y() << ","
|
||||
<< point.z() << ","
|
||||
<< to_string(point_type) << ","
|
||||
<< to_string(point_classification) << ","
|
||||
<< to_string(angle_type) << ","
|
||||
<< layer_index << ","
|
||||
<< point_index << ","
|
||||
<< distance << ","
|
||||
<< distance_to_previous << ","
|
||||
<< is_degenerate << ","
|
||||
<< shell_index << std::endl;
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,6 +179,6 @@ TEST_CASE_METHOD(Test::SeamsFixture, "Create perimeters", "[Seams][SeamPerimeter
|
||||
|
||||
if constexpr (debug_files) {
|
||||
std::ofstream csv{"perimeters.csv"};
|
||||
serialize_shell(csv, shells[0]);
|
||||
serialize_shells(csv, shells);
|
||||
}
|
||||
}
|
||||
|
||||
320
tests/fff_print/test_seam_scarf.cpp
Normal file
320
tests/fff_print/test_seam_scarf.cpp
Normal file
@@ -0,0 +1,320 @@
|
||||
#include <catch2/catch.hpp>
|
||||
#include <libslic3r/GCode/SeamScarf.hpp>
|
||||
#include <libslic3r/GCode/SmoothPath.hpp>
|
||||
|
||||
using namespace Slic3r;
|
||||
using Seams::Scarf::Impl::PathPoint;
|
||||
|
||||
TEST_CASE("Get path point", "[Seams][Scarf]") {
|
||||
using Seams::Scarf::Impl::get_path_point;
|
||||
const Points points{
|
||||
Point::new_scale(0, 0),
|
||||
Point::new_scale(0, 1),
|
||||
Point::new_scale(0, 2),
|
||||
Point::new_scale(0, 3),
|
||||
Point::new_scale(0, 4),
|
||||
};
|
||||
const ExtrusionPaths paths{
|
||||
{{points[0], points[1]}, {}},
|
||||
{{points[1], points[2]}, {}},
|
||||
{{points[2], points[3], points[4]}, {}},
|
||||
};
|
||||
const std::size_t global_index{5}; // Index if paths are flattened.
|
||||
const Point point{Point::new_scale(0, 3.5)};
|
||||
const PathPoint path_point{get_path_point(paths, point, global_index)};
|
||||
|
||||
CHECK(path_point.path_index == 2);
|
||||
CHECK(path_point.previous_point_on_path_index == 1);
|
||||
CHECK(path_point.point == point);
|
||||
}
|
||||
|
||||
TEST_CASE("Split path", "[Seams][Scarf]") {
|
||||
using Seams::Scarf::Impl::split_path;
|
||||
|
||||
const Points points{
|
||||
Point::new_scale(0, 0),
|
||||
Point::new_scale(1, 0),
|
||||
Point::new_scale(2, 0),
|
||||
};
|
||||
|
||||
const auto split_point{Point::new_scale(1.5, 0)};
|
||||
|
||||
const ExtrusionPath path{Polyline{points}, {}};
|
||||
const auto[path_before, path_after]{split_path(
|
||||
path, split_point, 1
|
||||
)};
|
||||
|
||||
REQUIRE(path_before.size() == 3);
|
||||
CHECK(path_before.first_point() == points.front());
|
||||
CHECK(path_before.last_point() == split_point);
|
||||
|
||||
REQUIRE(path_after.size() == 2);
|
||||
CHECK(path_after.first_point() == split_point);
|
||||
CHECK(path_after.last_point() == points.back());
|
||||
}
|
||||
|
||||
TEST_CASE("Split paths", "[Seams][Scarf]") {
|
||||
using Seams::Scarf::Impl::split_paths;
|
||||
|
||||
const Points points{
|
||||
Point::new_scale(0, 0),
|
||||
Point::new_scale(0, 1),
|
||||
Point::new_scale(0, 2),
|
||||
};
|
||||
ExtrusionPaths paths{
|
||||
{{points[0], points[1]}, {}},
|
||||
{{points[1], points[2]}, {}},
|
||||
};
|
||||
const auto split_point{Point::new_scale(0, 1.5)};
|
||||
PathPoint path_point{};
|
||||
path_point.point = split_point;
|
||||
path_point.previous_point_on_path_index = 0;
|
||||
path_point.path_index = 1;
|
||||
const ExtrusionPaths result{split_paths(std::move(paths), path_point)};
|
||||
|
||||
REQUIRE(result.size() == 3);
|
||||
CHECK(result[1].last_point() == split_point);
|
||||
CHECK(result[2].first_point() == split_point);
|
||||
}
|
||||
|
||||
TEST_CASE("Get length", "[Seams][Scarf]") {
|
||||
using Seams::Scarf::Impl::get_length;
|
||||
using Seams::Scarf::Impl::convert_to_smooth;
|
||||
|
||||
const Points points{
|
||||
Point::new_scale(0, 0),
|
||||
Point::new_scale(0, 1),
|
||||
Point::new_scale(0, 2.2),
|
||||
};
|
||||
ExtrusionPaths paths{
|
||||
{{points[0], points[1]}, {}},
|
||||
{{points[1], points[2]}, {}},
|
||||
};
|
||||
|
||||
CHECK(get_length(convert_to_smooth(paths)) == scaled(2.2));
|
||||
}
|
||||
|
||||
TEST_CASE("Linspace", "[Seams][Scarf]") {
|
||||
using Seams::Scarf::Impl::linspace;
|
||||
|
||||
const auto from{Point::new_scale(1, 0)};
|
||||
const auto to{Point::new_scale(3, 0)};
|
||||
|
||||
Points points{linspace(from, to, 3)};
|
||||
REQUIRE(points.size() == 3);
|
||||
CHECK(points[1] == Point::new_scale(2, 0));
|
||||
|
||||
points = linspace(from, to, 5);
|
||||
REQUIRE(points.size() == 5);
|
||||
CHECK(points[1] == Point::new_scale(1.5, 0));
|
||||
CHECK(points[2] == Point::new_scale(2.0, 0));
|
||||
CHECK(points[3] == Point::new_scale(2.5, 0));
|
||||
}
|
||||
|
||||
TEST_CASE("Ensure max distance", "[Seams][Scarf]") {
|
||||
using Seams::Scarf::Impl::ensure_max_distance;
|
||||
|
||||
const Points points{
|
||||
Point::new_scale(0, 0),
|
||||
Point::new_scale(0, 1),
|
||||
};
|
||||
|
||||
Points result{ensure_max_distance(points, scaled(0.5))};
|
||||
REQUIRE(result.size() == 3);
|
||||
CHECK(result[1] == Point::new_scale(0, 0.5));
|
||||
|
||||
result = ensure_max_distance(points, scaled(0.49));
|
||||
REQUIRE(result.size() == 4);
|
||||
}
|
||||
|
||||
TEST_CASE("Lineary increase extrusion height", "[Seams][Scarf]") {
|
||||
using Seams::Scarf::Impl::lineary_increase_extrusion_height;
|
||||
using GCode::SmoothPath, GCode::SmoothPathElement;
|
||||
|
||||
SmoothPath path{
|
||||
{{}, {{Point::new_scale(0, 0)}, {Point::new_scale(1, 0)}}},
|
||||
{{}, {{Point::new_scale(1, 0)}, {Point::new_scale(2, 0)}}},
|
||||
};
|
||||
|
||||
SmoothPath result{lineary_increase_extrusion_height(std::move(path), 0.5)};
|
||||
|
||||
CHECK(result[0].path[0].height_fraction == Approx(0.5));
|
||||
CHECK(result[0].path[0].e_fraction == Approx(0.0));
|
||||
CHECK(result[0].path[1].height_fraction == Approx(0.75));
|
||||
CHECK(result[0].path[1].e_fraction == Approx(0.5));
|
||||
CHECK(result[1].path[0].height_fraction == Approx(0.75));
|
||||
CHECK(result[1].path[0].e_fraction == Approx(0.5));
|
||||
CHECK(result[1].path[1].height_fraction == Approx(1.0));
|
||||
CHECK(result[1].path[1].e_fraction == Approx(1.0));
|
||||
}
|
||||
|
||||
TEST_CASE("Lineary reduce extrusion amount", "[Seams][Scarf]") {
|
||||
using Seams::Scarf::Impl::lineary_readuce_extrusion_amount;
|
||||
using GCode::SmoothPath, GCode::SmoothPathElement;
|
||||
|
||||
SmoothPath path{
|
||||
{{}, {{Point::new_scale(0, 0)}, {Point::new_scale(1, 0)}}},
|
||||
{{}, {{Point::new_scale(1, 0)}, {Point::new_scale(2, 0)}}},
|
||||
};
|
||||
|
||||
SmoothPath result{lineary_readuce_extrusion_amount(std::move(path))};
|
||||
|
||||
CHECK(result[0].path[0].e_fraction == Approx(1.0));
|
||||
CHECK(result[0].path[1].e_fraction == Approx(0.5));
|
||||
CHECK(result[1].path[0].e_fraction == Approx(0.5));
|
||||
CHECK(result[1].path[1].e_fraction == Approx(0.0));
|
||||
}
|
||||
|
||||
TEST_CASE("Elevate scarf", "[Seams][Scarf]") {
|
||||
using Seams::Scarf::Impl::elevate_scarf;
|
||||
using Seams::Scarf::Impl::convert_to_smooth;
|
||||
|
||||
|
||||
const Points points{
|
||||
Point::new_scale(0, 0),
|
||||
Point::new_scale(1, 0),
|
||||
Point::new_scale(2, 0),
|
||||
Point::new_scale(3, 0),
|
||||
};
|
||||
const ExtrusionPaths paths{
|
||||
{{points[0], points[1]}, {}},
|
||||
{{points[1], points[2]}, {}},
|
||||
{{points[2], points[3]}, {}},
|
||||
};
|
||||
|
||||
const GCode::SmoothPath result{elevate_scarf(
|
||||
paths,
|
||||
1,
|
||||
convert_to_smooth,
|
||||
0.5
|
||||
)};
|
||||
|
||||
|
||||
REQUIRE(result.size() == 3);
|
||||
REQUIRE(result[0].path.size() == 2);
|
||||
CHECK(result[0].path[0].e_fraction == Approx(0.0));
|
||||
CHECK(result[0].path[0].height_fraction == Approx(0.5));
|
||||
CHECK(result[0].path[1].e_fraction == Approx(1.0));
|
||||
CHECK(result[0].path[1].height_fraction == Approx(1.0));
|
||||
REQUIRE(result[1].path.size() == 2);
|
||||
CHECK(result[1].path[0].e_fraction == Approx(1.0));
|
||||
CHECK(result[1].path[0].height_fraction == Approx(1.0));
|
||||
CHECK(result[1].path[1].e_fraction == Approx(1.0));
|
||||
CHECK(result[1].path[1].height_fraction == Approx(1.0));
|
||||
REQUIRE(result[2].path.size() == 2);
|
||||
CHECK(result[2].path[0].e_fraction == Approx(1.0));
|
||||
CHECK(result[2].path[0].height_fraction == Approx(1.0));
|
||||
CHECK(result[2].path[1].e_fraction == Approx(0.0));
|
||||
CHECK(result[2].path[1].height_fraction == Approx(1.0));
|
||||
}
|
||||
|
||||
TEST_CASE("Get point offset from the path end", "[Seams][Scarf]") {
|
||||
using Seams::Scarf::Impl::get_point_offset_from_end;
|
||||
|
||||
const Points points{
|
||||
Point::new_scale(0, 0),
|
||||
Point::new_scale(1, 0),
|
||||
Point::new_scale(2, 0),
|
||||
Point::new_scale(3, 0),
|
||||
};
|
||||
const ExtrusionPaths paths{
|
||||
{{points[0], points[1]}, {}},
|
||||
{{points[1], points[2]}, {}},
|
||||
{{points[2], points[3]}, {}},
|
||||
};
|
||||
|
||||
std::optional<PathPoint> result{get_point_offset_from_end(paths, scaled(1.6))};
|
||||
|
||||
REQUIRE(result);
|
||||
CHECK(result->point == Point::new_scale(1.4, 0));
|
||||
CHECK(result->previous_point_on_path_index == 0);
|
||||
CHECK(result->path_index == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("Find point on path from the path end", "[Seams][Scarf]") {
|
||||
using Seams::Scarf::Impl::get_point_offset_from_end;
|
||||
|
||||
const Points points{
|
||||
Point::new_scale(0, 0),
|
||||
Point::new_scale(1, 0),
|
||||
Point::new_scale(2, 0),
|
||||
Point::new_scale(3, 0),
|
||||
Point::new_scale(4, 0),
|
||||
};
|
||||
const ExtrusionPaths paths{
|
||||
{{points[0], points[1]}, {}},
|
||||
{{points[1], points[2]}, {}},
|
||||
{{points[2], points[3], points[4]}, {}},
|
||||
};
|
||||
|
||||
const auto point{Point::new_scale(3.4, 0)};
|
||||
|
||||
std::optional<PathPoint> result{Seams::Scarf::Impl::find_path_point_from_end(paths, point, scaled(1e-2))};
|
||||
|
||||
REQUIRE(result);
|
||||
CHECK(result->point == point);
|
||||
CHECK(result->previous_point_on_path_index == 1);
|
||||
CHECK(result->path_index == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("Add scarf seam", "[Seams][Scarf]") {
|
||||
using Seams::Scarf::add_scarf_seam;
|
||||
using Seams::Scarf::Impl::convert_to_smooth;
|
||||
using Seams::Scarf::Impl::get_length;
|
||||
using Seams::Scarf::Scarf;
|
||||
|
||||
const Points points{
|
||||
Point::new_scale(0, 0),
|
||||
Point::new_scale(1, 0),
|
||||
Point::new_scale(1, 1),
|
||||
Point::new_scale(0, 1),
|
||||
Point::new_scale(0, 0),
|
||||
};
|
||||
const ExtrusionPaths paths{
|
||||
{Polyline{points}, {}},
|
||||
};
|
||||
|
||||
Scarf scarf{};
|
||||
scarf.start_point = Point::new_scale(0.5, 0);
|
||||
scarf.end_point = Point::new_scale(1, 0.5);
|
||||
scarf.start_height = 0.2;
|
||||
scarf.max_segment_length = 0.1;
|
||||
scarf.end_point_previous_index = 1;
|
||||
scarf.entire_loop = false;
|
||||
|
||||
const auto [path, wipe_offset]{add_scarf_seam(ExtrusionPaths{paths}, scarf, convert_to_smooth, false)};
|
||||
|
||||
REQUIRE(path.size() == 4);
|
||||
CHECK(wipe_offset == 1);
|
||||
|
||||
REQUIRE(path.back().path.size() >= 1.0 / scarf.max_segment_length);
|
||||
CHECK(path.back().path.back().point == scarf.end_point);
|
||||
CHECK(path.back().path.front().point == scarf.start_point);
|
||||
CHECK(path.back().path.back().e_fraction == Approx(0));
|
||||
|
||||
REQUIRE(path.front().path.size() >= 1.0 / scarf.max_segment_length);
|
||||
CHECK(path.front().path.back().point == scarf.end_point);
|
||||
CHECK(path.front().path.front().point == scarf.start_point);
|
||||
CHECK(path.front().path.front().e_fraction == Approx(0));
|
||||
CHECK(path.front().path.front().height_fraction == Approx(scarf.start_height));
|
||||
|
||||
CHECK(path.front().path[5].point == points[1]);
|
||||
CHECK(path.front().path[5].e_fraction == Approx(0.5));
|
||||
CHECK(path.front().path[5].height_fraction == Approx(0.6));
|
||||
CHECK(path.back().path[5].e_fraction == Approx(0.5));
|
||||
CHECK(path.back().path[5].height_fraction == Approx(1.0));
|
||||
|
||||
scarf.entire_loop = true;
|
||||
const auto [loop_path, _]{add_scarf_seam(ExtrusionPaths{paths}, scarf, convert_to_smooth, false)};
|
||||
|
||||
CHECK(get_length(loop_path) == scaled(8.0));
|
||||
REQUIRE(!loop_path.empty());
|
||||
REQUIRE(!loop_path.front().path.empty());
|
||||
CHECK(loop_path.front().path.front().point == scarf.end_point);
|
||||
CHECK(loop_path.front().path.front().e_fraction == Approx(0));
|
||||
REQUIRE(!loop_path.back().path.empty());
|
||||
CHECK(loop_path.back().path.back().point == scarf.end_point);
|
||||
|
||||
CHECK(loop_path.front().path.at(20).e_fraction == Approx(0.5));
|
||||
CHECK(loop_path.front().path.at(20).point == Point::new_scale(0, 0.5));
|
||||
}
|
||||
@@ -10,8 +10,6 @@
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::Seams;
|
||||
|
||||
constexpr bool debug_files{false};
|
||||
|
||||
struct ProjectionFixture
|
||||
{
|
||||
Polygon extrusion_path{
|
||||
|
||||
@@ -26,6 +26,7 @@ add_executable(${_TEST_NAME}_tests
|
||||
test_stl.cpp
|
||||
test_meshboolean.cpp
|
||||
test_marchingsquares.cpp
|
||||
test_multiple_beds.cpp
|
||||
test_region_expansion.cpp
|
||||
test_timeutils.cpp
|
||||
test_utils.cpp
|
||||
|
||||
@@ -15,7 +15,8 @@ SCENARIO("Reading 3mf file", "[3mf]") {
|
||||
std::string path = std::string(TEST_DATA_DIR) + "/test_3mf/Geräte/Büchse.3mf";
|
||||
DynamicPrintConfig config;
|
||||
ConfigSubstitutionContext ctxt{ ForwardCompatibilitySubstitutionRule::Disable };
|
||||
bool ret = load_3mf(path.c_str(), config, ctxt, &model, false);
|
||||
boost::optional<Semver> version;
|
||||
bool ret = load_3mf(path.c_str(), config, ctxt, &model, false, version);
|
||||
THEN("load should succeed") {
|
||||
REQUIRE(ret);
|
||||
}
|
||||
@@ -59,7 +60,8 @@ SCENARIO("Export+Import geometry to/from 3mf file cycle", "[3mf]") {
|
||||
DynamicPrintConfig dst_config;
|
||||
{
|
||||
ConfigSubstitutionContext ctxt{ ForwardCompatibilitySubstitutionRule::Disable };
|
||||
load_3mf(test_file.c_str(), dst_config, ctxt, &dst_model, false);
|
||||
boost::optional<Semver> version;
|
||||
load_3mf(test_file.c_str(), dst_config, ctxt, &dst_model, false, version);
|
||||
}
|
||||
boost::filesystem::remove(test_file);
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
#include <random>
|
||||
|
||||
#include <libslic3r/ExtrusionEntity.hpp>
|
||||
#include <libslic3r/GCode/ExtrusionOrder.hpp>
|
||||
#include <libslic3r/GCode/SmoothPath.hpp>
|
||||
#include <libslic3r/Geometry/ArcWelder.hpp>
|
||||
#include <libslic3r/Geometry/Circle.hpp>
|
||||
#include <libslic3r/SVG.hpp>
|
||||
@@ -398,6 +401,122 @@ TEST_CASE("arc wedge test", "[ArcWelder]") {
|
||||
}
|
||||
}
|
||||
|
||||
// Distilled a test case for failing assert(p != prev) inside GCodeGenerator::_extrude() that is caused
|
||||
// by performing simplification of each ExtrusionPath in ExtrusionMultiPath one by one and not
|
||||
// simplifying ExtrusionMultiPath as a whole.
|
||||
TEST_CASE("ExtrusionMultiPath simplification", "[ArcWelderMultiPathSimplify][!mayfail]")
|
||||
{
|
||||
using namespace Slic3r::Geometry;
|
||||
using namespace Slic3r::GCode;
|
||||
|
||||
ExtrusionMultiPath multi_path;
|
||||
|
||||
multi_path.paths.emplace_back(Polyline({Point(3615254, 8843476), Point(5301926, 8703627), Point(5503271, 8717959),
|
||||
Point(5787717, 8834837), Point(7465587, 10084995), Point(7565376, 10117372)}),
|
||||
ExtrusionAttributes(ExtrusionRole::SolidInfill, ExtrusionFlow(0.0626713, 0.449999f, 0.15f), false));
|
||||
|
||||
multi_path.paths.emplace_back(Polyline({Point(7565376, 10117372), Point(7751661, 10097239)}),
|
||||
ExtrusionAttributes(ExtrusionRole::SolidInfill, ExtrusionFlow(0.0604367, 0.435101f, 0.15f), false));
|
||||
|
||||
multi_path.paths.emplace_back(Polyline({Point(7751661, 10097239), Point(11289346, 8638614), Point(11412324, 8600432)}),
|
||||
ExtrusionAttributes(ExtrusionRole::SolidInfill, ExtrusionFlow(0.0547566, 0.397234f, 0.15f), false));
|
||||
|
||||
multi_path.paths.emplace_back(Polyline({Point(11412324, 8600432), Point(11727623, 8578798)}),
|
||||
ExtrusionAttributes(ExtrusionRole::SolidInfill, ExtrusionFlow(0.059829, 0.43105f, 0.15f), false));
|
||||
|
||||
multi_path.paths.emplace_back(Polyline({Point(11727623, 8578798), Point(12042923, 8557165)}),
|
||||
ExtrusionAttributes(ExtrusionRole::SolidInfill, ExtrusionFlow(0.0654324, 0.468406f, 0.15f), false));
|
||||
|
||||
multi_path.paths.emplace_back(Polyline({Point(12042923, 8557165), Point(12358223, 8535532), Point(12339460, 8545477)}),
|
||||
ExtrusionAttributes(ExtrusionRole::SolidInfill, ExtrusionFlow(0.0710358, 0.505762f, 0.15f), false));
|
||||
|
||||
multi_path.paths.emplace_back(Polyline({Point(12339460, 8545477), Point(12035789, 8689023)}),
|
||||
ExtrusionAttributes(ExtrusionRole::SolidInfill, ExtrusionFlow(0.0701369, 0.499769f, 0.15f), false));
|
||||
|
||||
multi_path.paths.emplace_back(Polyline({Point(12035789, 8689023), Point(11732119, 8832569)}),
|
||||
ExtrusionAttributes(ExtrusionRole::SolidInfill, ExtrusionFlow(0.0650101, 0.465591f, 0.15f), false));
|
||||
|
||||
multi_path.paths.emplace_back(Polyline({Point(11732119, 8832569), Point(11428449, 8976115)}),
|
||||
ExtrusionAttributes(ExtrusionRole::SolidInfill, ExtrusionFlow(0.0598834, 0.431413f, 0.15f), false));
|
||||
|
||||
multi_path.paths.emplace_back(Polyline({Point(11428449, 8976115), Point(7890375, 10433797)}),
|
||||
ExtrusionAttributes(ExtrusionRole::SolidInfill, ExtrusionFlow(0.0547566, 0.397234f, 0.15f), false));
|
||||
|
||||
multi_path.paths.emplace_back(Polyline({Point(7890375, 10433797), Point(7890196, 10433871)}),
|
||||
ExtrusionAttributes(ExtrusionRole::SolidInfill, ExtrusionFlow(0.0546036, 0.396214f, 0.15f), false));
|
||||
|
||||
multi_path.paths.emplace_back(Polyline({Point(7890196, 10433871), Point(7645162, 10520244)}),
|
||||
ExtrusionAttributes(ExtrusionRole::SolidInfill, ExtrusionFlow(0.0586375, 0.423107f, 0.15f), false));
|
||||
|
||||
multi_path.paths.emplace_back(Polyline({Point(7645162, 10520244), Point(7400129, 10606618), Point(6491466, 10980845),
|
||||
Point(3782930, 8968079)}),
|
||||
ExtrusionAttributes(ExtrusionRole::SolidInfill, ExtrusionFlow(0.0626713, 0.449999f, 0.15f), false));
|
||||
|
||||
const double resolution = 8000.;
|
||||
SmoothPathCache smooth_path_cache;
|
||||
SmoothPath smooth_path = smooth_path_cache.resolve_or_fit(multi_path, false, resolution);
|
||||
|
||||
double min_segment_length = std::numeric_limits<double>::max();
|
||||
for (const SmoothPathElement &el : smooth_path) {
|
||||
assert(el.path.size() > 1);
|
||||
Point prev_pt = el.path.front().point;
|
||||
|
||||
for (auto segment_it = std::next(el.path.begin()); segment_it != el.path.end(); ++segment_it) {
|
||||
if (const double length = (segment_it->point - prev_pt).cast<double>().norm(); length < min_segment_length) {
|
||||
min_segment_length = length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE(min_segment_length >= resolution);
|
||||
}
|
||||
|
||||
TEST_CASE("SmoothPath clipping test", "[ArcWelder]") {
|
||||
using namespace Slic3r::Geometry;
|
||||
|
||||
const Polyline polyline = {
|
||||
Point(9237362, -279099), Point(9239309, -204770), Point(9232158, 477899), Point(9153712, 1292530),
|
||||
Point(9014384, 2036579), Point(8842322, 2697128), Point(8569131, 3468590), Point(8287136, 4090253),
|
||||
Point(8050736, 4537759), Point(7786167, 4978071), Point(7502123, 5396751), Point(7085512, 5937730),
|
||||
Point(6536631, 6536722), Point(5937701, 7085536), Point(5336389, 7545178), Point(4766354, 7921046),
|
||||
Point(4287299, 8181151), Point(3798566, 8424823), Point(3161891, 8687141), Point(2477384, 8903260),
|
||||
Point(1985727, 9025657), Point(1488659, 9120891), Point(811611, 9208824), Point(229795, 9234222),
|
||||
Point(-477899, 9232158), Point(-1292541, 9153710), Point(-1963942, 9030487), Point(-2483966, 8901437),
|
||||
Point(-2967612, 8752145), Point(-3606656, 8511944), Point(-4098726, 8277235), Point(-4583048, 8025111),
|
||||
Point(-5164553, 7667365), Point(-5602853, 7343037), Point(-6030084, 7003203), Point(-6532687, 6541035),
|
||||
Point(-7085558, 5937673), Point(-7502041, 5396860), Point(-7802209, 4952884), Point(-8061668, 4518435),
|
||||
Point(-8375899, 3912214), Point(-8689042, 3156205), Point(-8915304, 2433948), Point(-9073554, 1769674),
|
||||
Point(-9194504, 960323), Point(-9238723, 227049), Point(-9237360, -279112), Point(-9194498, -960380),
|
||||
Point(-9073524, -1769810), Point(-8895452, -2505523), Point(-8689032, -3156238), Point(-8375859, -3912298),
|
||||
Point(-8025112, -4583044), Point(-7667378, -5164532), Point(-7180536, -5822455), Point(-6729193, -6334406),
|
||||
Point(-6350620, -6713810), Point(-5973693, -7051366), Point(-5438560, -7475505), Point(-4756170, -7927163),
|
||||
Point(-4110103, -8277232), Point(-3651006, -8489813), Point(-3015355, -8738921), Point(-2492584, -8893770),
|
||||
Point(-1963947, -9030483), Point(-1286636, -9154696), Point(-590411, -9222659), Point(14602, -9244383),
|
||||
Point(974789, -9192915), Point(1634833, -9095889), Point(2193590, -8977466), Point(2851102, -8793883),
|
||||
Point(3612042, -8509372), Point(4098709, -8277242), Point(4583076, -8025095), Point(5164577, -7667349),
|
||||
Point(5822437, -7180551), Point(6388368, -6677987), Point(6866030, -6190211), Point(7236430, -5740880),
|
||||
Point(7660739, -5174380), Point(8088357, -4476558), Point(8394013, -3866175), Point(8593000, -3400880),
|
||||
Point(8768650, -2918284), Point(8915319, -2433894), Point(9073549, -1769711), Point(9194508, -960282),
|
||||
Point(9237362, -279099)
|
||||
};
|
||||
|
||||
const ExtrusionAttributes extrusion_attributes(ExtrusionRole::Perimeter, ExtrusionFlow{1.0, 1.0, 1.0});
|
||||
const GCode::SmoothPath smooth_path = {GCode::SmoothPathElement{extrusion_attributes, ArcWelder::fit_path(polyline.points, 32000., 0.05)}};
|
||||
const double smooth_path_length = GCode::length(smooth_path);
|
||||
|
||||
const size_t clip_segment_cnt = 20;
|
||||
for (size_t segment_idx = 1; segment_idx <= clip_segment_cnt; ++segment_idx) {
|
||||
const double clip_length = static_cast<double>(segment_idx) * (smooth_path_length / (clip_segment_cnt + 1));
|
||||
GCode::SmoothPath smooth_path_clipped = smooth_path;
|
||||
|
||||
clip_end(smooth_path_clipped, smooth_path_length - clip_length, scaled<double>(GCode::ExtrusionOrder::min_gcode_segment_length));
|
||||
|
||||
const double smooth_path_clipped_length = GCode::length(smooth_path_clipped);
|
||||
const double relative_diff = std::abs(1. - (clip_length / smooth_path_clipped_length));
|
||||
REQUIRE(relative_diff <= 0.000001);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// For quantization
|
||||
//#include <libslic3r/GCode/GCodeWriter.hpp>
|
||||
|
||||
@@ -103,12 +103,13 @@ std::string get_font_filepath() {
|
||||
|
||||
// Explicit horror include (used to be implicit) - libslic3r "officialy" does not depend on imgui.
|
||||
#include "../../bundled_deps/imgui/imgui/imstb_truetype.h" // stbtt_fontinfo
|
||||
#include "boost/nowide/cstdio.hpp"
|
||||
TEST_CASE("Read glyph C shape from font, stb library calls ONLY", "[Emboss]") {
|
||||
std::string font_path = get_font_filepath();
|
||||
char letter = 'C';
|
||||
|
||||
// Read font file
|
||||
FILE *file = fopen(font_path.c_str(), "rb");
|
||||
FILE *file = boost::nowide::fopen(font_path.c_str(), "rb");
|
||||
REQUIRE(file != nullptr);
|
||||
// find size of file
|
||||
REQUIRE(fseek(file, 0L, SEEK_END) == 0);
|
||||
|
||||
35
tests/libslic3r/test_multiple_beds.cpp
Normal file
35
tests/libslic3r/test_multiple_beds.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <libslic3r/MultipleBeds.hpp>
|
||||
#include <numeric>
|
||||
|
||||
using namespace Slic3r;
|
||||
TEST_CASE("Conversion between grid coords and index", "[MultipleBeds]")
|
||||
{
|
||||
std::vector<BedsGrid::Index> original_indices(10);
|
||||
std::iota(original_indices.begin(), original_indices.end(), 0);
|
||||
|
||||
// Add indexes covering the whole int positive range.
|
||||
const int n{100};
|
||||
std::generate_n(std::back_inserter(original_indices), n, [i = 1]() mutable {
|
||||
return std::numeric_limits<int>::max() / n * i++;
|
||||
});
|
||||
|
||||
std::vector<BedsGrid::GridCoords> coords;
|
||||
std::transform(
|
||||
original_indices.begin(),
|
||||
original_indices.end(),
|
||||
std::back_inserter(coords),
|
||||
BedsGrid::index2grid_coords
|
||||
);
|
||||
|
||||
std::vector<BedsGrid::Index> indices;
|
||||
std::transform(
|
||||
coords.begin(),
|
||||
coords.end(),
|
||||
std::back_inserter(indices),
|
||||
BedsGrid::grid_coords2index
|
||||
);
|
||||
|
||||
CHECK(original_indices == indices);
|
||||
}
|
||||
@@ -33,7 +33,7 @@ TEST_CASE("Distance to line", "[Point]") {
|
||||
|
||||
TEST_CASE("Distance to diagonal line", "[Point]") {
|
||||
const Line line{{50, 50}, {125, -25}};
|
||||
CHECK(std::abs(line.distance_to(Point{100, 0})) == Approx(0));
|
||||
CHECK_THAT(std::abs(line.distance_to(Point{100, 0})), Catch::Matchers::WithinAbs(0, 1e-6));
|
||||
}
|
||||
|
||||
TEST_CASE("Perp distance to line does not overflow", "[Point]") {
|
||||
|
||||
@@ -78,14 +78,14 @@ SCENARIO("Simplify polyne, template", "[Polyline]")
|
||||
Points polyline{ {0,0}, {1000,0}, {2000,0}, {2000,1000}, {2000,2000}, {1000,2000}, {0,2000}, {0,1000}, {0,0} };
|
||||
WHEN("simplified with Douglas-Peucker with back inserter") {
|
||||
Points out;
|
||||
douglas_peucker<int64_t>(polyline.begin(), polyline.end(), std::back_inserter(out), 10, [](const Point &p) { return p; });
|
||||
douglas_peucker<int64_t>(polyline.begin(), polyline.end(), std::back_inserter(out), 10., [](const Point &p) { return p; });
|
||||
THEN("simplified correctly") {
|
||||
REQUIRE(out == Points{ {0,0}, {2000,0}, {2000,2000}, {0,2000}, {0,0} });
|
||||
}
|
||||
}
|
||||
WHEN("simplified with Douglas-Peucker in place") {
|
||||
Points out{ polyline };
|
||||
out.erase(douglas_peucker<int64_t>(out.begin(), out.end(), out.begin(), 10, [](const Point &p) { return p; }), out.end());
|
||||
out.erase(douglas_peucker<int64_t>(out.begin(), out.end(), out.begin(), 10., [](const Point &p) { return p; }), out.end());
|
||||
THEN("simplified correctly") {
|
||||
REQUIRE(out == Points{ {0,0}, {2000,0}, {2000,2000}, {0,2000}, {0,0} });
|
||||
}
|
||||
|
||||
@@ -90,14 +90,14 @@ TEST_CASE("Basic arrange with cube", "[arrangejob]") {
|
||||
arr2::ArrangeSettings settings;
|
||||
|
||||
Points bedpts = get_bed_shape(cfg);
|
||||
arr2::ArrangeBed bed = arr2::to_arrange_bed(bedpts);
|
||||
arr2::ArrangeBed bed = arr2::to_arrange_bed(bedpts, Vec2crd{0, 0});
|
||||
|
||||
SECTION("Single cube needs to be centered") {
|
||||
w.push(std::make_unique<ArrangeJob2>(arr2::Scene{
|
||||
arr2::SceneBuilder{}
|
||||
.set_model(m)
|
||||
.set_arrange_settings(&settings)
|
||||
.set_bed(cfg)}));
|
||||
.set_bed(cfg, Vec2crd{0, 0})}));
|
||||
|
||||
w.process_events();
|
||||
|
||||
@@ -126,7 +126,7 @@ TEST_CASE("Basic arrange with cube", "[arrangejob]") {
|
||||
arr2::Scene scene{arr2::SceneBuilder{}
|
||||
.set_model(m)
|
||||
.set_arrange_settings(&settings)
|
||||
.set_bed(cfg)
|
||||
.set_bed(cfg, Vec2crd{0, 0})
|
||||
.set_selection(&sel)};
|
||||
|
||||
w.push(std::make_unique<ArrangeJob2>(std::move(scene)));
|
||||
@@ -160,7 +160,7 @@ TEST_CASE("Basic arrange with cube", "[arrangejob]") {
|
||||
arr2::Scene scene{arr2::SceneBuilder{}
|
||||
.set_model(m)
|
||||
.set_arrange_settings(&settings)
|
||||
.set_bed(cfg)
|
||||
.set_bed(cfg, Vec2crd{0, 0})
|
||||
.set_selection(&sel)};
|
||||
|
||||
w.push(std::make_unique<ArrangeJob2>(std::move(scene)));
|
||||
@@ -217,7 +217,7 @@ TEST_CASE("Basic arrange with cube", "[arrangejob]") {
|
||||
arr2::Scene scene{arr2::SceneBuilder{}
|
||||
.set_model(m)
|
||||
.set_arrange_settings(&settings)
|
||||
.set_bed(cfg)};
|
||||
.set_bed(cfg, Point::new_scale(10, 10))};
|
||||
|
||||
w.push(std::make_unique<ArrangeJob2>(std::move(scene)));
|
||||
w.process_events();
|
||||
@@ -266,7 +266,7 @@ TEST_CASE("Test for modifying model during arrangement", "[arrangejob][fillbedjo
|
||||
new_volume->name = new_object->name;
|
||||
|
||||
Points bedpts = get_bed_shape(cfg);
|
||||
arr2::ArrangeBed bed = arr2::to_arrange_bed(bedpts);
|
||||
arr2::ArrangeBed bed = arr2::to_arrange_bed(bedpts, Vec2crd{0, 0});
|
||||
|
||||
BoostThreadWorker w(std::make_unique<DummyProgress>());
|
||||
RandomArrangeSettings settings;
|
||||
@@ -278,7 +278,7 @@ TEST_CASE("Test for modifying model during arrangement", "[arrangejob][fillbedjo
|
||||
arr2::Scene scene{arr2::SceneBuilder{}
|
||||
.set_model(m)
|
||||
.set_arrange_settings(&settings)
|
||||
.set_bed(cfg)};
|
||||
.set_bed(cfg, Vec2crd{0, 0})};
|
||||
|
||||
ArrangeJob2::Callbacks cbs;
|
||||
cbs.on_prepared = [&m] (auto &) {
|
||||
|
||||
Reference in New Issue
Block a user