restore most loop orientation to ccw.

add test_model and test_print tests. Work is needed for them
This commit is contained in:
supermerill 2019-04-02 19:18:01 +02:00
parent 4e1e4cff73
commit c03564f218
14 changed files with 152 additions and 84 deletions

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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; }

View File

@ -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]);

View File

@ -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.

View File

@ -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_

View File

@ -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] = {

View File

@ -77,6 +77,9 @@ public:
stl_file stl;
bool repaired;
/// --- for tests ----- ///
Pointf3s vertices();
private:
void require_shared_vertices();

View File

@ -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)

View File

@ -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

View File

@ -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");
}
}

View File

@ -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));
}
}
}