mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-10-04 16:16:30 +08:00
183 lines
6.9 KiB
C++
183 lines
6.9 KiB
C++
#include "libslic3r.h"
|
|
#include "TriangleMesh.hpp"
|
|
#include "SlicingAdaptive.hpp"
|
|
|
|
#ifdef SLIC3R_DEBUG
|
|
#undef NDEBUG
|
|
#define DEBUG
|
|
#define _DEBUG
|
|
#endif
|
|
|
|
/* This constant essentially describes the volumetric error at the surface which is induced
|
|
* by stacking "elliptic" extrusion threads.
|
|
* It is empirically determined by
|
|
* 1. measuring the surface profile of printed parts to find
|
|
* the ratio between layer height and profile height and then
|
|
* 2. computing the geometric difference between the model-surface and the elliptic profile.
|
|
* [Link to detailed description follows]
|
|
*/
|
|
#define SURFACE_CONST 0.18403
|
|
|
|
namespace Slic3r
|
|
{
|
|
|
|
void SlicingAdaptive::clear()
|
|
{
|
|
m_meshes.clear();
|
|
m_faces.clear();
|
|
m_face_normal_z.clear();
|
|
}
|
|
|
|
std::pair<float, float> face_z_span(const stl_facet *f)
|
|
{
|
|
return std::pair<float, float>(
|
|
std::min(std::min(f->vertex[0].z, f->vertex[1].z), f->vertex[2].z),
|
|
std::max(std::max(f->vertex[0].z, f->vertex[1].z), f->vertex[2].z));
|
|
}
|
|
|
|
void SlicingAdaptive::prepare(coordf_t object_size)
|
|
{
|
|
this->object_size = object_size;
|
|
|
|
// 1) Collect faces of all meshes.
|
|
int nfaces_total = 0;
|
|
for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh)
|
|
nfaces_total += (*it_mesh)->stl.stats.number_of_facets;
|
|
m_faces.reserve(nfaces_total);
|
|
for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh)
|
|
for (int i = 0; i < (*it_mesh)->stl.stats.number_of_facets; ++ i)
|
|
m_faces.push_back((*it_mesh)->stl.facet_start + i);
|
|
|
|
// 2) Sort faces lexicographically by their Z span.
|
|
std::sort(m_faces.begin(), m_faces.end(), [](const stl_facet *f1, const stl_facet *f2) {
|
|
std::pair<float, float> span1 = face_z_span(f1);
|
|
std::pair<float, float> span2 = face_z_span(f2);
|
|
return span1 < span2;
|
|
});
|
|
|
|
// 3) Generate Z components of the facet normals.
|
|
m_face_normal_z.assign(m_faces.size(), 0.f);
|
|
for (size_t iface = 0; iface < m_faces.size(); ++ iface)
|
|
m_face_normal_z[iface] = m_faces[iface]->normal.z;
|
|
|
|
// 4) Reset current facet pointer
|
|
this->current_facet = 0;
|
|
}
|
|
|
|
float SlicingAdaptive::next_layer_height(coordf_t z, coordf_t quality_factor, coordf_t min_layer_height, coordf_t max_layer_height)
|
|
{
|
|
float height = max_layer_height;
|
|
// factor must be between 0-1, 0 is highest quality, 1 highest print speed.
|
|
|
|
// factor must be between 0-1, 0 is highest quality, 1 highest print speed.
|
|
// Invert the slider scale (100% should represent a very high quality for the user)
|
|
quality_factor = std::max(0.f, std::min<float>(1.f, 1 - quality_factor/100.f));
|
|
|
|
float delta_min = SURFACE_CONST * min_layer_height;
|
|
float delta_max = SURFACE_CONST * max_layer_height + 0.5 * max_layer_height;
|
|
float scaled_quality_factor = quality_factor * (delta_max - delta_min) + delta_min;
|
|
|
|
bool first_hit = false;
|
|
|
|
// find all facets intersecting the slice-layer
|
|
int ordered_id = current_facet;
|
|
for (; ordered_id < int(m_faces.size()); ++ ordered_id) {
|
|
std::pair<float, float> zspan = face_z_span(m_faces[ordered_id]);
|
|
// facet's minimum is higher than slice_z -> end loop
|
|
if (zspan.first >= z)
|
|
break;
|
|
// facet's maximum is higher than slice_z -> store the first event for next layer_height call to begin at this point
|
|
if (zspan.second > z) {
|
|
// first event?
|
|
if (! first_hit) {
|
|
first_hit = true;
|
|
current_facet = ordered_id;
|
|
}
|
|
// skip touching facets which could otherwise cause small height values
|
|
if (zspan.second <= z + EPSILON)
|
|
continue;
|
|
// compute height for this facet and store minimum of all heights
|
|
height = std::min(height, this->_layer_height_from_facet(ordered_id, scaled_quality_factor));
|
|
}
|
|
}
|
|
|
|
// lower height limit due to printer capabilities
|
|
height = std::max<float>(height, min_layer_height);
|
|
|
|
// check for sloped facets inside the determined layer and correct height if necessary
|
|
if (height > min_layer_height) {
|
|
for (; ordered_id < int(m_faces.size()); ++ ordered_id) {
|
|
std::pair<float, float> zspan = face_z_span(m_faces[ordered_id]);
|
|
// facet's minimum is higher than slice_z + height -> end loop
|
|
if (zspan.first >= z + height)
|
|
break;
|
|
|
|
// skip touching facets which could otherwise cause small cusp values
|
|
if (zspan.second <= z + EPSILON)
|
|
continue;
|
|
|
|
// Compute new height for this facet and check against height.
|
|
float reduced_height = this->_layer_height_from_facet(ordered_id, scaled_quality_factor);
|
|
|
|
float z_diff = zspan.first - z;
|
|
|
|
if (reduced_height > z_diff) {
|
|
if (reduced_height < height) {
|
|
#ifdef DEBUG
|
|
std::cout << "adaptive layer computation: height is reduced from " << height;
|
|
#endif
|
|
height = reduced_height;
|
|
#ifdef DEBUG
|
|
std::cout << "to " << height << " due to higher facet" << std::endl;
|
|
#endif
|
|
}
|
|
} else {
|
|
#ifdef DEBUG
|
|
std::cout << "cusp computation, height is reduced from " << height;
|
|
#endif
|
|
height = z_diff;
|
|
#ifdef DEBUG
|
|
std::cout << "to " << height << " due to z-diff" << std::endl;
|
|
#endif
|
|
}
|
|
}
|
|
// lower height limit due to printer capabilities again
|
|
height = std::max(height, float(min_layer_height));
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
std::cout << "adaptive layer computation, layer-bottom at z:" << z << ", quality_factor:" << quality_factor << ", resulting layer height:" << height << std::endl;
|
|
#endif
|
|
return height;
|
|
}
|
|
|
|
// Returns the distance to the next horizontal facet in Z-dir
|
|
// to consider horizontal object features in slice thickness
|
|
float SlicingAdaptive::horizontal_facet_distance(coordf_t z, coordf_t max_layer_height)
|
|
{
|
|
for (size_t i = 0; i < m_faces.size(); ++ i) {
|
|
std::pair<float, float> zspan = face_z_span(m_faces[i]);
|
|
// facet's minimum is higher than max forward distance -> end loop
|
|
if (zspan.first > z + max_layer_height)
|
|
break;
|
|
// min_z == max_z -> horizontal facet
|
|
if (zspan.first > z && zspan.first == zspan.second)
|
|
return zspan.first - z;
|
|
}
|
|
|
|
// objects maximum?
|
|
return (z + max_layer_height > this->object_size) ?
|
|
std::max<float>(this->object_size - z, 0.f) :
|
|
max_layer_height;
|
|
}
|
|
|
|
// for a given facet, compute maximum height within the allowed surface roughness / stairstepping deviation
|
|
float SlicingAdaptive::_layer_height_from_facet(int ordered_id, float scaled_quality_factor)
|
|
{
|
|
float normal_z = std::abs(m_face_normal_z[ordered_id]);
|
|
float height = scaled_quality_factor/(SURFACE_CONST + normal_z/2);
|
|
return (normal_z == 0.f) ? 9999.f : height;
|
|
}
|
|
|
|
}; // namespace Slic3r
|