mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-16 06:41:49 +08:00
restore most loop orientation to ccw.
add test_model and test_print tests. Work is needed for them
This commit is contained in:
parent
4e1e4cff73
commit
c03564f218
@ -89,7 +89,7 @@ Then `cd` into the `deps` directory and use these commands to build:
|
||||
You can also use the Visual Studio GUI or other generators as mentioned above.
|
||||
|
||||
The `DESTDIR` option is the location where the bundle will be installed.
|
||||
This may be customized. If you leave it empty, the `DESTDIR` will be places inside the same `build` directory.
|
||||
This may be customized. If you leave it empty, the `DESTDIR` will be places inside the same `build` directory. For using your newly compile deps, use -DCMAKE_INSTALL_PREFIX=<path_of_build\destdir\usr\local> in your cmake command for slic3r.
|
||||
|
||||
Warning: If the `build` directory is nested too deep inside other folders, various file paths during the build
|
||||
become too long and the build might fail due to file writing errors. For this reason, it is recommended to
|
||||
|
@ -473,7 +473,10 @@ inline void extrusion_entities_append_loops(ExtrusionEntitiesPtr &dst, Polygons
|
||||
ExtrusionPath path(role, mm3_per_mm, width, height);
|
||||
path.polyline.points = std::move(poly.points);
|
||||
path.polyline.points.push_back(path.polyline.points.front());
|
||||
dst.emplace_back(new ExtrusionLoop(std::move(path)));
|
||||
ExtrusionLoop *loop = new ExtrusionLoop(std::move(path));
|
||||
//default to ccw
|
||||
loop->make_counter_clockwise();
|
||||
dst.emplace_back(loop);
|
||||
}
|
||||
}
|
||||
loops.clear();
|
||||
|
@ -2022,6 +2022,17 @@ std::vector<float> polygon_angles_at_vertices(const Polygon &polygon, const std:
|
||||
|
||||
std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::string &description, double speed, std::unique_ptr<EdgeGrid::Grid> *lower_layer_edge_grid)
|
||||
{
|
||||
#if DEBUG_EXTRUSION_OUTPUT
|
||||
std::cout << "extrude loop_" << (original_loop.polygon().is_counter_clockwise() ? "ccw" : "clw") << ": ";
|
||||
for (const ExtrusionPath &path : original_loop.paths) {
|
||||
std::cout << ", path{ ";
|
||||
for (const Point &pt : path.polyline.points) {
|
||||
std::cout << ", " << floor(100 * unscale<double>(pt.x())) / 100.0 << ":" << floor(100 * unscale<double>(pt.y())) / 100.0;
|
||||
}
|
||||
std::cout << "}";
|
||||
}
|
||||
std::cout << "\n";
|
||||
#endif
|
||||
// get a copy; don't modify the orientation of the original loop object otherwise
|
||||
// next copies (if any) would not detect the correct orientation
|
||||
ExtrusionLoop loop = original_loop;
|
||||
|
@ -670,45 +670,49 @@ void ModelObject::assign_new_unique_ids_recursive()
|
||||
// return new ModelObject(parent, *this, true);
|
||||
//}
|
||||
|
||||
ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh)
|
||||
ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh, bool centered)
|
||||
{
|
||||
ModelVolume* v = new ModelVolume(this, mesh);
|
||||
this->volumes.push_back(v);
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
v->center_geometry();
|
||||
if(centered)
|
||||
v->center_geometry();
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
this->invalidate_bounding_box();
|
||||
return v;
|
||||
}
|
||||
|
||||
ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh)
|
||||
ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh, bool centered)
|
||||
{
|
||||
ModelVolume* v = new ModelVolume(this, std::move(mesh));
|
||||
this->volumes.push_back(v);
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
v->center_geometry();
|
||||
if (centered)
|
||||
v->center_geometry();
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
this->invalidate_bounding_box();
|
||||
return v;
|
||||
}
|
||||
|
||||
ModelVolume* ModelObject::add_volume(const ModelVolume &other)
|
||||
ModelVolume* ModelObject::add_volume(const ModelVolume &other, bool centered)
|
||||
{
|
||||
ModelVolume* v = new ModelVolume(this, other);
|
||||
this->volumes.push_back(v);
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
v->center_geometry();
|
||||
if (centered)
|
||||
v->center_geometry();
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
this->invalidate_bounding_box();
|
||||
return v;
|
||||
}
|
||||
|
||||
ModelVolume* ModelObject::add_volume(const ModelVolume &other, TriangleMesh &&mesh)
|
||||
ModelVolume* ModelObject::add_volume(const ModelVolume &other, TriangleMesh &&mesh, bool centered)
|
||||
{
|
||||
ModelVolume* v = new ModelVolume(this, other, std::move(mesh));
|
||||
this->volumes.push_back(v);
|
||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
||||
v->center_geometry();
|
||||
if (centered)
|
||||
v->center_geometry();
|
||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
||||
this->invalidate_bounding_box();
|
||||
return v;
|
||||
|
@ -193,10 +193,10 @@ public:
|
||||
Model* get_model() { return m_model; };
|
||||
const Model* get_model() const { return m_model; };
|
||||
|
||||
ModelVolume* add_volume(const TriangleMesh &mesh);
|
||||
ModelVolume* add_volume(TriangleMesh &&mesh);
|
||||
ModelVolume* add_volume(const ModelVolume &volume);
|
||||
ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh);
|
||||
ModelVolume* add_volume(const TriangleMesh &mesh, bool centered = true);
|
||||
ModelVolume* add_volume(TriangleMesh &&mesh, bool centered = true);
|
||||
ModelVolume* add_volume(const ModelVolume &volume, bool centered = true);
|
||||
ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh, bool centered = true);
|
||||
void delete_volume(size_t idx);
|
||||
void clear_volumes();
|
||||
bool is_multiparts() const { return volumes.size() > 1; }
|
||||
|
@ -744,6 +744,10 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
|
||||
// let's get it from the sorted collection as it might have been reversed
|
||||
size_t i = idx - sorted_coll.orig_indices.begin();
|
||||
entities.append(*sorted_coll.entities[i]);
|
||||
//if thin extrusion is a loop, make it ccw like a normal contour.
|
||||
if (ExtrusionLoop* loop = dynamic_cast<ExtrusionLoop*>(entities.entities.back())) {
|
||||
loop->make_counter_clockwise();
|
||||
}
|
||||
} else {
|
||||
const PerimeterGeneratorLoop &loop = loops[*idx];
|
||||
ExtrusionLoop eloop = *dynamic_cast<ExtrusionLoop*>(coll.entities[*idx]);
|
||||
|
@ -1720,6 +1720,8 @@ void Print::_make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollectio
|
||||
first_layer_height // this will be overridden at G-code export time
|
||||
)));
|
||||
eloop.paths.back().polyline = loop.split_at_first_point();
|
||||
//we make it clowkwise, but as it will be reversed, it will be ccw
|
||||
eloop.make_clockwise();
|
||||
out.append(eloop);
|
||||
if (m_config.min_skirt_length.value > 0) {
|
||||
// The skirt length is limited. Sum the total amount of filament length extruded, in mm.
|
||||
|
@ -57,4 +57,5 @@
|
||||
#define ENABLE_SVG_ICONS (1 && ENABLE_1_42_0_ALPHA8 && ENABLE_TEXTURES_FROM_SVG)
|
||||
|
||||
|
||||
#define DEBUG_EXTRUSION_OUTPUT 0
|
||||
#endif // _technologies_h_
|
||||
|
@ -1826,6 +1826,22 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
||||
stl_get_size(&lower->stl);
|
||||
}
|
||||
|
||||
Pointf3s TriangleMesh::vertices()
|
||||
{
|
||||
Pointf3s tmp{};
|
||||
if (this->repaired) {
|
||||
if (this->stl.v_shared == nullptr)
|
||||
stl_generate_shared_vertices(&stl); // build the list of vertices
|
||||
for (auto i = 0; i < this->stl.stats.shared_vertices; i++) {
|
||||
const auto& v = this->stl.v_shared[i];
|
||||
tmp.emplace_back(Vec3d(v.x(), v.y(), v.z()));
|
||||
}
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(warning) << "TriangleMesh", "vertices() requires repair()";
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// Generate the vertex list for a cube solid of arbitrary size in X/Y/Z.
|
||||
TriangleMesh make_cube(double x, double y, double z) {
|
||||
Vec3d pv[8] = {
|
||||
|
@ -77,6 +77,9 @@ public:
|
||||
|
||||
stl_file stl;
|
||||
bool repaired;
|
||||
|
||||
/// --- for tests ----- ///
|
||||
Pointf3s vertices();
|
||||
|
||||
private:
|
||||
void require_shared_vertices();
|
||||
|
@ -15,6 +15,8 @@ set(SLIC3R_TEST_SOURCES
|
||||
libslic3r/test_flow.cpp
|
||||
libslic3r/test_gcodewriter.cpp
|
||||
libslic3r/test_geometry.cpp
|
||||
libslic3r/test_model.cpp
|
||||
libslic3r/test_print.cpp
|
||||
)
|
||||
|
||||
if (NOT TARGET Catch)
|
||||
|
@ -42,8 +42,8 @@ SCENARIO("Extrusion width specifics", "[!mayfail]") {
|
||||
std::string gcode_filepath("");
|
||||
Slic3r::Test::gcode(gcode_filepath, print);
|
||||
GCodeReader parser {Slic3r::GCodeReader()};
|
||||
const auto layer_height { config->opt_float("layer_height") };
|
||||
std::string gcode_from_file{ read_to_string(gcode_filepath) };
|
||||
const double layer_height = config->opt_float("layer_height");
|
||||
std::string gcode_from_file= read_to_string(gcode_filepath);
|
||||
parser.parse_buffer(gcode_from_file, [&E_per_mm_bottom, layer_height] (Slic3r::GCodeReader& self, const Slic3r::GCodeReader::GCodeLine& line)
|
||||
{
|
||||
if (self.z() == Approx(layer_height).margin(0.01)) { // only consider first layer
|
||||
|
@ -1,47 +1,55 @@
|
||||
#include <catch.hpp>
|
||||
#include "Model.hpp"
|
||||
#include "test_data.hpp" // get access to init_print, etc
|
||||
#include "../../libslic3r/Config.hpp"
|
||||
#include "../../libslic3r/Model.hpp"
|
||||
#include "../test_data.hpp" // get access to init_print, etc
|
||||
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::Test;
|
||||
|
||||
SCENARIO("Model construction") {
|
||||
GIVEN("A Slic3r Model") {
|
||||
auto model {Slic3r::Model()};
|
||||
auto sample_mesh {Slic3r::TriangleMesh::make_cube(20,20,20)};
|
||||
Model model;
|
||||
TriangleMesh sample_mesh = make_cube(20,20,20);
|
||||
sample_mesh.repair();
|
||||
|
||||
auto config {Slic3r::Config::new_from_defaults()};
|
||||
std::shared_ptr<Slic3r::Print> print = std::make_shared<Slic3r::Print>();
|
||||
print->apply_config(config);
|
||||
DynamicPrintConfig *config = Slic3r::DynamicPrintConfig::new_from_defaults();
|
||||
Slic3r::Print print;
|
||||
print.apply_config(*config);
|
||||
//Slic3r::Test::init_print(print, { sample_mesh }, model, config);
|
||||
|
||||
WHEN("Model object is added") {
|
||||
ModelObject* mo {model.add_object()};
|
||||
ModelObject* mo = model.add_object();
|
||||
mo->name = "cube20";
|
||||
THEN("Model object list == 1") {
|
||||
REQUIRE(model.objects.size() == 1);
|
||||
}
|
||||
|
||||
mo->add_volume(sample_mesh);
|
||||
mo->add_volume(sample_mesh, false);
|
||||
THEN("Model volume list == 1") {
|
||||
REQUIRE(mo->volumes.size() == 1);
|
||||
}
|
||||
THEN("Model volume modifier is false") {
|
||||
REQUIRE(mo->volumes.front()->modifier == false);
|
||||
REQUIRE(mo->volumes.front()->is_modifier() == false);
|
||||
}
|
||||
THEN("Mesh is equivalent to input mesh.") {
|
||||
REQUIRE(sample_mesh.vertices() == mo->volumes.front()->mesh.vertices());
|
||||
}
|
||||
ModelInstance* inst {mo->add_instance()};
|
||||
inst->rotation = 0;
|
||||
inst->scaling_factor = 1.0;
|
||||
model.arrange_objects(print->config.min_object_distance());
|
||||
model.center_instances_around_point(Slic3r::Pointf(100,100));
|
||||
print->auto_assign_extruders(mo);
|
||||
print->add_model_object(mo);
|
||||
ModelInstance* inst = mo->add_instance();
|
||||
inst->set_rotation(Vec3d(0,0,0));
|
||||
inst->set_scaling_factor(Vec3d(1, 1, 1));
|
||||
model.arrange_objects(print.config().min_object_distance());
|
||||
model.center_instances_around_point(Slic3r::Vec2d(100,100));
|
||||
print.auto_assign_extruders(mo);
|
||||
//print.add_model_object(mo);
|
||||
print.apply(model, *config);
|
||||
print.validate();
|
||||
THEN("Print works?") {
|
||||
print->process();
|
||||
auto gcode {std::stringstream("")};
|
||||
print->export_gcode(gcode, true);
|
||||
REQUIRE(gcode.str().size() > 0);
|
||||
std::string gcode_filepath("");
|
||||
Slic3r::Test::gcode(gcode_filepath, print);
|
||||
std::cout << "gcode generation done\n";
|
||||
std::string gcode_from_file = read_to_string(gcode_filepath);
|
||||
REQUIRE(gcode_from_file.size() > 0);
|
||||
clean_file(gcode_filepath, "gcode");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,60 +1,70 @@
|
||||
#include <catch.hpp>
|
||||
#include <string>
|
||||
#include "test_data.hpp"
|
||||
#include "libslic3r.h"
|
||||
#include "../test_data.hpp"
|
||||
#include "../../libslic3r/libslic3r.h"
|
||||
|
||||
using namespace Slic3r::Test;
|
||||
using namespace Slic3r;
|
||||
using namespace std::literals;
|
||||
|
||||
SCENARIO("PrintObject: Perimeter generation") {
|
||||
GIVEN("20mm cube and default config") {
|
||||
auto config {Slic3r::Config::new_from_defaults()};
|
||||
TestMesh m { TestMesh::cube_20x20x20 };
|
||||
Slic3r::Model model;
|
||||
auto event_counter {0U};
|
||||
DynamicPrintConfig *config = Slic3r::DynamicPrintConfig::new_from_defaults();
|
||||
TestMesh m = TestMesh::cube_20x20x20;
|
||||
Model model;
|
||||
unsigned int event_counter = 0U;
|
||||
std::string stage;
|
||||
int value {0};
|
||||
int value = 0;
|
||||
auto callback {[&event_counter, &stage, &value] (int a, const char* b) { stage = std::string(b); event_counter++; value = a; }};
|
||||
config->set("fill_density", 0);
|
||||
config->set_key_value("fill_density", new ConfigOptionPercent(0));
|
||||
|
||||
WHEN("make_perimeters() is called") {
|
||||
auto print {Slic3r::Test::init_print({m}, model, config)};
|
||||
const auto& object = *(print->objects.at(0));
|
||||
print->objects[0]->make_perimeters();
|
||||
Print print;
|
||||
Slic3r::Test::init_print(print, { m }, model, config);
|
||||
PrintObject& object = *(print.objects().at(0));
|
||||
print.process();
|
||||
// there are 66.66666.... layers for 0.3mm in 20mm
|
||||
//slic3r is rounded (slice at half-layer), slic3rPE is less?
|
||||
//TODO: check the slic32r why it's not cut at half-layer
|
||||
THEN("67 layers exist in the model") {
|
||||
REQUIRE(object.layers.size() == 67);
|
||||
REQUIRE(object.layers().size() == 67);
|
||||
}
|
||||
THEN("Every layer in region 0 has 1 island of perimeters") {
|
||||
for(auto* layer : object.layers) {
|
||||
REQUIRE(layer->regions[0]->perimeters.size() == 1);
|
||||
for(Layer* layer : object.layers()) {
|
||||
REQUIRE(layer->regions()[0]->perimeters.entities.size() == 1);
|
||||
}
|
||||
}
|
||||
THEN("Every layer in region 0 has 3 paths in its perimeters list.") {
|
||||
for(auto* layer : object.layers) {
|
||||
REQUIRE(layer->regions[0]->perimeters.items_count() == 3);
|
||||
THEN("Every layer (but top) in region 0 has 3 paths in its perimeters list.") {
|
||||
LayerPtrs layers = object.layers();
|
||||
for (auto layer = layers.begin(); layer != layers.end() - 1; ++layer) {
|
||||
REQUIRE((*layer)->regions()[0]->perimeters.items_count() == 3);
|
||||
}
|
||||
}
|
||||
THEN("Top layer in region 0 has 1 path in its perimeters list (only 1 perimeter on top).") {
|
||||
REQUIRE(object.layers().back()->regions()[0]->perimeters.items_count() == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("Print: Skirt generation") {
|
||||
GIVEN("20mm cube and default config") {
|
||||
auto config {Slic3r::Config::new_from_defaults()};
|
||||
TestMesh m { TestMesh::cube_20x20x20 };
|
||||
DynamicPrintConfig *config = Slic3r::DynamicPrintConfig::new_from_defaults();
|
||||
TestMesh m = TestMesh::cube_20x20x20;
|
||||
Slic3r::Model model;
|
||||
auto event_counter {0U};
|
||||
unsigned int event_counter = 0U;
|
||||
std::string stage;
|
||||
int value {0};
|
||||
config->set("skirt_height", 1);
|
||||
config->set("skirt_distance", 1);
|
||||
int value = 0;
|
||||
config->set_key_value("skirt_height", new ConfigOptionInt(1));
|
||||
config->set_key_value("skirt_distance", new ConfigOptionFloat(1));
|
||||
WHEN("Skirts is set to 2 loops") {
|
||||
config->set("skirts", 2);
|
||||
auto print {Slic3r::Test::init_print({m}, model, config)};
|
||||
print->make_skirt();
|
||||
config->set_key_value("skirts", new ConfigOptionInt(2));
|
||||
Print print;
|
||||
Slic3r::Test::init_print(print, { m }, model, config);
|
||||
print.process();
|
||||
THEN("Skirt Extrusion collection has 2 loops in it") {
|
||||
REQUIRE(print->skirt.items_count() == 2);
|
||||
REQUIRE(print->skirt.flatten().entities.size() == 2);
|
||||
REQUIRE(print.skirt().items_count() == 2);
|
||||
REQUIRE(print.skirt().flatten().entities.size() == 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -62,36 +72,40 @@ SCENARIO("Print: Skirt generation") {
|
||||
|
||||
SCENARIO("Print: Brim generation") {
|
||||
GIVEN("20mm cube and default config, 1mm first layer width") {
|
||||
auto config {Slic3r::Config::new_from_defaults()};
|
||||
TestMesh m { TestMesh::cube_20x20x20 };
|
||||
DynamicPrintConfig *config = Slic3r::DynamicPrintConfig::new_from_defaults();
|
||||
TestMesh m = TestMesh::cube_20x20x20;
|
||||
Slic3r::Model model;
|
||||
auto event_counter {0U};
|
||||
unsigned int event_counter = 0U;
|
||||
std::string stage;
|
||||
int value {0};
|
||||
config->set("first_layer_extrusion_width", 1);
|
||||
int value = 0;
|
||||
config->set_key_value("first_layer_extrusion_width", new ConfigOptionFloatOrPercent(1, false));
|
||||
WHEN("Brim is set to 3mm") {
|
||||
config->set("brim_width", 3);
|
||||
auto print {Slic3r::Test::init_print({m}, model, config)};
|
||||
print->make_brim();
|
||||
config->set_key_value("brim_width", new ConfigOptionFloat(3));
|
||||
Print print;
|
||||
Slic3r::Test::init_print(print, { m }, model, config);
|
||||
print.process();
|
||||
THEN("Brim Extrusion collection has 3 loops in it") {
|
||||
REQUIRE(print->brim.items_count() == 3);
|
||||
REQUIRE(print.brim().items_count() == 3);
|
||||
}
|
||||
}
|
||||
WHEN("Brim is set to 6mm") {
|
||||
config->set("brim_width", 6);
|
||||
auto print {Slic3r::Test::init_print({m}, model, config)};
|
||||
print->make_brim();
|
||||
config->set_key_value("brim_width", new ConfigOptionFloat(6));
|
||||
Print print;
|
||||
Slic3r::Test::init_print(print, { m }, model, config);
|
||||
print.process();
|
||||
THEN("Brim Extrusion collection has 6 loops in it") {
|
||||
REQUIRE(print->brim.items_count() == 6);
|
||||
REQUIRE(print.brim().items_count() == 6);
|
||||
}
|
||||
}
|
||||
WHEN("Brim is set to 6mm, extrusion width 0.5mm") {
|
||||
config->set("brim_width", 6);
|
||||
config->set("first_layer_extrusion_width", 0.5);
|
||||
auto print {Slic3r::Test::init_print({m}, model, config)};
|
||||
print->make_brim();
|
||||
THEN("Brim Extrusion collection has 12 loops in it") {
|
||||
REQUIRE(print->brim.items_count() == 12);
|
||||
config->set_key_value("brim_width", new ConfigOptionFloat(6));
|
||||
config->set_key_value("first_layer_extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
|
||||
Print print;
|
||||
Slic3r::Test::init_print(print, { m }, model, config);
|
||||
print.process();
|
||||
double nbLoops = 6.0 / print.brim_flow().spacing();
|
||||
THEN("Brim Extrusion collection has " + std::to_string(nbLoops) + " loops in it (flow="+ std::to_string(print.brim_flow().spacing())+")") {
|
||||
REQUIRE(print.brim().items_count() == floor(nbLoops));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user