Merge remote-tracking branch 'origin/master' into ys_msw_dpi

This commit is contained in:
YuSanka 2019-04-14 13:49:22 +02:00
commit df7ada0199
104 changed files with 2162 additions and 410 deletions

View file

@ -189,7 +189,6 @@ target_link_libraries(libslic3r
clipper
nowide
${EXPAT_LIBRARIES}
${GLEW_LIBRARIES}
glu-libtess
polypartition
poly2tri

View file

@ -593,6 +593,8 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
this->origin_translation = rhs.origin_translation;
m_bounding_box = rhs.m_bounding_box;
m_bounding_box_valid = rhs.m_bounding_box_valid;
m_raw_bounding_box = rhs.m_raw_bounding_box;
m_raw_bounding_box_valid = rhs.m_raw_bounding_box_valid;
m_raw_mesh_bounding_box = rhs.m_raw_mesh_bounding_box;
m_raw_mesh_bounding_box_valid = rhs.m_raw_mesh_bounding_box_valid;
@ -627,6 +629,8 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
this->origin_translation = std::move(rhs.origin_translation);
m_bounding_box = std::move(rhs.m_bounding_box);
m_bounding_box_valid = std::move(rhs.m_bounding_box_valid);
m_raw_bounding_box = rhs.m_raw_bounding_box;
m_raw_bounding_box_valid = rhs.m_raw_bounding_box_valid;
m_raw_mesh_bounding_box = rhs.m_raw_mesh_bounding_box;
m_raw_mesh_bounding_box_valid = rhs.m_raw_mesh_bounding_box_valid;
@ -859,7 +863,7 @@ TriangleMesh ModelObject::full_raw_mesh() const
return mesh;
}
BoundingBoxf3 ModelObject::raw_mesh_bounding_box() const
const BoundingBoxf3& ModelObject::raw_mesh_bounding_box() const
{
if (! m_raw_mesh_bounding_box_valid) {
m_raw_mesh_bounding_box_valid = true;
@ -880,33 +884,36 @@ BoundingBoxf3 ModelObject::full_raw_mesh_bounding_box() const
}
// A transformed snug bounding box around the non-modifier object volumes, without the translation applied.
// This bounding box is only used for the actual slicing.
BoundingBoxf3 ModelObject::raw_bounding_box() const
// This bounding box is only used for the actual slicing and for layer editing UI to calculate the layers.
const BoundingBoxf3& ModelObject::raw_bounding_box() const
{
BoundingBoxf3 bb;
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
if (this->instances.empty())
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
if (! m_raw_bounding_box_valid) {
m_raw_bounding_box_valid = true;
m_raw_bounding_box.reset();
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
if (this->instances.empty())
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
for (const ModelVolume *v : this->volumes)
if (v->is_model_part()) {
#if !ENABLE_GENERIC_SUBPARTS_PLACEMENT
if (this->instances.empty())
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
#endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT
const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
for (const ModelVolume *v : this->volumes)
if (v->is_model_part()) {
#if !ENABLE_GENERIC_SUBPARTS_PLACEMENT
if (this->instances.empty())
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
#endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT
TriangleMesh vol_mesh(v->mesh);
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
vol_mesh.transform(inst_matrix * v->get_matrix());
bb.merge(vol_mesh.bounding_box());
#else
vol_mesh.transform(v->get_matrix());
bb.merge(this->instances.front()->transform_mesh_bounding_box(vol_mesh, true));
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
}
return bb;
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
m_raw_bounding_box.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix()));
#else
// unmaintaned
assert(false);
// vol_mesh.transform(v->get_matrix());
// m_raw_bounding_box_valid.merge(this->instances.front()->transform_mesh_bounding_box(vol_mesh, true));
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
}
}
return m_raw_bounding_box;
}
// This returns an accurate snug bounding box of the transformed object instance, without the translation applied.
@ -920,13 +927,13 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_
{
if (v->is_model_part())
{
TriangleMesh mesh(v->mesh);
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
mesh.transform(inst_matrix * v->get_matrix());
bb.merge(mesh.bounding_box());
bb.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix()));
#else
mesh.transform(v->get_matrix());
bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(mesh, dont_translate));
// not maintained
assert(false);
//mesh.transform(v->get_matrix());
//bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(mesh, dont_translate));
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
}
}

