Merge remote-tracking branch 'samir/Samir55-support_porting' into test_merge_samir

# Conflicts:
#	src/CMakeLists.txt
This commit is contained in:
Joseph Lenox 2018-07-15 12:02:11 -05:00
commit 575faf3231
7 changed files with 1743 additions and 13 deletions

View File

@ -60,7 +60,7 @@ sub generate {
$self->clip_with_shape($interface, $shape) if @$shape;
# Propagate contact layers and interface layers downwards to generate
# the main support layers.
# the main support layers.
my ($base) = $self->generate_base_layers($support_z, $contact, $interface, $top);
$self->clip_with_object($base, $support_z, $object);
$self->clip_with_shape($base, $shape) if @$shape;
@ -108,7 +108,7 @@ sub contact_area {
# determine contact areas
my %contact = (); # contact_z => [ polygons ]
my %overhang = (); # contact_z => [ polygons ] - this stores the actual overhang supported by each contact layer
my %overhang = (); # contact_z => [ polygons ] - this stores the actual overhang supported by each contact layer
for my $layer_id (0 .. $#{$object->layers}) {
# note $layer_id might != $layer->id when raft_layers > 0
# so $layer_id == 0 means first object layer
@ -224,7 +224,7 @@ sub contact_area {
# Get all perimeters as polylines.
# TODO: split_at_first_point() (called by as_polyline() for ExtrusionLoops)
# could split a bridge mid-way
# could split a bridge mid-way
my @overhang_perimeters = map $_->as_polyline, @{$layerm->perimeters->flatten};
# Only consider the overhang parts of such perimeters,
@ -374,7 +374,7 @@ sub object_top {
# we considered)
my $min_top = min(keys %top) // max(keys %$contact);
# use <= instead of just < because otherwise we'd ignore any contact regions
# having the same Z of top layers
# having the same Z of top layers
push @$projection, map @{$contact->{$_}}, grep { $_ > $layer->print_z && $_ <= $min_top } keys %$contact;
# now find whether any projection falls onto this top surface
@ -511,7 +511,7 @@ sub generate_bottom_interface_layers {
my $interface_layers = 0;
# loop through support layers until we find the one(s) right above the top
# surface
# surface
foreach my $layer_id (0 .. $#$support_z) {
my $z = $support_z->[$layer_id];
next unless $z > $top_z;
@ -581,7 +581,7 @@ sub generate_base_layers {
# This method removes object silhouette from support material
# (it's used with interface and base only). It removes a bit more,
# leaving a thin gap between object and support in the XY plane.
# leaving a thin gap between object and support in the XY plane.
sub clip_with_object {
my ($self, $support, $support_z, $object) = @_;
@ -595,7 +595,7 @@ sub clip_with_object {
# $layer->slices contains the full shape of layer, thus including
# perimeter's width. $support contains the full shape of support
# material, thus including the width of its foremost extrusion.
# material, thus including the width of its foremost extrusion.
# We leave a gap equal to a full extrusion width.
$support->{$i} = diff(
$support->{$i},
@ -825,7 +825,7 @@ sub generate_toolpaths {
$base_flow = $self->first_layer_flow;
# use the proper spacing for first layer as we don't need to align
# its pattern to the other layers
# its pattern to the other layers
$filler->set_min_spacing($base_flow->spacing);
# subtract brim so that it goes around the object fully (and support gets its own brim)

View File

@ -89,7 +89,7 @@ include_directories(${LIBDIR}/poly2tri/common)
add_library(ZipArchive STATIC
${LIBDIR}/Zip/ZipArchive.cpp
)
target_compile_features(ZipArchive PUBLIC cxx_std_11)
add_library(libslic3r STATIC
${LIBDIR}/libslic3r/BoundingBox.cpp
@ -146,12 +146,11 @@ add_library(libslic3r STATIC
${LIBDIR}/libslic3r/SurfaceCollection.cpp
${LIBDIR}/libslic3r/SVG.cpp
${LIBDIR}/libslic3r/TriangleMesh.cpp
${LIBDIR}/libslic3r/SupportMaterial.cpp
${LIBDIR}/libslic3r/utils.cpp
)
target_compile_features(libslic3r PUBLIC cxx_std_11)
add_library(BSpline STATIC
${LIBDIR}/BSpline/BSpline.cpp
)
@ -172,6 +171,8 @@ add_library(expat STATIC
${LIBDIR}/expat/xmlrole.c
${LIBDIR}/expat/xmltok.c
)
target_compile_features(clipper PUBLIC cxx_std_11)
add_library(polypartition STATIC ${LIBDIR}/polypartition.cpp)
add_library(poly2tri STATIC
${LIBDIR}/poly2tri/common/shapes.cc
@ -200,6 +201,7 @@ set(SLIC3R_TEST_SOURCES
${TESTDIR}/test_data.cpp
${TESTDIR}/libslic3r/test_trianglemesh.cpp
${TESTDIR}/libslic3r/test_config.cpp
${TESTDIR}/libslic3r/test_support_material.cpp
)
add_executable(slic3r slic3r.cpp)
#set_target_properties(slic3r PROPERTIES LINK_SEARCH_START_STATIC 1)

View File

@ -0,0 +1,296 @@
//#include <catch.hpp>
#include <libslic3r/IO.hpp>
#include <libslic3r/GCodeReader.hpp>
#include "/home/ahmedsamir/Work/SamirSlic3r/Slic3r/build/external/Catch/include/catch.hpp"
#include "libslic3r.h"
#include "TriangleMesh.hpp"
#include "Model.hpp"
#include "SupportMaterial.hpp"
using namespace std;
using namespace Slic3r;
void test_1_checks(Print &print, bool &a, bool &b, bool &c, bool &d);
bool test_6_checks(Print &print);
// Testing 0.1: supports material member functions.
TEST_CASE("", "")
{
// Create a mesh & modelObject.
TriangleMesh mesh = TriangleMesh::make_cube(20, 20, 20);
// Create modelObject.
Model model = Model();
ModelObject *object = model.add_object();
object->add_volume(mesh);
model.add_default_instances();
// Align to origin.
model.align_instances_to_origin();
// Create Print.
Print print = Print();
vector<coordf_t> contact_z = {1.9};
vector<coordf_t> top_z = {1.1};
print.default_object_config.support_material = 1;
print.default_object_config.set_deserialize("raft_layers", "3");
print.add_model_object(model.objects[0]);
print.objects.front()->_slice();
SupportMaterial *support = print.objects.front()->_support_material();
support->generate(print.objects.front());
REQUIRE(print.objects.front()->support_layer_count() == 3);
}
// Test 1.
SCENARIO("SupportMaterial: support_layers_z and contact_distance")
{
GIVEN("A print object having one modelObject") {
// Create a mesh & modelObject.
TriangleMesh mesh = TriangleMesh::make_cube(20, 20, 20);
// Create modelObject.
Model model = Model();
ModelObject *object = model.add_object();
object->add_volume(mesh);
model.add_default_instances();
// Align to origin.
model.align_instances_to_origin();
// Create Print.
Print print = Print();
print.default_object_config.set_deserialize("support_material", "1");
WHEN("First layer height = 0.4") {
print.default_object_config.set_deserialize("layer_height", "0.2");
print.default_object_config.set_deserialize("first_layer_height", "0.4");
print.add_model_object(model.objects[0]);
print.objects.front()->_slice();
bool a, b, c, d;
test_1_checks(print, a, b, c, d);
THEN("First layer height is honored") {
REQUIRE(a == true);
}
THEN("No null or negative support layers") {
REQUIRE(b == true);
}
THEN("No layers thicker than nozzle diameter") {
REQUIRE(c == true);
}
THEN("Layers above top surfaces are spaced correctly") {
REQUIRE(d == true);
}
}
WHEN("Layer height = 0.2 and, first layer height = 0.3") {
print.default_object_config.set_deserialize("layer_height", "0.2");
print.default_object_config.set_deserialize("first_layer_height", "0.3");
print.add_model_object(model.objects[0]);
print.objects.front()->_slice();
bool a, b, c, d;
test_1_checks(print, a, b, c, d);
THEN("First layer height is honored") {
REQUIRE(a == true);
}
THEN("No null or negative support layers") {
REQUIRE(b == true);
}
THEN("No layers thicker than nozzle diameter") {
REQUIRE(c == true);
}
THEN("Layers above top surfaces are spaced correctly") {
REQUIRE(d == true);
}
}
WHEN("Layer height = nozzle_diameter[0]") {
print.default_object_config.set_deserialize("layer_height", "0.2");
print.default_object_config.set_deserialize("first_layer_height", "0.3");
print.add_model_object(model.objects[0]);
print.objects.front()->_slice();
bool a, b, c, d;
test_1_checks(print, a, b, c, d);
THEN("First layer height is honored") {
REQUIRE(a == true);
}
THEN("No null or negative support layers") {
REQUIRE(b == true);
}
THEN("No layers thicker than nozzle diameter") {
REQUIRE(c == true);
}
THEN("Layers above top surfaces are spaced correctly") {
REQUIRE(d == true);
}
}
}
}
// Test 8.
TEST_CASE("SupportMaterial: forced support is generated", "")
{
// Create a mesh & modelObject.
TriangleMesh mesh = TriangleMesh::make_cube(20, 20, 20);
Model model = Model();
ModelObject *object = model.add_object();
object->add_volume(mesh);
model.add_default_instances();
model.align_instances_to_origin();
Print print = Print();
vector<coordf_t> contact_z = {1.9};
vector<coordf_t> top_z = {1.1};
print.default_object_config.support_material_enforce_layers = 100;
print.default_object_config.support_material = 0;
print.default_object_config.layer_height = 0.2;
print.default_object_config.set_deserialize("first_layer_height", "0.3");
print.add_model_object(model.objects[0]);
print.objects.front()->_slice();
SupportMaterial *support = print.objects.front()->_support_material();
auto support_z = support->support_layers_z(contact_z, top_z, print.default_object_config.layer_height);
bool check = true;
for (size_t i = 1; i < support_z.size(); i++) {
if (support_z[i] - support_z[i - 1] <= 0)
check = false;
}
REQUIRE(check == true);
}
// Test 6.
SCENARIO("SupportMaterial: Checking bridge speed")
{
GIVEN("Print object") {
// Create a mesh & modelObject.
TriangleMesh mesh = TriangleMesh::make_cube(20, 20, 20);
Model model = Model();
ModelObject *object = model.add_object();
object->add_volume(mesh);
model.add_default_instances();
model.align_instances_to_origin();
Print print = Print();
print.config.brim_width = 0;
print.config.skirts = 0;
print.config.skirts = 0;
print.default_object_config.support_material = 1;
print.default_region_config.top_solid_layers = 0; // so that we don't have the internal bridge over infill.
print.default_region_config.bridge_speed = 99;
print.config.cooling = 0;
print.config.set_deserialize("first_layer_speed", "100%");
WHEN("support_material_contact_distance = 0.2") {
print.default_object_config.support_material_contact_distance = 0.2;
print.add_model_object(model.objects[0]);
bool check = test_6_checks(print);
REQUIRE(check == true); // bridge speed is used.
}
WHEN("support_material_contact_distance = 0") {
print.default_object_config.support_material_contact_distance = 0;
print.add_model_object(model.objects[0]);
bool check = test_6_checks(print);
REQUIRE(check == true); // bridge speed is not used.
}
WHEN("support_material_contact_distance = 0.2 & raft_layers = 5") {
print.default_object_config.support_material_contact_distance = 0.2;
print.default_object_config.raft_layers = 5;
print.add_model_object(model.objects[0]);
bool check = test_6_checks(print);
REQUIRE(check == true); // bridge speed is used.
}
WHEN("support_material_contact_distance = 0 & raft_layers = 5") {
print.default_object_config.support_material_contact_distance = 0;
print.default_object_config.raft_layers = 5;
print.add_model_object(model.objects[0]);
bool check = test_6_checks(print);
REQUIRE(check == true); // bridge speed is not used.
}
}
}
void test_1_checks(Print &print, bool &a, bool &b, bool &c, bool &d)
{
vector<coordf_t> contact_z = {1.9};
vector<coordf_t> top_z = {1.1};
SupportMaterial *support = print.objects.front()->_support_material();
vector<coordf_t>
support_z = support->support_layers_z(contact_z, top_z, print.default_object_config.layer_height);
a = (support_z[0] == print.default_object_config.first_layer_height.value);
b = true;
for (size_t i = 1; i < support_z.size(); ++i)
if (support_z[i] - support_z[i - 1] <= 0) b = false;
c = true;
for (size_t i = 1; i < support_z.size(); ++i)
if (support_z[i] - support_z[i - 1] > print.config.nozzle_diameter.get_at(0) + EPSILON)
c = false;
coordf_t expected_top_spacing = support
->contact_distance(print.default_object_config.layer_height,
print.config.nozzle_diameter.get_at(0));
bool wrong_top_spacing = 0;
for (coordf_t top_z_el : top_z) {
// find layer index of this top surface.
size_t layer_id = -1;
for (size_t i = 0; i < support_z.size(); i++) {
if (abs(support_z[i] - top_z_el) < EPSILON) {
layer_id = i;
i = static_cast<int>(support_z.size());
}
}
// check that first support layer above this top surface (or the next one) is spaced with nozzle diameter
if (abs(support_z[layer_id + 1] - support_z[layer_id] - expected_top_spacing) > EPSILON
&& abs(support_z[layer_id + 2] - support_z[layer_id] - expected_top_spacing) > EPSILON) {
wrong_top_spacing = 1;
}
}
d = !wrong_top_spacing;
}
// TODO
bool test_6_checks(Print &print)
{
bool has_bridge_speed = true;
// Pre-Processing.
PrintObject *print_object = print.objects.front();
print_object->_infill();
SupportMaterial *support_material = print.objects.front()->_support_material();
support_material->generate(print_object);
// TODO but not needed in test 6 (make brims and make skirts).
// Exporting gcode.
// TODO validation found in Simple.pm
return has_bridge_speed;
}

View File

@ -15,6 +15,7 @@
#include "PlaceholderParser.hpp"
#include "SlicingAdaptive.hpp"
#include "LayerHeightSpline.hpp"
#include "SupportMaterial.hpp"
#include <exception>
@ -25,6 +26,7 @@ class InvalidObjectException : public std::exception {};
class Print;
class PrintObject;
class ModelObject;
class SupportMaterial;
// Print step IDs for keeping track of the print state.
enum PrintStep {
@ -132,6 +134,8 @@ class PrintObject
Layer* add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
void delete_layer(int idx);
SupportMaterial* _support_material();
Flow _support_material_flow(FlowRole role = frSupportMaterial);
size_t support_layer_count() const;
void clear_support_layers();
SupportLayer* get_support_layer(int idx) { return this->support_layers.at(idx); };
@ -232,7 +236,6 @@ class Print
void auto_assign_extruders(ModelObject* model_object) const;
std::string output_filename();
std::string output_filepath(const std::string &path);
private:
void clear_regions();
void delete_region(size_t idx);

View File

@ -1095,4 +1095,55 @@ PrintObject::_infill()
this->state.set_done(posInfill);
}
SupportMaterial *
PrintObject::_support_material()
{
// TODO what does this line do //= FLOW_ROLE_SUPPORT_MATERIAL;
Flow first_layer_flow = Flow::new_from_config_width(
frSupportMaterial,
print()->config
.first_layer_extrusion_width, // check why this line is put || config.support_material_extrusion_width,
static_cast<float>(print()->config.nozzle_diameter.get_at(static_cast<size_t>(
config.support_material_extruder
- 1))), // Check why this is put in perl "// $self->print->config->nozzle_diameter->[0]"
static_cast<float>(config.get_abs_value("first_layer_height")),
0 // No bridge flow ratio.
);
return new SupportMaterial(
&print()->config,
&config,
first_layer_flow,
_support_material_flow(),
_support_material_flow(frSupportMaterialInterface)
);
}
Flow
PrintObject::_support_material_flow(FlowRole role)
{
// Create support flow.
int extruder =
(role == frSupportMaterial) ?
config.support_material_extruder.value : config
.support_material_interface_extruder.value;
auto width = config.support_material_extrusion_width; // || config.extrusion_width;
if (role == frSupportMaterialInterface)
width = config.support_material_interface_extrusion_width; // || width;
// We use a bogus layer_height because we use the same flow for all
// support material layers.
Flow support_flow = Flow::new_from_config_width(
role,
width,
static_cast<float>(print()->config.nozzle_diameter
.get_at(static_cast<size_t>(extruder - 1))), // Check this line $self->print->config->nozzle_diameter->[0].
static_cast<float>(config.layer_height.value),
0
);
return support_flow;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,164 @@
#ifndef slic3r_SupportMaterial_hpp_
#define slic3r_SupportMaterial_hpp_
namespace Slic3r {
#include <numeric>
#include <vector>
#include <iostream>
#include <algorithm>
#include "libslic3r.h"
#include "PrintConfig.hpp"
#include "Flow.hpp"
#include "Layer.hpp"
#include "Geometry.hpp"
#include "Print.hpp"
#include "ClipperUtils.hpp"
#include "ExPolygon.hpp"
#include "SVG.hpp"
#include <libslic3r/Fill/Fill.hpp>
using namespace std;
namespace Slic3r
{
// how much we extend support around the actual contact area
constexpr coordf_t SUPPORT_MATERIAL_MARGIN = 1.5;
constexpr coordf_t MARGIN_STEP = SUPPORT_MATERIAL_MARGIN / 3;
constexpr coordf_t PILLAR_SIZE = 2.5;
constexpr coordf_t PILLAR_SPACING = 10;
/// Struct for carrying the toolpaths parameters needed for each thread.
struct toolpaths_params
{
int contact_loops;
coordf_t circle_radius;
coordf_t circle_distance;
Polygon circle;
SupportMaterialPattern pattern;
vector<int> angles;
double interface_angle{};
double interface_spacing{};
float interface_density{};
double support_spacing{};
double support_density{};
toolpaths_params(int contact_loops = 0,
coordf_t circle_radius = 0,
coordf_t circle_distance = 0,
const Polygon &circle = Polygon(),
const SupportMaterialPattern &pattern = SupportMaterialPattern(),
const vector<int> &angles = vector<int>())
: contact_loops(contact_loops),
circle_radius(circle_radius),
circle_distance(circle_distance),
circle(circle),
pattern(pattern),
angles(angles)
{}
};
class SupportMaterial
{
public:
friend PrintObject;
PrintConfig *config; ///< The print config
PrintObjectConfig *object_config; ///< The object print config.
Flow flow; ///< The intermediate layers print flow.
Flow first_layer_flow; ///< The first (base) layers print flow.
Flow interface_flow; ///< The interface layers print flow.
/// Generate the extrusions paths for the support matterial generated for the given print object.
void generate_toolpaths(PrintObject *object,
map<coordf_t, Polygons> overhang,
map<coordf_t, Polygons> contact,
map<int, Polygons> interface,
map<int, Polygons> base);
/// Generate support material for the given print object.
void generate(PrintObject *object);
/// Generate the support layers slicing z coordinates.
vector<coordf_t> support_layers_z(vector<coordf_t> contact_z,
vector<coordf_t> top_z,
coordf_t max_object_layer_height);
pair<map<coordf_t, Polygons>, map<coordf_t, Polygons>> contact_area(PrintObject *object);
map<coordf_t, Polygons> object_top(PrintObject *object, map<coordf_t, Polygons> *contact);
void generate_pillars_shape(const map<coordf_t, Polygons> &contact,
const vector<coordf_t> &support_z,
map<int, Polygons> &shape);
map<int, Polygons> generate_base_layers(vector<coordf_t> support_z,
map<coordf_t, Polygons> contact,
map<int, Polygons> interface,
map<coordf_t, Polygons> top);
map<int, Polygons> generate_interface_layers(vector<coordf_t> support_z,
map<coordf_t, Polygons> contact,
map<coordf_t, Polygons> top);
void generate_bottom_interface_layers(const vector<coordf_t> &support_z,
map<int, Polygons> &base,
map<coordf_t, Polygons> &top,
map<int, Polygons> &interface);
coordf_t contact_distance(coordf_t layer_height, coordf_t nozzle_diameter);
/// This method returns the indices of the layers overlapping with the given one.
vector<int> overlapping_layers(int layer_idx, const vector<coordf_t> &support_z);
void clip_with_shape(map<int, Polygons> &support, map<int, Polygons> &shape);
// This method removes object silhouette from support material
// (it's used with interface and base only). It removes a bit more,
// leaving a thin gap between object and support in the XY plane.
void clip_with_object(map<int, Polygons> &support, vector<coordf_t> support_z, PrintObject &object);
void process_layer(int layer_id, toolpaths_params params);
private:
/// SupportMaterial is generated by PrintObject.
SupportMaterial(PrintConfig *print_config,
PrintObjectConfig *print_object_config,
Flow flow,
Flow first_layer_flow,
Flow interface_flow)
: config(print_config),
object_config(print_object_config),
flow(Flow(0, 0, 0)),
first_layer_flow(Flow(0, 0, 0)),
interface_flow(Flow(0, 0, 0)),
object(nullptr)
{}
// Get the maximum layer height given a print object.
coordf_t get_max_layer_height(PrintObject *object);
// (Deprecated) use append_to instead
void append_polygons(Polygons &dst, Polygons &src);
// Return polygon vector given a vector of surfaces.
Polygons p(SurfacesPtr &surfaces);
vector<coordf_t> get_keys_sorted(map<coordf_t, Polygons> _map);
Polygon create_circle(coordf_t radius);
// Used during generate_toolpaths function.
PrintObject *object;
map<coordf_t, Polygons> overhang;
map<coordf_t, Polygons> contact;
map<int, Polygons> interface;
map<int, Polygons> base;
};
}
#endif