mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-09 10:16:50 +00:00
Merge branch 'main' into feature/update_wipetower
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
#include "libslic3r/MultiNozzleUtils.hpp"
|
||||
#include "libslic3r/ProjectTask.hpp"
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
@@ -109,8 +111,8 @@ SCENARIO("Export+Import geometry to/from 3mf file cycle", "[3mf]") {
|
||||
src_object->instances.front()->set_transformation(src_instance_transform);
|
||||
|
||||
WHEN("model is saved+loaded to/from 3mf file") {
|
||||
// save the model to 3mf file
|
||||
std::string test_file = std::string(TEST_DATA_DIR) + "/test_3mf/prusa.3mf";
|
||||
ScopedTemporaryFile temp(".3mf");
|
||||
const std::string test_file = temp.string();
|
||||
store_3mf(test_file.c_str(), &src_model, nullptr, false);
|
||||
|
||||
// load back the model from the 3mf file
|
||||
@@ -120,7 +122,6 @@ SCENARIO("Export+Import geometry to/from 3mf file cycle", "[3mf]") {
|
||||
ConfigSubstitutionContext ctxt{ ForwardCompatibilitySubstitutionRule::Disable };
|
||||
load_3mf(test_file.c_str(), dst_config, ctxt, &dst_model, false);
|
||||
}
|
||||
boost::filesystem::remove(test_file);
|
||||
|
||||
// compare meshes
|
||||
TriangleMesh src_mesh = src_model.mesh();
|
||||
@@ -522,7 +523,7 @@ SCENARIO("2D convex hull of sinking object", "[3mf][.]") {
|
||||
object->center_around_origin(false);
|
||||
|
||||
// This outputs the same exact data as the Prusaslicer test
|
||||
object->volumes[0]->mesh().write_ascii("/tmp/orca.ascii");
|
||||
write_debug_stl("3mf/orca.ascii", object->volumes[0]->mesh());
|
||||
|
||||
// set instance's attitude so that it is rotated, scaled (and sinking? how is it sinking? the rotation? does it matter if it's sinking?)
|
||||
ModelInstance* instance = object->instances[0];
|
||||
|
||||
@@ -73,6 +73,40 @@ TEST_CASE("apply_override fills nil entries from the 0-based default index", "[C
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("support_different_extruders is true only when the printer defines more than one variant column", "[Config]")
|
||||
{
|
||||
int extruder_count = 0;
|
||||
|
||||
SECTION("a non-Bambu dual-nozzle printer with one variant column reports false") {
|
||||
DynamicPrintConfig config;
|
||||
config.option<ConfigOptionFloats>("nozzle_diameter", true)->values = {0.4, 0.4};
|
||||
// Both extruders resolve to the same default variant, so there is only one column.
|
||||
config.option<ConfigOptionStrings>("extruder_variant_list", true)->values = {"Direct Drive Standard",
|
||||
"Direct Drive Standard"};
|
||||
REQUIRE(config.support_different_extruders(extruder_count) == false);
|
||||
REQUIRE(extruder_count == 2);
|
||||
}
|
||||
|
||||
SECTION("a Bambu H2D-style printer with distinct variants reports true") {
|
||||
DynamicPrintConfig config;
|
||||
config.option<ConfigOptionFloats>("nozzle_diameter", true)->values = {0.4, 0.4};
|
||||
config.option<ConfigOptionStrings>("extruder_variant_list", true)->values = {
|
||||
"Direct Drive Standard,Direct Drive High Flow",
|
||||
"Direct Drive Standard,Direct Drive High Flow,Direct Drive TPU High Flow"};
|
||||
REQUIRE(config.support_different_extruders(extruder_count) == true);
|
||||
REQUIRE(extruder_count == 2);
|
||||
}
|
||||
|
||||
SECTION("a many-toolhead printer that never opts into variants reports false") {
|
||||
// A Snapmaker U1 has four identical toolheads and never defines extruder_variant_list,
|
||||
// so the config falls back to a single default variant token.
|
||||
DynamicPrintConfig config;
|
||||
config.option<ConfigOptionFloats>("nozzle_diameter", true)->values = {0.4, 0.4, 0.4, 0.4};
|
||||
REQUIRE(config.support_different_extruders(extruder_count) == false);
|
||||
REQUIRE(extruder_count == 4);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("get_config_index_base resolves (volume type, extruder type, id) to a slot", "[Config]")
|
||||
{
|
||||
const std::vector<std::string> variant_list = {"Direct Drive Standard", "Direct Drive High Flow",
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "libslic3r/SLA/Hollowing.hpp"
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
TEST_CASE("Hollow two overlapping spheres") {
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -16,6 +18,6 @@ TEST_CASE("Hollow two overlapping spheres") {
|
||||
|
||||
sla::hollow_mesh(sphere1, sla::HollowingConfig{}, sla::HollowingFlags::hfRemoveInsideTriangles);
|
||||
|
||||
sphere1.WriteOBJFile("twospheres.obj");
|
||||
write_debug_obj("hollowing/twospheres.obj", sphere1);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
TEST_CASE("Split empty mesh", "[its_split][its]") {
|
||||
@@ -29,13 +31,15 @@ TEST_CASE("Split simple mesh consisting of one part", "[its_split][its]") {
|
||||
REQUIRE(res.front().vertices.size() == cube.vertices.size());
|
||||
}
|
||||
|
||||
// Dump each split part as its own OBJ for eyeballing; no-op in release.
|
||||
void debug_write_obj(const std::vector<indexed_triangle_set> &res, const std::string &name)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
size_t part_idx = 0;
|
||||
for (auto &part_its : res) {
|
||||
its_write_obj(part_its, (name + std::to_string(part_idx++) + ".obj").c_str());
|
||||
}
|
||||
for (const auto &part_its : res)
|
||||
write_debug_obj("indexed_triangle_set/" + name + std::to_string(part_idx++) + ".obj", part_its);
|
||||
#else
|
||||
(void) res; (void) name;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -260,7 +264,6 @@ TEST_CASE("Reduce one edge by Quadric Edge Collapse", "[its]")
|
||||
CHECK(is_similar(its_, its, cfg));
|
||||
}
|
||||
|
||||
#include "test_utils.hpp"
|
||||
TEST_CASE("Simplify mesh by Quadric edge collapse to 5%", "[its]")
|
||||
{
|
||||
TriangleMesh mesh = load_model("frog_legs.obj");
|
||||
|
||||
@@ -191,22 +191,21 @@ static void test_expolys(Rst&& rst, const ExPolygons& ref, Vec2i32 window, const
|
||||
for (const ExPolygon& expoly : ref)
|
||||
rst.draw(expoly);
|
||||
|
||||
std::fstream out(name + ".png", std::ios::out);
|
||||
out << rst.encode(sla::PNGRasterEncoder{});
|
||||
out.close();
|
||||
write_debug_stream("marchingsquares/" + name + ".png",
|
||||
[&] { return rst.encode(sla::PNGRasterEncoder{}); });
|
||||
|
||||
const ExPolygons bmp = rstGetPolys(rst);
|
||||
const ExPolygons ext = sla::raster_to_polygons(rst, window);
|
||||
|
||||
SVG svg(name + ".svg", raster_bb);
|
||||
svg.draw(bmp, "green");
|
||||
if (pixel_size.x() >= scale_(0.5))
|
||||
svg.draw_grid(raster_bb, "grey", scale_(0.05), pixel_size.x());
|
||||
if (window_size.x() >= scale_(1.0))
|
||||
svg.draw_grid(raster_bb, "grey", scale_(0.10), window_size.x());
|
||||
svg.draw_outline(ref, "red", "red", scale_(0.3));
|
||||
svg.draw_outline(ext, "blue", "blue");
|
||||
svg.Close();
|
||||
write_debug_svg("marchingsquares/" + name + ".svg", raster_bb, [&](SVG &svg) {
|
||||
svg.draw(bmp, "green");
|
||||
if (pixel_size.x() >= scale_(0.5))
|
||||
svg.draw_grid(raster_bb, "grey", scale_(0.05), pixel_size.x());
|
||||
if (window_size.x() >= scale_(1.0))
|
||||
svg.draw_grid(raster_bb, "grey", scale_(0.10), window_size.x());
|
||||
svg.draw_outline(ref, "red", "red", scale_(0.3));
|
||||
svg.draw_outline(ext, "blue", "blue");
|
||||
});
|
||||
|
||||
// Note all these areas are unscaled back to mm^2.
|
||||
double raster_area = unscaled(unscaled(area(bmp)));
|
||||
@@ -432,9 +431,7 @@ static void recreate_object_from_rasters(const std::string& objname, float lh)
|
||||
double disp_w = 120.96;
|
||||
double disp_h = 68.04;
|
||||
|
||||
#ifndef NDEBUG
|
||||
size_t cntr = 0;
|
||||
#endif
|
||||
for (ExPolygons& layer : layers) {
|
||||
auto rst = create_raster(res, disp_w, disp_h);
|
||||
|
||||
@@ -442,11 +439,8 @@ static void recreate_object_from_rasters(const std::string& objname, float lh)
|
||||
rst.draw(island);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::fstream out(objname + std::to_string(cntr) + ".png", std::ios::out);
|
||||
out << rst.encode(sla::PNGRasterEncoder{});
|
||||
out.close();
|
||||
#endif
|
||||
write_debug_stream("marchingsquares/" + objname + std::to_string(cntr) + ".png",
|
||||
[&] { return rst.encode(sla::PNGRasterEncoder{}); });
|
||||
|
||||
ExPolygons layer_ = sla::raster_to_polygons(rst);
|
||||
// float delta = scaled(std::min(rst.pixel_dimensions().h_mm,
|
||||
@@ -454,21 +448,19 @@ static void recreate_object_from_rasters(const std::string& objname, float lh)
|
||||
|
||||
// layer_ = expolygons_simplify(layer_, delta);
|
||||
|
||||
#ifndef NDEBUG
|
||||
SVG svg(objname + std::to_string(cntr) + ".svg", rstBBox(rst));
|
||||
svg.draw(layer_);
|
||||
svg.draw(layer, "green");
|
||||
svg.Close();
|
||||
#endif
|
||||
write_debug_svg("marchingsquares/" + objname + std::to_string(cntr) + ".svg", rstBBox(rst),
|
||||
[&](SVG &svg) {
|
||||
svg.draw(layer_);
|
||||
svg.draw(layer, "green");
|
||||
});
|
||||
|
||||
double layera = 0., layera_ = 0.;
|
||||
for (auto& p : layer)
|
||||
layera += p.area();
|
||||
for (auto& p : layer_)
|
||||
layera_ += p.area();
|
||||
#ifndef NDEBUG
|
||||
std::cout << cntr++ << std::endl;
|
||||
#endif
|
||||
++cntr;
|
||||
|
||||
double diff = std::abs(layera_ - layera);
|
||||
REQUIRE((diff <= 0.1 * layera || diff < scaled<double>(1.) * scaled<double>(1.)));
|
||||
|
||||
@@ -477,7 +469,7 @@ static void recreate_object_from_rasters(const std::string& objname, float lh)
|
||||
|
||||
indexed_triangle_set out = slices_to_mesh(layers, bb.min.z(), double(lh), double(lh));
|
||||
|
||||
its_write_obj(out, "out_from_rasters.obj");
|
||||
write_debug_obj("marchingsquares/out_from_rasters.obj", out);
|
||||
}
|
||||
|
||||
TEST_CASE("Recreate object from rasters", "[SL1Import]") { recreate_object_from_rasters("frog_legs.obj", 0.05f); }
|
||||
|
||||
Reference in New Issue
Block a user