View file

@ -212,7 +212,7 @@ public:
// This bounding box is approximate and not snug.
// This bounding box is being cached.
const BoundingBoxf3& bounding_box() const;
void invalidate_bounding_box() { m_bounding_box_valid = false; m_raw_mesh_bounding_box_valid = false; }
void invalidate_bounding_box() { m_bounding_box_valid = false; m_raw_bounding_box_valid = false; m_raw_mesh_bounding_box_valid = false; }
// A mesh containing all transformed instances of this object.
TriangleMesh mesh() const;
@ -223,11 +223,11 @@ public:
TriangleMesh full_raw_mesh() const;
// A transformed snug bounding box around the non-modifier object volumes, without the translation applied.
// This bounding box is only used for the actual slicing.
BoundingBoxf3 raw_bounding_box() const;
const BoundingBoxf3& raw_bounding_box() const;
// A snug bounding box around the transformed non-modifier object volumes.
BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const;
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
BoundingBoxf3 raw_mesh_bounding_box() const;
const BoundingBoxf3& raw_mesh_bounding_box() const;
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
BoundingBoxf3 full_raw_mesh_bounding_box() const;
@ -285,7 +285,7 @@ protected:
private:
ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()),
m_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) {}
m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) {}
~ModelObject();
/* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */
@ -304,6 +304,8 @@ private:
// Bounding box, cached.
mutable BoundingBoxf3 m_bounding_box;
mutable bool m_bounding_box_valid;
mutable BoundingBoxf3 m_raw_bounding_box;
mutable bool m_raw_bounding_box_valid;
mutable BoundingBoxf3 m_raw_mesh_bounding_box;
mutable bool m_raw_mesh_bounding_box_valid;
};

View file

@ -132,7 +132,7 @@ public:
// The slicing parameters are dependent on various configuration values
// (layer height, first layer height, raft settings, print nozzle diameter etc).
const SlicingParameters& slicing_parameters() const { return m_slicing_params; }
static SlicingParameters slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object);
static SlicingParameters slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z);
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
std::vector<unsigned int> object_extruders() const;

View file

@ -2528,14 +2528,17 @@ void PrintConfigDef::init_sla_params()
def = this->add("pad_wall_height", coFloat);
def->label = L("Pad wall height");
def->tooltip = L("Defines the cavity depth. Set to zero to disable the cavity.");
def->tooltip = L("Defines the pad cavity depth. Set to zero to disable the cavity. "
"Be careful when enabling this feature, as some resins may "
"produce an extreme suction effect inside the cavity, "
"which makes pealing the print off the vat foil difficult.");
def->category = L("Pad");
// def->tooltip = L("");
def->sidetext = L("mm");
def->min = 0;
def->max = 30;
def->mode = comSimple;
def->default_value = new ConfigOptionFloat(5.0);
def->mode = comExpert;
def->default_value = new ConfigOptionFloat(0.);
def = this->add("pad_max_merge_distance", coFloat);
def->label = L("Max merge distance");
@ -3114,6 +3117,13 @@ CLIMiscConfigDef::CLIMiscConfigDef()
def->label = L("Logging level");
def->tooltip = L("Messages with severity lower or eqal to the loglevel will be printed out. 0:trace, 1:debug, 2:info, 3:warning, 4:error, 5:fatal");
def->min = 0;
#if defined(_MSC_VER) && defined(SLIC3R_GUI)
def = this->add("sw_renderer", coBool);
def->label = L("Render with a software renderer");
def->tooltip = L("Render with a software renderer. The bundled MESA software renderer is loaded instead of the default OpenGL driver.");
def->min = 0;
#endif /* _MSC_VER */
}
const CLIActionsConfigDef cli_actions_config_def;

View file

@ -1370,7 +1370,7 @@ void PrintObject::update_slicing_parameters()
this->print()->config(), m_config, unscale<double>(this->size(2)), this->object_extruders());
}
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object)
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z)
{
PrintConfig print_config;
PrintObjectConfig object_config;
@ -1390,7 +1390,9 @@ SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full
object_extruders);
sort_remove_duplicates(object_extruders);
return SlicingParameters::create_from_config(print_config, object_config, model_object.bounding_box().max.z(), object_extruders);
if (object_max_z <= 0.f)
object_max_z = model_object.raw_bounding_box().size().z();
return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders);
}
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)

View file

@ -1572,10 +1572,8 @@ public:
auto hit = bridge_mesh_intersect(headjp, n, r);
if(std::isinf(hit.distance())) ground_head_indices.emplace_back(i);
else {
if(m_cfg.ground_facing_only) head.invalidate();
m_iheads_onmodel.emplace_back(std::make_pair(i, hit));
}
else if(m_cfg.ground_facing_only) head.invalidate();
else m_iheads_onmodel.emplace_back(std::make_pair(i, hit));
}
// We want to search for clusters of points that are far enough
@ -1872,7 +1870,7 @@ public:
}
}
void cascade_pillars() {
void interconnect_pillars() {
// Now comes the algorithm that connects pillars with each other.
// Ideally every pillar should be connected with at least one of its
// neighbors if that neighbor is within max_pillar_link_distance
@ -2121,7 +2119,7 @@ bool SLASupportTree::generate(const std::vector<SupportPoint> &support_points,
std::bind(&Algorithm::routing_to_model, &alg),
std::bind(&Algorithm::cascade_pillars, &alg),
std::bind(&Algorithm::interconnect_pillars, &alg),
std::bind(&Algorithm::routing_headless, &alg),
@ -2150,16 +2148,16 @@ bool SLASupportTree::generate(const std::vector<SupportPoint> &support_points,
// Let's define a simple automaton that will run our program.
auto progress = [&ctl, &pc] () {
static const std::array<std::string, NUM_STEPS> stepstr {
L("Starting"),
L("Filtering"),
L("Generate pinheads"),
L("Classification"),
L("Routing to ground"),
L("Routing supports to model surface"),
L("Cascading pillars"),
L("Processing small holes"),
L("Done"),
L("Abort")
"Starting",
"Filtering",
"Generate pinheads",
"Classification",
"Routing to ground",
"Routing supports to model surface",
"Interconnecting pillars",
"Processing small holes",
"Done",
"Abort"
};
static const std::array<unsigned, NUM_STEPS> stepstate {

View file

@ -693,6 +693,16 @@ void TriangleMeshSlicer::init(TriangleMesh *_mesh, throw_on_cancel_callback_type
}
}
void TriangleMeshSlicer::set_up_direction(const Vec3f& up)
{
m_quaternion.setFromTwoVectors(up, Vec3f::UnitZ());
m_use_quaternion = true;
}
void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
{
BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::slice";
@ -795,7 +805,7 @@ void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons
void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex,
const std::vector<float> &z) const
{
const stl_facet &facet = this->mesh->stl.facet_start[facet_idx];
const stl_facet &facet = m_use_quaternion ? this->mesh->stl.facet_start[facet_idx].rotated(m_quaternion) : this->mesh->stl.facet_start[facet_idx];
// find facet extents
const float min_z = fminf(facet.vertex[0](2), fminf(facet.vertex[1](2), facet.vertex[2](2)));
@ -860,26 +870,43 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet(
IntersectionPoint points[3];
size_t num_points = 0;
size_t point_on_layer = size_t(-1);
// Reorder vertices so that the first one is the one with lowest Z.
// This is needed to get all intersection lines in a consistent order
// (external on the right of the line)
const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex;
int i = (facet.vertex[1].z() == min_z) ? 1 : ((facet.vertex[2].z() == min_z) ? 2 : 0);
// These are used only if the cut plane is tilted:
stl_vertex rotated_a;
stl_vertex rotated_b;
for (int j = i; j - i < 3; ++j) { // loop through facet edges
int edge_id = this->facets_edges[facet_idx * 3 + (j % 3)];
int a_id = vertices[j % 3];
int b_id = vertices[(j+1) % 3];
const stl_vertex *a = &this->v_scaled_shared[a_id];
const stl_vertex *b = &this->v_scaled_shared[b_id];
const stl_vertex *a;
const stl_vertex *b;
if (m_use_quaternion) {
rotated_a = m_quaternion * this->v_scaled_shared[a_id];
rotated_b = m_quaternion * this->v_scaled_shared[b_id];
a = &rotated_a;
b = &rotated_b;
}
else {
a = &this->v_scaled_shared[a_id];
b = &this->v_scaled_shared[b_id];
}
// Is edge or face aligned with the cutting plane?
if (a->z() == slice_z && b->z() == slice_z) {
// Edge is horizontal and belongs to the current layer.
const stl_vertex &v0 = this->v_scaled_shared[vertices[0]];
const stl_vertex &v1 = this->v_scaled_shared[vertices[1]];
const stl_vertex &v2 = this->v_scaled_shared[vertices[2]];
const stl_normal &normal = this->mesh->stl.facet_start[facet_idx].normal;
// The following rotation of the three vertices may not be efficient, but this branch happens rarely.
const stl_vertex &v0 = m_use_quaternion ? stl_vertex(m_quaternion * this->v_scaled_shared[vertices[0]]) : this->v_scaled_shared[vertices[0]];
const stl_vertex &v1 = m_use_quaternion ? stl_vertex(m_quaternion * this->v_scaled_shared[vertices[1]]) : this->v_scaled_shared[vertices[1]];
const stl_vertex &v2 = m_use_quaternion ? stl_vertex(m_quaternion * this->v_scaled_shared[vertices[2]]) : this->v_scaled_shared[vertices[2]];
const stl_normal &normal = facet.normal;
// We may ignore this edge for slicing purposes, but we may still use it for object cutting.
FacetSliceType result = Slicing;
if (min_z == max_z) {
@ -995,7 +1022,9 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet(
if (i == line_out->a_id || i == line_out->b_id)
i = vertices[2];
assert(i != line_out->a_id && i != line_out->b_id);
line_out->edge_type = (this->v_scaled_shared[i].z() < slice_z) ? feTop : feBottom;
line_out->edge_type = ((m_use_quaternion ?
(m_quaternion * this->v_scaled_shared[i]).z()
: this->v_scaled_shared[i].z()) < slice_z) ? feTop : feBottom;
}
#endif
return Slicing;

View file

@ -25,9 +25,10 @@ public:
TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd> &facets);
TriangleMesh(const TriangleMesh &other) : repaired(false) { stl_initialize(&this->stl); *this = other; }
TriangleMesh(TriangleMesh &&other) : repaired(false) { stl_initialize(&this->stl); this->swap(other); }
~TriangleMesh() { stl_close(&this->stl); }
~TriangleMesh() { clear(); }
TriangleMesh& operator=(const TriangleMesh &other);
TriangleMesh& operator=(TriangleMesh &&other) { this->swap(other); return *this; }
void clear() { stl_close(&this->stl); this->repaired = false; }
void swap(TriangleMesh &other) { std::swap(this->stl, other.stl); std::swap(this->repaired, other.repaired); }
void ReadSTLFile(const char* input_file) { stl_open(&stl, input_file); }
void write_ascii(const char* output_file) { stl_write_ascii(&this->stl, output_file, ""); }
@ -171,6 +172,7 @@ public:
FacetSliceType slice_facet(float slice_z, const stl_facet &facet, const int facet_idx,
const float min_z, const float max_z, IntersectionLine *line_out) const;
void cut(float z, TriangleMesh* upper, TriangleMesh* lower) const;
void set_up_direction(const Vec3f& up);
private:
const TriangleMesh *mesh;
@ -178,6 +180,10 @@ private:
std::vector<int> facets_edges;
// Scaled copy of this->mesh->stl.v_shared
std::vector<stl_vertex> v_scaled_shared;
// Quaternion that will be used to rotate every facet before the slicing
Eigen::Quaternion<float, Eigen::DontAlign> m_quaternion;
// Whether or not the above quaterion should be used
bool m_use_quaternion = false;
void _slice_do(size_t facet_idx, std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex, const std::vector<float> &z) const;
void make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) const;