Integrated the new layer height spans with configs into the backend.
Fixed some compiler warnings.
This commit is contained in:
parent
0c95d4e0d9
commit
35b3fd3176
@ -126,7 +126,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
|||||||
Polygons surfaces_polygons = to_polygons(surfaces);
|
Polygons surfaces_polygons = to_polygons(surfaces);
|
||||||
Polygons collapsed = diff(
|
Polygons collapsed = diff(
|
||||||
surfaces_polygons,
|
surfaces_polygons,
|
||||||
offset2(surfaces_polygons, -distance_between_surfaces/2, +distance_between_surfaces/2),
|
offset2(surfaces_polygons, (float)-distance_between_surfaces/2, (float)+distance_between_surfaces/2),
|
||||||
true);
|
true);
|
||||||
Polygons to_subtract;
|
Polygons to_subtract;
|
||||||
to_subtract.reserve(collapsed.size() + number_polygons(surfaces));
|
to_subtract.reserve(collapsed.size() + number_polygons(surfaces));
|
||||||
@ -137,7 +137,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
|||||||
surfaces_append(
|
surfaces_append(
|
||||||
surfaces,
|
surfaces,
|
||||||
intersection_ex(
|
intersection_ex(
|
||||||
offset(collapsed, distance_between_surfaces),
|
offset(collapsed, (float)distance_between_surfaces),
|
||||||
to_subtract,
|
to_subtract,
|
||||||
true),
|
true),
|
||||||
stInternalSolid);
|
stInternalSolid);
|
||||||
@ -219,14 +219,14 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
|||||||
f->z = layerm.layer()->print_z;
|
f->z = layerm.layer()->print_z;
|
||||||
f->angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
|
f->angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
|
||||||
// Maximum length of the perimeter segment linking two infill lines.
|
// Maximum length of the perimeter segment linking two infill lines.
|
||||||
f->link_max_length = scale_(link_max_length);
|
f->link_max_length = (coord_t)scale_(link_max_length);
|
||||||
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
|
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
|
||||||
f->loop_clipping = scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER;
|
f->loop_clipping = coord_t(scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
|
||||||
// f->layer_height = h;
|
// f->layer_height = h;
|
||||||
|
|
||||||
// apply half spacing using this flow's own spacing and generate infill
|
// apply half spacing using this flow's own spacing and generate infill
|
||||||
FillParams params;
|
FillParams params;
|
||||||
params.density = 0.01 * density;
|
params.density = float(0.01 * density);
|
||||||
// params.dont_adjust = true;
|
// params.dont_adjust = true;
|
||||||
params.dont_adjust = false;
|
params.dont_adjust = false;
|
||||||
Polylines polylines = f->fill_surface(&surface, params);
|
Polylines polylines = f->fill_surface(&surface, params);
|
||||||
@ -240,7 +240,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
|||||||
// so we can safely ignore the slight variation that might have
|
// so we can safely ignore the slight variation that might have
|
||||||
// been applied to $f->flow_spacing
|
// been applied to $f->flow_spacing
|
||||||
} else {
|
} else {
|
||||||
flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, h, is_bridge || f->use_bridge_flow());
|
flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, (float)h, is_bridge || f->use_bridge_flow());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save into layer.
|
// Save into layer.
|
||||||
|
@ -2031,7 +2031,7 @@ namespace Slic3r {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
vertices_count += its.vertices.size();
|
vertices_count += (int)its.vertices.size();
|
||||||
|
|
||||||
const Transform3d& matrix = volume->get_matrix();
|
const Transform3d& matrix = volume->get_matrix();
|
||||||
|
|
||||||
@ -2061,7 +2061,7 @@ namespace Slic3r {
|
|||||||
|
|
||||||
// updates triangle offsets
|
// updates triangle offsets
|
||||||
volume_it->second.first_triangle_id = triangles_count;
|
volume_it->second.first_triangle_id = triangles_count;
|
||||||
triangles_count += its.indices.size();
|
triangles_count += (int)its.indices.size();
|
||||||
volume_it->second.last_triangle_id = triangles_count - 1;
|
volume_it->second.last_triangle_id = triangles_count - 1;
|
||||||
|
|
||||||
for (size_t i = 0; i < its.indices.size(); ++ i)
|
for (size_t i = 0; i < its.indices.size(); ++ i)
|
||||||
|
@ -192,7 +192,7 @@ struct AMFParserContext
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Version of the amf file
|
// Version of the amf file
|
||||||
unsigned int m_version;
|
unsigned int m_version;
|
||||||
// Current Expat XML parser instance.
|
// Current Expat XML parser instance.
|
||||||
XML_Parser m_parser;
|
XML_Parser m_parser;
|
||||||
// Model to receive objects extracted from an AMF file.
|
// Model to receive objects extracted from an AMF file.
|
||||||
@ -616,7 +616,7 @@ void AMFParserContext::endElement(const char * /* name */)
|
|||||||
if (end != nullptr)
|
if (end != nullptr)
|
||||||
*end = 0;
|
*end = 0;
|
||||||
|
|
||||||
point(coord_idx) = atof(p);
|
point(coord_idx) = float(atof(p));
|
||||||
if (++coord_idx == 5) {
|
if (++coord_idx == 5) {
|
||||||
m_object->sla_support_points.push_back(sla::SupportPoint(point));
|
m_object->sla_support_points.push_back(sla::SupportPoint(point));
|
||||||
coord_idx = 0;
|
coord_idx = 0;
|
||||||
@ -628,8 +628,8 @@ void AMFParserContext::endElement(const char * /* name */)
|
|||||||
m_object->sla_points_status = sla::PointsStatus::UserModified;
|
m_object->sla_points_status = sla::PointsStatus::UserModified;
|
||||||
}
|
}
|
||||||
else if (m_path.size() == 5 && m_path[1] == NODE_TYPE_OBJECT && m_path[3] == NODE_TYPE_RANGE &&
|
else if (m_path.size() == 5 && m_path[1] == NODE_TYPE_OBJECT && m_path[3] == NODE_TYPE_RANGE &&
|
||||||
m_object && strcmp(opt_key, "layer_height_ranges") == 0) {
|
m_object && strcmp(opt_key, "layer_height_range") == 0) {
|
||||||
// Parse object's layer_height_ranges, a semicolon separated doubles.
|
// Parse object's layer_height_range, a semicolon separated doubles.
|
||||||
char* p = const_cast<char*>(m_value[1].c_str());
|
char* p = const_cast<char*>(m_value[1].c_str());
|
||||||
char* end = strchr(p, ';');
|
char* end = strchr(p, ';');
|
||||||
*end = 0;
|
*end = 0;
|
||||||
@ -946,7 +946,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||||||
for (auto range : config_ranges) {
|
for (auto range : config_ranges) {
|
||||||
stream << " <range id=\"" << layer_counter << "\">\n";
|
stream << " <range id=\"" << layer_counter << "\">\n";
|
||||||
|
|
||||||
stream << " <metadata type=\"slic3r.layer_height_ranges\">";
|
stream << " <metadata type=\"slic3r.layer_height_range\">";
|
||||||
stream << range.first.first << ";" << range.first.second << "</metadata>\n";
|
stream << range.first.first << ";" << range.first.second << "</metadata>\n";
|
||||||
|
|
||||||
for (const std::string& key : range.second.keys())
|
for (const std::string& key : range.second.keys())
|
||||||
@ -994,7 +994,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||||||
stream << " </coordinates>\n";
|
stream << " </coordinates>\n";
|
||||||
stream << " </vertex>\n";
|
stream << " </vertex>\n";
|
||||||
}
|
}
|
||||||
num_vertices += its.vertices.size();
|
num_vertices += (int)its.vertices.size();
|
||||||
}
|
}
|
||||||
stream << " </vertices>\n";
|
stream << " </vertices>\n";
|
||||||
for (size_t i_volume = 0; i_volume < object->volumes.size(); ++i_volume) {
|
for (size_t i_volume = 0; i_volume < object->volumes.size(); ++i_volume) {
|
||||||
|
@ -593,7 +593,6 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
|
|||||||
this->config = rhs.config;
|
this->config = rhs.config;
|
||||||
this->sla_support_points = rhs.sla_support_points;
|
this->sla_support_points = rhs.sla_support_points;
|
||||||
this->sla_points_status = rhs.sla_points_status;
|
this->sla_points_status = rhs.sla_points_status;
|
||||||
this->layer_height_ranges = rhs.layer_height_ranges;
|
|
||||||
this->layer_config_ranges = rhs.layer_config_ranges; // #ys_FIXME_experiment
|
this->layer_config_ranges = rhs.layer_config_ranges; // #ys_FIXME_experiment
|
||||||
this->layer_height_profile = rhs.layer_height_profile;
|
this->layer_height_profile = rhs.layer_height_profile;
|
||||||
this->origin_translation = rhs.origin_translation;
|
this->origin_translation = rhs.origin_translation;
|
||||||
@ -630,7 +629,6 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
|
|||||||
this->config = std::move(rhs.config);
|
this->config = std::move(rhs.config);
|
||||||
this->sla_support_points = std::move(rhs.sla_support_points);
|
this->sla_support_points = std::move(rhs.sla_support_points);
|
||||||
this->sla_points_status = std::move(rhs.sla_points_status);
|
this->sla_points_status = std::move(rhs.sla_points_status);
|
||||||
this->layer_height_ranges = std::move(rhs.layer_height_ranges);
|
|
||||||
this->layer_config_ranges = std::move(rhs.layer_config_ranges); // #ys_FIXME_experiment
|
this->layer_config_ranges = std::move(rhs.layer_config_ranges); // #ys_FIXME_experiment
|
||||||
this->layer_height_profile = std::move(rhs.layer_height_profile);
|
this->layer_height_profile = std::move(rhs.layer_height_profile);
|
||||||
this->origin_translation = std::move(rhs.origin_translation);
|
this->origin_translation = std::move(rhs.origin_translation);
|
||||||
@ -1809,7 +1807,7 @@ bool model_volume_list_changed(const ModelObject &model_object_old, const ModelO
|
|||||||
if (!mv_old.get_matrix().isApprox(mv_new.get_matrix()))
|
if (!mv_old.get_matrix().isApprox(mv_new.get_matrix()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
++i_old;
|
++ i_old;
|
||||||
++ i_new;
|
++ i_new;
|
||||||
}
|
}
|
||||||
for (; i_old < model_object_old.volumes.size(); ++ i_old) {
|
for (; i_old < model_object_old.volumes.size(); ++ i_old) {
|
||||||
|
@ -179,10 +179,8 @@ public:
|
|||||||
ModelVolumePtrs volumes;
|
ModelVolumePtrs volumes;
|
||||||
// Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings.
|
// Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings.
|
||||||
DynamicPrintConfig config;
|
DynamicPrintConfig config;
|
||||||
// Variation of a layer thickness for spans of Z coordinates.
|
// Variation of a layer thickness for spans of Z coordinates + optional parameter overrides.
|
||||||
t_layer_height_ranges layer_height_ranges;
|
t_layer_config_ranges layer_config_ranges;
|
||||||
// Variation of a layer thickness for spans of Z coordinates.
|
|
||||||
t_layer_config_ranges layer_config_ranges;
|
|
||||||
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
|
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
|
||||||
// The pairs of <z, layer_height> are packed into a 1D array.
|
// The pairs of <z, layer_height> are packed into a 1D array.
|
||||||
std::vector<coordf_t> layer_height_profile;
|
std::vector<coordf_t> layer_height_profile;
|
||||||
|
@ -41,36 +41,6 @@ void Print::clear()
|
|||||||
m_model.clear_objects();
|
m_model.clear_objects();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only used by the Perl test cases.
|
|
||||||
void Print::reload_object(size_t /* idx */)
|
|
||||||
{
|
|
||||||
ModelObjectPtrs model_objects;
|
|
||||||
{
|
|
||||||
tbb::mutex::scoped_lock lock(this->state_mutex());
|
|
||||||
// The following call should stop background processing if it is running.
|
|
||||||
this->invalidate_all_steps();
|
|
||||||
/* TODO: this method should check whether the per-object config and per-material configs
|
|
||||||
have changed in such a way that regions need to be rearranged or we can just apply
|
|
||||||
the diff and invalidate something. Same logic as apply()
|
|
||||||
For now we just re-add all objects since we haven't implemented this incremental logic yet.
|
|
||||||
This should also check whether object volumes (parts) have changed. */
|
|
||||||
// collect all current model objects
|
|
||||||
model_objects.reserve(m_objects.size());
|
|
||||||
for (PrintObject *object : m_objects)
|
|
||||||
model_objects.push_back(object->model_object());
|
|
||||||
// remove our print objects
|
|
||||||
for (PrintObject *object : m_objects)
|
|
||||||
delete object;
|
|
||||||
m_objects.clear();
|
|
||||||
for (PrintRegion *region : m_regions)
|
|
||||||
delete region;
|
|
||||||
m_regions.clear();
|
|
||||||
}
|
|
||||||
// re-add model objects
|
|
||||||
for (ModelObject *mo : model_objects)
|
|
||||||
this->add_model_object(mo);
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintRegion* Print::add_region()
|
PrintRegion* Print::add_region()
|
||||||
{
|
{
|
||||||
m_regions.emplace_back(new PrintRegion(this));
|
m_regions.emplace_back(new PrintRegion(this));
|
||||||
@ -335,7 +305,7 @@ unsigned int Print::num_object_instances() const
|
|||||||
{
|
{
|
||||||
unsigned int instances = 0;
|
unsigned int instances = 0;
|
||||||
for (const PrintObject *print_object : m_objects)
|
for (const PrintObject *print_object : m_objects)
|
||||||
instances += print_object->copies().size();
|
instances += (unsigned int)print_object->copies().size();
|
||||||
return instances;
|
return instances;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,7 +330,7 @@ double Print::max_allowed_layer_height() const
|
|||||||
|
|
||||||
// Caller is responsible for supplying models whose objects don't collide
|
// Caller is responsible for supplying models whose objects don't collide
|
||||||
// and have explicit instance positions.
|
// and have explicit instance positions.
|
||||||
void Print::add_model_object(ModelObject* model_object, int idx)
|
void Print::add_model_object_perl_tests_only(ModelObject* model_object, int idx)
|
||||||
{
|
{
|
||||||
tbb::mutex::scoped_lock lock(this->state_mutex());
|
tbb::mutex::scoped_lock lock(this->state_mutex());
|
||||||
// Add a copy of this ModelObject to this Print.
|
// Add a copy of this ModelObject to this Print.
|
||||||
@ -389,26 +359,26 @@ void Print::add_model_object(ModelObject* model_object, int idx)
|
|||||||
object->set_trafo(trafo);
|
object->set_trafo(trafo);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t volume_id = 0;
|
int volume_id = 0;
|
||||||
for (const ModelVolume *volume : model_object->volumes) {
|
for (const ModelVolume *volume : model_object->volumes) {
|
||||||
if (! volume->is_model_part() && ! volume->is_modifier())
|
if (! volume->is_model_part() && ! volume->is_modifier())
|
||||||
continue;
|
continue;
|
||||||
// Get the config applied to this volume.
|
// Get the config applied to this volume.
|
||||||
PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, 99999);
|
PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, nullptr, *volume, 99999);
|
||||||
// Find an existing print region with the same config.
|
// Find an existing print region with the same config.
|
||||||
size_t region_id = size_t(-1);
|
int region_id = -1;
|
||||||
for (size_t i = 0; i < m_regions.size(); ++ i)
|
for (int i = 0; i < (int)m_regions.size(); ++ i)
|
||||||
if (config.equals(m_regions[i]->config())) {
|
if (config.equals(m_regions[i]->config())) {
|
||||||
region_id = i;
|
region_id = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// If no region exists with the same config, create a new one.
|
// If no region exists with the same config, create a new one.
|
||||||
if (region_id == size_t(-1)) {
|
if (region_id == -1) {
|
||||||
region_id = m_regions.size();
|
region_id = (int)m_regions.size();
|
||||||
this->add_region(config);
|
this->add_region(config);
|
||||||
}
|
}
|
||||||
// Assign volume to a region.
|
// Assign volume to a region.
|
||||||
object->add_region_volume(region_id, volume_id);
|
object->add_region_volume((unsigned int)region_id, volume_id, t_layer_height_range(0, DBL_MAX));
|
||||||
++ volume_id;
|
++ volume_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,18 +459,18 @@ bool Print::apply_config_perl_tests_only(DynamicPrintConfig config)
|
|||||||
bool this_region_config_set = false;
|
bool this_region_config_set = false;
|
||||||
for (PrintObject *object : m_objects) {
|
for (PrintObject *object : m_objects) {
|
||||||
if (region_id < object->region_volumes.size()) {
|
if (region_id < object->region_volumes.size()) {
|
||||||
for (int volume_id : object->region_volumes[region_id]) {
|
for (const std::pair<t_layer_height_range, int> &volume_and_range : object->region_volumes[region_id]) {
|
||||||
const ModelVolume &volume = *object->model_object()->volumes[volume_id];
|
const ModelVolume &volume = *object->model_object()->volumes[volume_and_range.second];
|
||||||
if (this_region_config_set) {
|
if (this_region_config_set) {
|
||||||
// If the new config for this volume differs from the other
|
// If the new config for this volume differs from the other
|
||||||
// volume configs currently associated to this region, it means
|
// volume configs currently associated to this region, it means
|
||||||
// the region subdivision does not make sense anymore.
|
// the region subdivision does not make sense anymore.
|
||||||
if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, volume, 99999))) {
|
if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, nullptr, volume, 99999))) {
|
||||||
rearrange_regions = true;
|
rearrange_regions = true;
|
||||||
goto exit_for_rearrange_regions;
|
goto exit_for_rearrange_regions;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, 99999);
|
this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, nullptr, volume, 99999);
|
||||||
this_region_config_set = true;
|
this_region_config_set = true;
|
||||||
}
|
}
|
||||||
for (const PrintRegionConfig &cfg : other_region_configs) {
|
for (const PrintRegionConfig &cfg : other_region_configs) {
|
||||||
@ -540,7 +510,7 @@ exit_for_rearrange_regions:
|
|||||||
model_objects.push_back(object->model_object());
|
model_objects.push_back(object->model_object());
|
||||||
this->clear();
|
this->clear();
|
||||||
for (ModelObject *mo : model_objects)
|
for (ModelObject *mo : model_objects)
|
||||||
this->add_model_object(mo);
|
this->add_model_object_perl_tests_only(mo);
|
||||||
invalidated = true;
|
invalidated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -620,6 +590,20 @@ static inline void model_volume_list_copy_configs(ModelObject &model_object_dst,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void layer_height_ranges_copy_configs(t_layer_config_ranges &lr_dst, const t_layer_config_ranges &lr_src)
|
||||||
|
{
|
||||||
|
assert(lr_dst.size() == lr_src.size());
|
||||||
|
auto it_src = lr_src.cbegin();
|
||||||
|
for (auto &kvp_dst : lr_dst) {
|
||||||
|
const auto &kvp_src = *it_src ++;
|
||||||
|
assert(std::abs(kvp_dst.first.first - kvp_src.first.first ) <= EPSILON);
|
||||||
|
assert(std::abs(kvp_dst.first.second - kvp_src.first.second) <= EPSILON);
|
||||||
|
// Layer heights are allowed do differ in case the layer height table is being overriden by the smooth profile.
|
||||||
|
// assert(std::abs(kvp_dst.second.option("layer_height")->getFloat() - kvp_src.second.option("layer_height")->getFloat()) <= EPSILON);
|
||||||
|
kvp_dst.second = kvp_src.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool transform3d_lower(const Transform3d &lhs, const Transform3d &rhs)
|
static inline bool transform3d_lower(const Transform3d &lhs, const Transform3d &rhs)
|
||||||
{
|
{
|
||||||
typedef Transform3d::Scalar T;
|
typedef Transform3d::Scalar T;
|
||||||
@ -674,6 +658,23 @@ static std::vector<PrintInstances> print_objects_from_model_object(const ModelOb
|
|||||||
return std::vector<PrintInstances>(trafos.begin(), trafos.end());
|
return std::vector<PrintInstances>(trafos.begin(), trafos.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compare just the layer ranges and their layer heights, not the associated configs.
|
||||||
|
// Ignore the layer heights if check_layer_heights is false.
|
||||||
|
bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_config_ranges &lr2, bool check_layer_height)
|
||||||
|
{
|
||||||
|
if (lr1.size() != lr2.size())
|
||||||
|
return false;
|
||||||
|
auto it2 = lr2.begin();
|
||||||
|
for (const auto &kvp1 : lr1) {
|
||||||
|
const auto &kvp2 = *it2 ++;
|
||||||
|
if (std::abs(kvp1.first.first - kvp2.first.first ) > EPSILON ||
|
||||||
|
std::abs(kvp1.first.second - kvp2.first.second) > EPSILON ||
|
||||||
|
(check_layer_height && std::abs(kvp1.second.option("layer_height")->getFloat() - kvp2.second.option("layer_height")->getFloat()) > EPSILON))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &config_in)
|
Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &config_in)
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
@ -724,6 +725,50 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||||||
// Handle changes to regions config defaults
|
// Handle changes to regions config defaults
|
||||||
m_default_region_config.apply_only(config, region_diff, true);
|
m_default_region_config.apply_only(config, region_diff, true);
|
||||||
|
|
||||||
|
class LayerRanges
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LayerRanges() {}
|
||||||
|
// Convert input config ranges into continuous non-overlapping sorted vector of intervals and their configs.
|
||||||
|
void assign(const t_layer_config_ranges &in) {
|
||||||
|
m_ranges.clear();
|
||||||
|
m_ranges.reserve(in.size());
|
||||||
|
// Input ranges are sorted lexicographically. First range trims the other ranges.
|
||||||
|
coordf_t last_z = 0;
|
||||||
|
for (const std::pair<const t_layer_height_range, DynamicPrintConfig> &range : in) {
|
||||||
|
// for (auto &range : in) {
|
||||||
|
if (range.first.second > last_z) {
|
||||||
|
coordf_t min_z = std::max(range.first.first, 0.);
|
||||||
|
if (min_z > last_z + EPSILON) {
|
||||||
|
m_ranges.emplace_back(t_layer_height_range(last_z, min_z), nullptr);
|
||||||
|
last_z = min_z;
|
||||||
|
}
|
||||||
|
if (range.first.second > last_z + EPSILON) {
|
||||||
|
const DynamicPrintConfig* cfg = &range.second;
|
||||||
|
m_ranges.emplace_back(t_layer_height_range(last_z, range.first.second), cfg);
|
||||||
|
last_z = range.first.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_ranges.empty())
|
||||||
|
m_ranges.emplace_back(t_layer_height_range(0, DBL_MAX), nullptr);
|
||||||
|
else if (m_ranges.back().second == nullptr)
|
||||||
|
m_ranges.back().first.second = DBL_MAX;
|
||||||
|
else
|
||||||
|
m_ranges.emplace_back(t_layer_height_range(m_ranges.back().first.second, DBL_MAX), nullptr);
|
||||||
|
}
|
||||||
|
const DynamicPrintConfig* config(const t_layer_height_range &range) const {
|
||||||
|
auto it = std::lower_bound(m_ranges.begin(), m_ranges.end(), std::make_pair< t_layer_height_range, const DynamicPrintConfig*>(t_layer_height_range(range.first - EPSILON, range.second - EPSILON), nullptr));
|
||||||
|
assert(it != m_ranges.end());
|
||||||
|
assert(it == m_ranges.end() || std::abs(it->first.first - range.first ) < EPSILON);
|
||||||
|
assert(it == m_ranges.end() || std::abs(it->first.second - range.second) < EPSILON);
|
||||||
|
return (it == m_ranges.end()) ? nullptr : it->second;
|
||||||
|
}
|
||||||
|
auto begin() const { return m_ranges.cbegin(); }
|
||||||
|
auto end() const { return m_ranges.cend(); }
|
||||||
|
private:
|
||||||
|
std::vector<std::pair<t_layer_height_range, const DynamicPrintConfig*>> m_ranges;
|
||||||
|
};
|
||||||
struct ModelObjectStatus {
|
struct ModelObjectStatus {
|
||||||
enum Status {
|
enum Status {
|
||||||
Unknown,
|
Unknown,
|
||||||
@ -733,8 +778,9 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||||||
Deleted,
|
Deleted,
|
||||||
};
|
};
|
||||||
ModelObjectStatus(ModelID id, Status status = Unknown) : id(id), status(status) {}
|
ModelObjectStatus(ModelID id, Status status = Unknown) : id(id), status(status) {}
|
||||||
ModelID id;
|
ModelID id;
|
||||||
Status status;
|
Status status;
|
||||||
|
LayerRanges layer_ranges;
|
||||||
// Search by id.
|
// Search by id.
|
||||||
bool operator<(const ModelObjectStatus &rhs) const { return id < rhs.id; }
|
bool operator<(const ModelObjectStatus &rhs) const { return id < rhs.id; }
|
||||||
};
|
};
|
||||||
@ -861,22 +907,23 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||||||
auto it_status = model_object_status.find(ModelObjectStatus(model_object.id()));
|
auto it_status = model_object_status.find(ModelObjectStatus(model_object.id()));
|
||||||
assert(it_status != model_object_status.end());
|
assert(it_status != model_object_status.end());
|
||||||
assert(it_status->status != ModelObjectStatus::Deleted);
|
assert(it_status->status != ModelObjectStatus::Deleted);
|
||||||
|
const ModelObject& model_object_new = *model.objects[idx_model_object];
|
||||||
|
const_cast<ModelObjectStatus&>(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges);
|
||||||
if (it_status->status == ModelObjectStatus::New)
|
if (it_status->status == ModelObjectStatus::New)
|
||||||
// PrintObject instances will be added in the next loop.
|
// PrintObject instances will be added in the next loop.
|
||||||
continue;
|
continue;
|
||||||
// Update the ModelObject instance, possibly invalidate the linked PrintObjects.
|
// Update the ModelObject instance, possibly invalidate the linked PrintObjects.
|
||||||
assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved);
|
assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved);
|
||||||
const ModelObject &model_object_new = *model.objects[idx_model_object];
|
|
||||||
// Check whether a model part volume was added or removed, their transformations or order changed.
|
// Check whether a model part volume was added or removed, their transformations or order changed.
|
||||||
|
// Only volume IDs, volume types and their order are checked, configuration and other parameters are NOT checked.
|
||||||
bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART);
|
bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART);
|
||||||
bool modifiers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::PARAMETER_MODIFIER);
|
bool modifiers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::PARAMETER_MODIFIER);
|
||||||
bool support_blockers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_BLOCKER);
|
bool support_blockers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_BLOCKER);
|
||||||
bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER);
|
bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER);
|
||||||
if (model_parts_differ || modifiers_differ ||
|
if (model_parts_differ || modifiers_differ ||
|
||||||
model_object.origin_translation != model_object_new.origin_translation ||
|
model_object.origin_translation != model_object_new.origin_translation ||
|
||||||
// model_object.layer_height_ranges != model_object_new.layer_height_ranges ||
|
model_object.layer_height_profile != model_object_new.layer_height_profile ||
|
||||||
model_object.layer_config_ranges != model_object_new.layer_config_ranges || // #ys_FIXME_experiment
|
! layer_height_ranges_equal(model_object.layer_config_ranges, model_object_new.layer_config_ranges, model_object_new.layer_height_profile.empty())) {
|
||||||
model_object.layer_height_profile != model_object_new.layer_height_profile) {
|
|
||||||
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
|
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
|
||||||
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
||||||
for (auto it = range.first; it != range.second; ++ it) {
|
for (auto it = range.first; it != range.second; ++ it) {
|
||||||
@ -916,7 +963,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||||||
//FIXME What to do with m_material_id?
|
//FIXME What to do with m_material_id?
|
||||||
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::MODEL_PART);
|
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::MODEL_PART);
|
||||||
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::PARAMETER_MODIFIER);
|
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::PARAMETER_MODIFIER);
|
||||||
// Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
|
layer_height_ranges_copy_configs(model_object.layer_config_ranges /* dst */, model_object_new.layer_config_ranges /* src */);
|
||||||
|
// Copy the ModelObject name, input_file and instances. The instances will be compared against PrintObject instances in the next step.
|
||||||
model_object.name = model_object_new.name;
|
model_object.name = model_object_new.name;
|
||||||
model_object.input_file = model_object_new.input_file;
|
model_object.input_file = model_object_new.input_file;
|
||||||
model_object.clear_instances();
|
model_object.clear_instances();
|
||||||
@ -1028,19 +1076,27 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||||||
PrintRegionConfig this_region_config;
|
PrintRegionConfig this_region_config;
|
||||||
bool this_region_config_set = false;
|
bool this_region_config_set = false;
|
||||||
for (PrintObject *print_object : m_objects) {
|
for (PrintObject *print_object : m_objects) {
|
||||||
|
const LayerRanges *layer_ranges;
|
||||||
|
{
|
||||||
|
auto it_status = model_object_status.find(ModelObjectStatus(print_object->model_object()->id()));
|
||||||
|
assert(it_status != model_object_status.end());
|
||||||
|
assert(it_status->status != ModelObjectStatus::Deleted);
|
||||||
|
layer_ranges = &it_status->layer_ranges;
|
||||||
|
}
|
||||||
if (region_id < print_object->region_volumes.size()) {
|
if (region_id < print_object->region_volumes.size()) {
|
||||||
for (int volume_id : print_object->region_volumes[region_id]) {
|
for (const std::pair<t_layer_height_range, int> &volume_and_range : print_object->region_volumes[region_id]) {
|
||||||
const ModelVolume &volume = *print_object->model_object()->volumes[volume_id];
|
const ModelVolume &volume = *print_object->model_object()->volumes[volume_and_range.second];
|
||||||
|
const DynamicPrintConfig *layer_range_config = layer_ranges->config(volume_and_range.first);
|
||||||
if (this_region_config_set) {
|
if (this_region_config_set) {
|
||||||
// If the new config for this volume differs from the other
|
// If the new config for this volume differs from the other
|
||||||
// volume configs currently associated to this region, it means
|
// volume configs currently associated to this region, it means
|
||||||
// the region subdivision does not make sense anymore.
|
// the region subdivision does not make sense anymore.
|
||||||
if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders)))
|
if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, layer_range_config, volume, num_extruders)))
|
||||||
// Regions were split. Reset this print_object.
|
// Regions were split. Reset this print_object.
|
||||||
goto print_object_end;
|
goto print_object_end;
|
||||||
} else {
|
} else {
|
||||||
this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders);
|
this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, layer_range_config, volume, num_extruders);
|
||||||
for (size_t i = 0; i < region_id; ++i) {
|
for (size_t i = 0; i < region_id; ++ i) {
|
||||||
const PrintRegion ®ion_other = *m_regions[i];
|
const PrintRegion ®ion_other = *m_regions[i];
|
||||||
if (region_other.m_refcnt != 0 && region_other.config().equals(this_region_config))
|
if (region_other.m_refcnt != 0 && region_other.config().equals(this_region_config))
|
||||||
// Regions were merged. Reset this print_object.
|
// Regions were merged. Reset this print_object.
|
||||||
@ -1055,7 +1111,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||||||
update_apply_status(print_object->invalidate_all_steps());
|
update_apply_status(print_object->invalidate_all_steps());
|
||||||
// Decrease the references to regions from this volume.
|
// Decrease the references to regions from this volume.
|
||||||
int ireg = 0;
|
int ireg = 0;
|
||||||
for (const std::vector<int> &volumes : print_object->region_volumes) {
|
for (const std::vector<std::pair<t_layer_height_range, int>> &volumes : print_object->region_volumes) {
|
||||||
if (! volumes.empty())
|
if (! volumes.empty())
|
||||||
-- m_regions[ireg]->m_refcnt;
|
-- m_regions[ireg]->m_refcnt;
|
||||||
++ ireg;
|
++ ireg;
|
||||||
@ -1077,52 +1133,65 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||||||
for (size_t idx_print_object = 0; idx_print_object < m_objects.size(); ++ idx_print_object) {
|
for (size_t idx_print_object = 0; idx_print_object < m_objects.size(); ++ idx_print_object) {
|
||||||
PrintObject &print_object0 = *m_objects[idx_print_object];
|
PrintObject &print_object0 = *m_objects[idx_print_object];
|
||||||
const ModelObject &model_object = *print_object0.model_object();
|
const ModelObject &model_object = *print_object0.model_object();
|
||||||
std::vector<int> map_volume_to_region(model_object.volumes.size(), -1);
|
const LayerRanges *layer_ranges;
|
||||||
|
{
|
||||||
|
auto it_status = model_object_status.find(ModelObjectStatus(model_object.id()));
|
||||||
|
assert(it_status != model_object_status.end());
|
||||||
|
assert(it_status->status != ModelObjectStatus::Deleted);
|
||||||
|
layer_ranges = &it_status->layer_ranges;
|
||||||
|
}
|
||||||
|
std::vector<int> regions_in_object;
|
||||||
|
regions_in_object.reserve(64);
|
||||||
for (size_t i = idx_print_object; i < m_objects.size() && m_objects[i]->model_object() == &model_object; ++ i) {
|
for (size_t i = idx_print_object; i < m_objects.size() && m_objects[i]->model_object() == &model_object; ++ i) {
|
||||||
PrintObject &print_object = *m_objects[i];
|
PrintObject &print_object = *m_objects[i];
|
||||||
bool fresh = print_object.region_volumes.empty();
|
bool fresh = print_object.region_volumes.empty();
|
||||||
unsigned int volume_id = 0;
|
unsigned int volume_id = 0;
|
||||||
|
unsigned int idx_region_in_object = 0;
|
||||||
for (const ModelVolume *volume : model_object.volumes) {
|
for (const ModelVolume *volume : model_object.volumes) {
|
||||||
if (! volume->is_model_part() && ! volume->is_modifier()) {
|
if (! volume->is_model_part() && ! volume->is_modifier()) {
|
||||||
++ volume_id;
|
++ volume_id;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int region_id = -1;
|
// Filter the layer ranges, so they do not overlap and they contain at least a single layer.
|
||||||
if (&print_object == &print_object0) {
|
// Now insert a volume with a layer range to its own region.
|
||||||
// Get the config applied to this volume.
|
for (auto it_range = layer_ranges->begin(); it_range != layer_ranges->end(); ++ it_range) {
|
||||||
PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, num_extruders);
|
int region_id = -1;
|
||||||
// Find an existing print region with the same config.
|
if (&print_object == &print_object0) {
|
||||||
int idx_empty_slot = -1;
|
// Get the config applied to this volume.
|
||||||
for (int i = 0; i < (int)m_regions.size(); ++ i) {
|
PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, it_range->second, *volume, num_extruders);
|
||||||
if (m_regions[i]->m_refcnt == 0) {
|
// Find an existing print region with the same config.
|
||||||
if (idx_empty_slot == -1)
|
int idx_empty_slot = -1;
|
||||||
idx_empty_slot = i;
|
for (int i = 0; i < (int)m_regions.size(); ++ i) {
|
||||||
} else if (config.equals(m_regions[i]->config())) {
|
if (m_regions[i]->m_refcnt == 0) {
|
||||||
region_id = i;
|
if (idx_empty_slot == -1)
|
||||||
break;
|
idx_empty_slot = i;
|
||||||
|
} else if (config.equals(m_regions[i]->config())) {
|
||||||
|
region_id = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If no region exists with the same config, create a new one.
|
||||||
|
if (region_id == -1) {
|
||||||
|
if (idx_empty_slot == -1) {
|
||||||
|
region_id = (int)m_regions.size();
|
||||||
|
this->add_region(config);
|
||||||
|
} else {
|
||||||
|
region_id = idx_empty_slot;
|
||||||
|
m_regions[region_id]->set_config(std::move(config));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
regions_in_object.emplace_back(region_id);
|
||||||
// If no region exists with the same config, create a new one.
|
} else
|
||||||
if (region_id == -1) {
|
region_id = regions_in_object[idx_region_in_object ++];
|
||||||
if (idx_empty_slot == -1) {
|
// Assign volume to a region.
|
||||||
region_id = (int)m_regions.size();
|
if (fresh) {
|
||||||
this->add_region(config);
|
if (region_id >= print_object.region_volumes.size() || print_object.region_volumes[region_id].empty())
|
||||||
} else {
|
++ m_regions[region_id]->m_refcnt;
|
||||||
region_id = idx_empty_slot;
|
print_object.add_region_volume(region_id, volume_id, it_range->first);
|
||||||
m_regions[region_id]->set_config(std::move(config));
|
}
|
||||||
}
|
}
|
||||||
}
|
++ volume_id;
|
||||||
map_volume_to_region[volume_id] = region_id;
|
}
|
||||||
} else
|
|
||||||
region_id = map_volume_to_region[volume_id];
|
|
||||||
// Assign volume to a region.
|
|
||||||
if (fresh) {
|
|
||||||
if (region_id >= print_object.region_volumes.size() || print_object.region_volumes[region_id].empty())
|
|
||||||
++ m_regions[region_id]->m_refcnt;
|
|
||||||
print_object.add_region_volume(region_id, volume_id);
|
|
||||||
}
|
|
||||||
++ volume_id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1176,7 +1245,7 @@ std::string Print::validate() const
|
|||||||
Polygon convex_hull0 = offset(
|
Polygon convex_hull0 = offset(
|
||||||
print_object->model_object()->convex_hull_2d(
|
print_object->model_object()->convex_hull_2d(
|
||||||
Geometry::assemble_transform(Vec3d::Zero(), rotation, model_instance0->get_scaling_factor(), model_instance0->get_mirror())),
|
Geometry::assemble_transform(Vec3d::Zero(), rotation, model_instance0->get_scaling_factor(), model_instance0->get_mirror())),
|
||||||
scale_(m_config.extruder_clearance_radius.value) / 2., jtRound, scale_(0.1)).front();
|
float(scale_(0.5 * m_config.extruder_clearance_radius.value)), jtRound, float(scale_(0.1))).front();
|
||||||
// Now we check that no instance of convex_hull intersects any of the previously checked object instances.
|
// Now we check that no instance of convex_hull intersects any of the previously checked object instances.
|
||||||
for (const Point © : print_object->m_copies) {
|
for (const Point © : print_object->m_copies) {
|
||||||
Polygon convex_hull = convex_hull0;
|
Polygon convex_hull = convex_hull0;
|
||||||
@ -1228,7 +1297,6 @@ std::string Print::validate() const
|
|||||||
bool has_custom_layering = false;
|
bool has_custom_layering = false;
|
||||||
std::vector<std::vector<coordf_t>> layer_height_profiles;
|
std::vector<std::vector<coordf_t>> layer_height_profiles;
|
||||||
for (const PrintObject *object : m_objects) {
|
for (const PrintObject *object : m_objects) {
|
||||||
// has_custom_layering = ! object->model_object()->layer_height_ranges.empty() || ! object->model_object()->layer_height_profile.empty();
|
|
||||||
has_custom_layering = ! object->model_object()->layer_config_ranges.empty() || ! object->model_object()->layer_height_profile.empty(); // #ys_FIXME_experiment
|
has_custom_layering = ! object->model_object()->layer_config_ranges.empty() || ! object->model_object()->layer_height_profile.empty(); // #ys_FIXME_experiment
|
||||||
if (has_custom_layering) {
|
if (has_custom_layering) {
|
||||||
layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>());
|
layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>());
|
||||||
@ -1437,9 +1505,9 @@ Flow Print::brim_flow() const
|
|||||||
generation as well. */
|
generation as well. */
|
||||||
return Flow::new_from_config_width(
|
return Flow::new_from_config_width(
|
||||||
frPerimeter,
|
frPerimeter,
|
||||||
width,
|
width,
|
||||||
m_config.nozzle_diameter.get_at(m_regions.front()->config().perimeter_extruder-1),
|
(float)m_config.nozzle_diameter.get_at(m_regions.front()->config().perimeter_extruder-1),
|
||||||
this->skirt_first_layer_height(),
|
(float)this->skirt_first_layer_height(),
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1459,9 +1527,9 @@ Flow Print::skirt_flow() const
|
|||||||
generation as well. */
|
generation as well. */
|
||||||
return Flow::new_from_config_width(
|
return Flow::new_from_config_width(
|
||||||
frPerimeter,
|
frPerimeter,
|
||||||
width,
|
width,
|
||||||
m_config.nozzle_diameter.get_at(m_objects.front()->config().support_material_extruder-1),
|
(float)m_config.nozzle_diameter.get_at(m_objects.front()->config().support_material_extruder-1),
|
||||||
this->skirt_first_layer_height(),
|
(float)this->skirt_first_layer_height(),
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1636,20 +1704,20 @@ void Print::_make_skirt()
|
|||||||
|
|
||||||
// Initial offset of the brim inner edge from the object (possible with a support & raft).
|
// Initial offset of the brim inner edge from the object (possible with a support & raft).
|
||||||
// The skirt will touch the brim if the brim is extruded.
|
// The skirt will touch the brim if the brim is extruded.
|
||||||
Flow brim_flow = this->brim_flow();
|
Flow brim_flow = this->brim_flow();
|
||||||
double actual_brim_width = brim_flow.spacing() * floor(m_config.brim_width.value / brim_flow.spacing());
|
double actual_brim_width = brim_flow.spacing() * floor(m_config.brim_width.value / brim_flow.spacing());
|
||||||
coord_t distance = scale_(std::max(m_config.skirt_distance.value, actual_brim_width) - spacing/2.);
|
auto distance = float(scale_(std::max(m_config.skirt_distance.value, actual_brim_width) - spacing/2.));
|
||||||
// Draw outlines from outside to inside.
|
// Draw outlines from outside to inside.
|
||||||
// Loop while we have less skirts than required or any extruder hasn't reached the min length if any.
|
// Loop while we have less skirts than required or any extruder hasn't reached the min length if any.
|
||||||
std::vector<coordf_t> extruded_length(extruders.size(), 0.);
|
std::vector<coordf_t> extruded_length(extruders.size(), 0.);
|
||||||
for (int i = n_skirts, extruder_idx = 0; i > 0; -- i) {
|
for (int i = n_skirts, extruder_idx = 0; i > 0; -- i) {
|
||||||
this->throw_if_canceled();
|
this->throw_if_canceled();
|
||||||
// Offset the skirt outside.
|
// Offset the skirt outside.
|
||||||
distance += coord_t(scale_(spacing));
|
distance += float(scale_(spacing));
|
||||||
// Generate the skirt centerline.
|
// Generate the skirt centerline.
|
||||||
Polygon loop;
|
Polygon loop;
|
||||||
{
|
{
|
||||||
Polygons loops = offset(convex_hull, distance, ClipperLib::jtRound, scale_(0.1));
|
Polygons loops = offset(convex_hull, distance, ClipperLib::jtRound, float(scale_(0.1)));
|
||||||
Geometry::simplify_polygons(loops, scale_(0.05), &loops);
|
Geometry::simplify_polygons(loops, scale_(0.05), &loops);
|
||||||
if (loops.empty())
|
if (loops.empty())
|
||||||
break;
|
break;
|
||||||
@ -1660,9 +1728,9 @@ void Print::_make_skirt()
|
|||||||
eloop.paths.emplace_back(ExtrusionPath(
|
eloop.paths.emplace_back(ExtrusionPath(
|
||||||
ExtrusionPath(
|
ExtrusionPath(
|
||||||
erSkirt,
|
erSkirt,
|
||||||
mm3_per_mm, // this will be overridden at G-code export time
|
(float)mm3_per_mm, // this will be overridden at G-code export time
|
||||||
flow.width,
|
flow.width,
|
||||||
first_layer_height // this will be overridden at G-code export time
|
(float)first_layer_height // this will be overridden at G-code export time
|
||||||
)));
|
)));
|
||||||
eloop.paths.back().polyline = loop.split_at_first_point();
|
eloop.paths.back().polyline = loop.split_at_first_point();
|
||||||
m_skirt.append(eloop);
|
m_skirt.append(eloop);
|
||||||
@ -1788,7 +1856,7 @@ void Print::_make_wipe_tower()
|
|||||||
// Insert the new support layer.
|
// Insert the new support layer.
|
||||||
double height = lt.print_z - m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z;
|
double height = lt.print_z - m_wipe_tower_data.tool_ordering.layer_tools()[i-1].print_z;
|
||||||
//FIXME the support layer ID is set to -1, as Vojtech hopes it is not being used anyway.
|
//FIXME the support layer ID is set to -1, as Vojtech hopes it is not being used anyway.
|
||||||
it_layer = m_objects.front()->insert_support_layer(it_layer, size_t(-1), height, lt.print_z, lt.print_z - 0.5 * height);
|
it_layer = m_objects.front()->insert_support_layer(it_layer, -1, height, lt.print_z, lt.print_z - 0.5 * height);
|
||||||
++ it_layer;
|
++ it_layer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1815,19 +1883,19 @@ void Print::_make_wipe_tower()
|
|||||||
WipeTowerPrusaMM::parse_material(m_config.filament_type.get_at(i).c_str()),
|
WipeTowerPrusaMM::parse_material(m_config.filament_type.get_at(i).c_str()),
|
||||||
m_config.temperature.get_at(i),
|
m_config.temperature.get_at(i),
|
||||||
m_config.first_layer_temperature.get_at(i),
|
m_config.first_layer_temperature.get_at(i),
|
||||||
m_config.filament_loading_speed.get_at(i),
|
(float)m_config.filament_loading_speed.get_at(i),
|
||||||
m_config.filament_loading_speed_start.get_at(i),
|
(float)m_config.filament_loading_speed_start.get_at(i),
|
||||||
m_config.filament_unloading_speed.get_at(i),
|
(float)m_config.filament_unloading_speed.get_at(i),
|
||||||
m_config.filament_unloading_speed_start.get_at(i),
|
(float)m_config.filament_unloading_speed_start.get_at(i),
|
||||||
m_config.filament_toolchange_delay.get_at(i),
|
(float)m_config.filament_toolchange_delay.get_at(i),
|
||||||
m_config.filament_cooling_moves.get_at(i),
|
m_config.filament_cooling_moves.get_at(i),
|
||||||
m_config.filament_cooling_initial_speed.get_at(i),
|
(float)m_config.filament_cooling_initial_speed.get_at(i),
|
||||||
m_config.filament_cooling_final_speed.get_at(i),
|
(float)m_config.filament_cooling_final_speed.get_at(i),
|
||||||
m_config.filament_ramming_parameters.get_at(i),
|
m_config.filament_ramming_parameters.get_at(i),
|
||||||
m_config.nozzle_diameter.get_at(i));
|
(float)m_config.nozzle_diameter.get_at(i));
|
||||||
|
|
||||||
m_wipe_tower_data.priming = Slic3r::make_unique<WipeTower::ToolChangeResult>(
|
m_wipe_tower_data.priming = Slic3r::make_unique<WipeTower::ToolChangeResult>(
|
||||||
wipe_tower.prime(this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false));
|
wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false));
|
||||||
|
|
||||||
// Lets go through the wipe tower layers and determine pairs of extruder changes for each
|
// Lets go through the wipe tower layers and determine pairs of extruder changes for each
|
||||||
// to pass to wipe_tower (so that it can use it for planning the layout of the tower)
|
// to pass to wipe_tower (so that it can use it for planning the layout of the tower)
|
||||||
@ -1836,21 +1904,21 @@ void Print::_make_wipe_tower()
|
|||||||
for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers
|
for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers
|
||||||
if (!layer_tools.has_wipe_tower) continue;
|
if (!layer_tools.has_wipe_tower) continue;
|
||||||
bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front();
|
bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front();
|
||||||
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id,false);
|
wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id, false);
|
||||||
for (const auto extruder_id : layer_tools.extruders) {
|
for (const auto extruder_id : layer_tools.extruders) {
|
||||||
if ((first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) {
|
if ((first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) {
|
||||||
float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange
|
float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange
|
||||||
// Not all of that can be used for infill purging:
|
// Not all of that can be used for infill purging:
|
||||||
volume_to_wipe -= m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id);
|
volume_to_wipe -= (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id);
|
||||||
|
|
||||||
// try to assign some infills/objects for the wiping:
|
// try to assign some infills/objects for the wiping:
|
||||||
volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, volume_to_wipe);
|
volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, volume_to_wipe);
|
||||||
|
|
||||||
// add back the minimal amount toforce on the wipe tower:
|
// add back the minimal amount toforce on the wipe tower:
|
||||||
volume_to_wipe += m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id);
|
volume_to_wipe += (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id);
|
||||||
|
|
||||||
// request a toolchange at the wipe tower with at least volume_to_wipe purging amount
|
// request a toolchange at the wipe tower with at least volume_to_wipe purging amount
|
||||||
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id,
|
wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id,
|
||||||
first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back(), volume_to_wipe);
|
first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back(), volume_to_wipe);
|
||||||
current_extruder_id = extruder_id;
|
current_extruder_id = extruder_id;
|
||||||
}
|
}
|
||||||
|
@ -80,8 +80,8 @@ private: // Prevents erroneous use by other classes.
|
|||||||
typedef PrintObjectBaseWithState<Print, PrintObjectStep, posCount> Inherited;
|
typedef PrintObjectBaseWithState<Print, PrintObjectStep, posCount> Inherited;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// vector of (vectors of volume ids), indexed by region_id
|
// vector of (layer height ranges and vectors of volume ids), indexed by region_id
|
||||||
std::vector<std::vector<int>> region_volumes;
|
std::vector<std::vector<std::pair<t_layer_height_range, int>>> region_volumes;
|
||||||
|
|
||||||
// this is set to true when LayerRegion->slices is split in top/internal/bottom
|
// this is set to true when LayerRegion->slices is split in top/internal/bottom
|
||||||
// so that next call to make_perimeters() performs a union() before computing loops
|
// so that next call to make_perimeters() performs a union() before computing loops
|
||||||
@ -99,10 +99,10 @@ public:
|
|||||||
BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); }
|
BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); }
|
||||||
|
|
||||||
// adds region_id, too, if necessary
|
// adds region_id, too, if necessary
|
||||||
void add_region_volume(unsigned int region_id, int volume_id) {
|
void add_region_volume(unsigned int region_id, int volume_id, const t_layer_height_range &layer_range) {
|
||||||
if (region_id >= region_volumes.size())
|
if (region_id >= region_volumes.size())
|
||||||
region_volumes.resize(region_id + 1);
|
region_volumes.resize(region_id + 1);
|
||||||
region_volumes[region_id].emplace_back(volume_id);
|
region_volumes[region_id].emplace_back(layer_range, volume_id);
|
||||||
}
|
}
|
||||||
// This is the *total* layer count (including support layers)
|
// This is the *total* layer count (including support layers)
|
||||||
// this value is not supposed to be compared with Layer::id
|
// this value is not supposed to be compared with Layer::id
|
||||||
@ -141,8 +141,9 @@ public:
|
|||||||
void slice();
|
void slice();
|
||||||
|
|
||||||
// Helpers to slice support enforcer / blocker meshes by the support generator.
|
// Helpers to slice support enforcer / blocker meshes by the support generator.
|
||||||
std::vector<ExPolygons> slice_support_enforcers() const;
|
std::vector<ExPolygons> slice_support_volumes(const ModelVolumeType &model_volume_type) const;
|
||||||
std::vector<ExPolygons> slice_support_blockers() const;
|
std::vector<ExPolygons> slice_support_blockers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_BLOCKER); }
|
||||||
|
std::vector<ExPolygons> slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// to be called from Print only.
|
// to be called from Print only.
|
||||||
@ -165,7 +166,7 @@ protected:
|
|||||||
void update_slicing_parameters();
|
void update_slicing_parameters();
|
||||||
|
|
||||||
static PrintObjectConfig object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders);
|
static PrintObjectConfig object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders);
|
||||||
static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders);
|
static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const DynamicPrintConfig *layer_range_config, const ModelVolume &volume, size_t num_extruders);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void make_perimeters();
|
void make_perimeters();
|
||||||
@ -201,9 +202,11 @@ private:
|
|||||||
LayerPtrs m_layers;
|
LayerPtrs m_layers;
|
||||||
SupportLayerPtrs m_support_layers;
|
SupportLayerPtrs m_support_layers;
|
||||||
|
|
||||||
std::vector<ExPolygons> _slice_region(size_t region_id, const std::vector<float> &z, bool modifier);
|
std::vector<ExPolygons> slice_region(size_t region_id, const std::vector<float> &z) const;
|
||||||
std::vector<ExPolygons> _slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const;
|
std::vector<ExPolygons> slice_modifiers(size_t region_id, const std::vector<float> &z) const;
|
||||||
std::vector<ExPolygons> _slice_volume(const std::vector<float> &z, const ModelVolume &volume) const;
|
std::vector<ExPolygons> slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const;
|
||||||
|
std::vector<ExPolygons> slice_volume(const std::vector<float> &z, const ModelVolume &volume) const;
|
||||||
|
std::vector<ExPolygons> slice_volume(const std::vector<float> &z, const std::vector<t_layer_height_range> &ranges, const ModelVolume &volume) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WipeTowerData
|
struct WipeTowerData
|
||||||
@ -292,8 +295,7 @@ public:
|
|||||||
ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override;
|
ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override;
|
||||||
|
|
||||||
// The following three methods are used by the Perl tests only. Get rid of them!
|
// The following three methods are used by the Perl tests only. Get rid of them!
|
||||||
void reload_object(size_t idx);
|
void add_model_object_perl_tests_only(ModelObject* model_object, int idx = -1);
|
||||||
void add_model_object(ModelObject* model_object, int idx = -1);
|
|
||||||
bool apply_config_perl_tests_only(DynamicPrintConfig config);
|
bool apply_config_perl_tests_only(DynamicPrintConfig config);
|
||||||
|
|
||||||
void process() override;
|
void process() override;
|
||||||
|
@ -49,7 +49,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_insta
|
|||||||
{
|
{
|
||||||
// Translate meshes so that our toolpath generation algorithms work with smaller
|
// Translate meshes so that our toolpath generation algorithms work with smaller
|
||||||
// XY coordinates; this translation is an optimization and not strictly required.
|
// XY coordinates; this translation is an optimization and not strictly required.
|
||||||
// A cloned mesh will be aligned to 0 before slicing in _slice_region() since we
|
// A cloned mesh will be aligned to 0 before slicing in slice_region() since we
|
||||||
// don't assume it's already aligned and we don't alter the original position in model.
|
// don't assume it's already aligned and we don't alter the original position in model.
|
||||||
// We store the XY translation so that we can place copies correctly in the output G-code
|
// We store the XY translation so that we can place copies correctly in the output G-code
|
||||||
// (copies are expressed in G-code coordinates and this translation is not publicly exposed).
|
// (copies are expressed in G-code coordinates and this translation is not publicly exposed).
|
||||||
@ -590,7 +590,12 @@ bool PrintObject::invalidate_step(PrintObjectStep step)
|
|||||||
|
|
||||||
bool PrintObject::invalidate_all_steps()
|
bool PrintObject::invalidate_all_steps()
|
||||||
{
|
{
|
||||||
return Inherited::invalidate_all_steps() | m_print->invalidate_all_steps();
|
// First call the "invalidate" functions, which may cancel background processing.
|
||||||
|
bool result = Inherited::invalidate_all_steps() | m_print->invalidate_all_steps();
|
||||||
|
// Then reset some of the depending values.
|
||||||
|
this->m_slicing_params.valid = false;
|
||||||
|
this->region_volumes.clear();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PrintObject::has_support_material() const
|
bool PrintObject::has_support_material() const
|
||||||
@ -1354,10 +1359,12 @@ PrintObjectConfig PrintObject::object_config_from_model_object(const PrintObject
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintRegionConfig PrintObject::region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders)
|
PrintRegionConfig PrintObject::region_config_from_model_volume(const PrintRegionConfig &default_region_config, const DynamicPrintConfig *layer_range_config, const ModelVolume &volume, size_t num_extruders)
|
||||||
{
|
{
|
||||||
PrintRegionConfig config = default_region_config;
|
PrintRegionConfig config = default_region_config;
|
||||||
normalize_and_apply_config(config, volume.get_object()->config);
|
normalize_and_apply_config(config, volume.get_object()->config);
|
||||||
|
if (layer_range_config != nullptr)
|
||||||
|
normalize_and_apply_config(config, *layer_range_config);
|
||||||
normalize_and_apply_config(config, volume.config);
|
normalize_and_apply_config(config, volume.config);
|
||||||
if (! volume.material_id().empty())
|
if (! volume.material_id().empty())
|
||||||
normalize_and_apply_config(config, volume.material()->config);
|
normalize_and_apply_config(config, volume.material()->config);
|
||||||
@ -1375,28 +1382,37 @@ void PrintObject::update_slicing_parameters()
|
|||||||
this->print()->config(), m_config, unscale<double>(this->size(2)), this->object_extruders());
|
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, float object_max_z)
|
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full_config, const ModelObject& model_object, float object_max_z)
|
||||||
{
|
{
|
||||||
PrintConfig print_config;
|
PrintConfig print_config;
|
||||||
PrintObjectConfig object_config;
|
PrintObjectConfig object_config;
|
||||||
PrintRegionConfig default_region_config;
|
PrintRegionConfig default_region_config;
|
||||||
print_config .apply(full_config, true);
|
print_config.apply(full_config, true);
|
||||||
object_config.apply(full_config, true);
|
object_config.apply(full_config, true);
|
||||||
default_region_config.apply(full_config, true);
|
default_region_config.apply(full_config, true);
|
||||||
size_t num_extruders = print_config.nozzle_diameter.size();
|
size_t num_extruders = print_config.nozzle_diameter.size();
|
||||||
object_config = object_config_from_model_object(object_config, model_object, num_extruders);
|
object_config = object_config_from_model_object(object_config, model_object, num_extruders);
|
||||||
|
|
||||||
std::vector<unsigned int> object_extruders;
|
std::vector<unsigned int> object_extruders;
|
||||||
for (const ModelVolume *model_volume : model_object.volumes)
|
for (const ModelVolume* model_volume : model_object.volumes)
|
||||||
if (model_volume->is_model_part())
|
if (model_volume->is_model_part()) {
|
||||||
PrintRegion::collect_object_printing_extruders(
|
PrintRegion::collect_object_printing_extruders(
|
||||||
print_config,
|
print_config,
|
||||||
region_config_from_model_volume(default_region_config, *model_volume, num_extruders),
|
region_config_from_model_volume(default_region_config, nullptr, *model_volume, num_extruders),
|
||||||
object_extruders);
|
object_extruders);
|
||||||
|
for (const std::pair<const t_layer_height_range, DynamicPrintConfig> &range_and_config : model_object.layer_config_ranges)
|
||||||
|
if (range_and_config.second.has("perimeter_extruder") ||
|
||||||
|
range_and_config.second.has("infill_extruder") ||
|
||||||
|
range_and_config.second.has("solid_infill_extruder"))
|
||||||
|
PrintRegion::collect_object_printing_extruders(
|
||||||
|
print_config,
|
||||||
|
region_config_from_model_volume(default_region_config, &range_and_config.second, *model_volume, num_extruders),
|
||||||
|
object_extruders);
|
||||||
|
}
|
||||||
sort_remove_duplicates(object_extruders);
|
sort_remove_duplicates(object_extruders);
|
||||||
|
|
||||||
if (object_max_z <= 0.f)
|
if (object_max_z <= 0.f)
|
||||||
object_max_z = model_object.raw_bounding_box().size().z();
|
object_max_z = (float)model_object.raw_bounding_box().size().z();
|
||||||
return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders);
|
return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1430,13 +1446,12 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
|
|||||||
layer_height_profile.clear();
|
layer_height_profile.clear();
|
||||||
|
|
||||||
if (layer_height_profile.empty()) {
|
if (layer_height_profile.empty()) {
|
||||||
if (0)
|
if (0)
|
||||||
// if (this->layer_height_profile.empty())
|
// if (this->layer_height_profile.empty())
|
||||||
layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_height_ranges, model_object.volumes);
|
layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);
|
||||||
else
|
else
|
||||||
// layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_height_ranges);
|
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); // #ys_FIXME_experiment
|
||||||
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); // #ys_FIXME_experiment
|
updated = true;
|
||||||
updated = true;
|
|
||||||
}
|
}
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
@ -1490,22 +1505,28 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Count model parts and modifier meshes, check whether the model parts are of the same region.
|
// Count model parts and modifier meshes, check whether the model parts are of the same region.
|
||||||
int single_volume_region = -2; // not set yet
|
int all_volumes_single_region = -2; // not set yet
|
||||||
|
bool has_z_ranges = false;
|
||||||
size_t num_volumes = 0;
|
size_t num_volumes = 0;
|
||||||
size_t num_modifiers = 0;
|
size_t num_modifiers = 0;
|
||||||
std::vector<int> map_volume_to_region(this->model_object()->volumes.size());
|
|
||||||
for (int region_id = 0; region_id < (int)this->region_volumes.size(); ++ region_id) {
|
for (int region_id = 0; region_id < (int)this->region_volumes.size(); ++ region_id) {
|
||||||
for (int volume_id : this->region_volumes[region_id]) {
|
int last_volume_id = -1;
|
||||||
|
for (const std::pair<t_layer_height_range, int> &volume_and_range : this->region_volumes[region_id]) {
|
||||||
|
const int volume_id = volume_and_range.second;
|
||||||
const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
|
const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
|
||||||
if (model_volume->is_model_part()) {
|
if (model_volume->is_model_part()) {
|
||||||
map_volume_to_region[volume_id] = region_id;
|
if (last_volume_id == volume_id) {
|
||||||
if (single_volume_region == -2)
|
has_z_ranges = true;
|
||||||
// first model volume met
|
} else {
|
||||||
single_volume_region = region_id;
|
last_volume_id = volume_id;
|
||||||
else if (single_volume_region != region_id)
|
if (all_volumes_single_region == -2)
|
||||||
// multiple volumes met and they are not equal
|
// first model volume met
|
||||||
single_volume_region = -1;
|
all_volumes_single_region = region_id;
|
||||||
++ num_volumes;
|
else if (all_volumes_single_region != region_id)
|
||||||
|
// multiple volumes met and they are not equal
|
||||||
|
all_volumes_single_region = -1;
|
||||||
|
++ num_volumes;
|
||||||
|
}
|
||||||
} else if (model_volume->is_modifier())
|
} else if (model_volume->is_modifier())
|
||||||
++ num_modifiers;
|
++ num_modifiers;
|
||||||
}
|
}
|
||||||
@ -1515,13 +1536,13 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
|||||||
// Slice all non-modifier volumes.
|
// Slice all non-modifier volumes.
|
||||||
bool clipped = false;
|
bool clipped = false;
|
||||||
bool upscaled = false;
|
bool upscaled = false;
|
||||||
if (! m_config.clip_multipart_objects.value || single_volume_region >= 0) {
|
if (! has_z_ranges && (! m_config.clip_multipart_objects.value || all_volumes_single_region >= 0)) {
|
||||||
// Cheap path: Slice regions without mutual clipping.
|
// Cheap path: Slice regions without mutual clipping.
|
||||||
// The cheap path is possible if no clipping is allowed or if slicing volumes of just a single region.
|
// The cheap path is possible if no clipping is allowed or if slicing volumes of just a single region.
|
||||||
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id;
|
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id;
|
||||||
// slicing in parallel
|
// slicing in parallel
|
||||||
std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(region_id, slice_zs, false);
|
std::vector<ExPolygons> expolygons_by_layer = this->slice_region(region_id, slice_zs);
|
||||||
m_print->throw_if_canceled();
|
m_print->throw_if_canceled();
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " start";
|
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " start";
|
||||||
for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id)
|
for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id)
|
||||||
@ -1542,15 +1563,29 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
|||||||
};
|
};
|
||||||
std::vector<SlicedVolume> sliced_volumes;
|
std::vector<SlicedVolume> sliced_volumes;
|
||||||
sliced_volumes.reserve(num_volumes);
|
sliced_volumes.reserve(num_volumes);
|
||||||
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id)
|
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
||||||
for (int volume_id : this->region_volumes[region_id]) {
|
const std::vector<std::pair<t_layer_height_range, int>> &volumes_and_ranges = this->region_volumes[region_id];
|
||||||
|
for (size_t i = 0; i < volumes_and_ranges.size(); ) {
|
||||||
|
int volume_id = volumes_and_ranges[i].second;
|
||||||
const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
|
const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
|
||||||
if (model_volume->is_model_part()) {
|
if (model_volume->is_model_part()) {
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - volume " << volume_id;
|
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - volume " << volume_id;
|
||||||
|
// Find the ranges of this volume. Ranges in volumes_and_ranges must not overlap for a single volume.
|
||||||
|
std::vector<t_layer_height_range> ranges;
|
||||||
|
ranges.emplace_back(volumes_and_ranges[i].first);
|
||||||
|
size_t j = i + 1;
|
||||||
|
for (; j < volumes_and_ranges.size() && volume_id == volumes_and_ranges[j].second; ++ j)
|
||||||
|
if (! ranges.empty() && std::abs(ranges.back().second - volumes_and_ranges[j].first.first) < EPSILON)
|
||||||
|
ranges.back().second = volumes_and_ranges[j].first.second;
|
||||||
|
else
|
||||||
|
ranges.emplace_back(volumes_and_ranges[j].first);
|
||||||
// slicing in parallel
|
// slicing in parallel
|
||||||
sliced_volumes.emplace_back(volume_id, map_volume_to_region[volume_id], this->_slice_volume(slice_zs, *model_volume));
|
sliced_volumes.emplace_back(volume_id, (int)region_id, this->slice_volume(slice_zs, ranges, *model_volume));
|
||||||
}
|
i = j;
|
||||||
|
} else
|
||||||
|
++ i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Second clip the volumes in the order they are presented at the user interface.
|
// Second clip the volumes in the order they are presented at the user interface.
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - parallel clipping - start";
|
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - parallel clipping - start";
|
||||||
tbb::parallel_for(
|
tbb::parallel_for(
|
||||||
@ -1604,7 +1639,7 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
|||||||
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - region " << region_id;
|
BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - region " << region_id;
|
||||||
// slicing in parallel
|
// slicing in parallel
|
||||||
std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(region_id, slice_zs, true);
|
std::vector<ExPolygons> expolygons_by_layer = this->slice_modifiers(region_id, slice_zs);
|
||||||
m_print->throw_if_canceled();
|
m_print->throw_if_canceled();
|
||||||
if (expolygons_by_layer.empty())
|
if (expolygons_by_layer.empty())
|
||||||
continue;
|
continue;
|
||||||
@ -1620,7 +1655,7 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
|||||||
Layer *layer = m_layers[layer_id];
|
Layer *layer = m_layers[layer_id];
|
||||||
LayerRegion *layerm = layer->m_regions[region_id];
|
LayerRegion *layerm = layer->m_regions[region_id];
|
||||||
LayerRegion *other_layerm = layer->m_regions[other_region_id];
|
LayerRegion *other_layerm = layer->m_regions[other_region_id];
|
||||||
if (layerm == nullptr || other_layerm == nullptr)
|
if (layerm == nullptr || other_layerm == nullptr || other_layerm->slices.empty() || expolygons_by_layer[layer_id].empty())
|
||||||
continue;
|
continue;
|
||||||
Polygons other_slices = to_polygons(other_layerm->slices);
|
Polygons other_slices = to_polygons(other_layerm->slices);
|
||||||
ExPolygons my_parts = intersection_ex(other_slices, to_polygons(expolygons_by_layer[layer_id]));
|
ExPolygons my_parts = intersection_ex(other_slices, to_polygons(expolygons_by_layer[layer_id]));
|
||||||
@ -1753,46 +1788,127 @@ end:
|
|||||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - end";
|
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - end";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ExPolygons> PrintObject::_slice_region(size_t region_id, const std::vector<float> &z, bool modifier)
|
// To be used only if there are no layer span specific configurations applied, which would lead to z ranges being generated for this region.
|
||||||
|
std::vector<ExPolygons> PrintObject::slice_region(size_t region_id, const std::vector<float> &z) const
|
||||||
{
|
{
|
||||||
std::vector<const ModelVolume*> volumes;
|
std::vector<const ModelVolume*> volumes;
|
||||||
if (region_id < this->region_volumes.size()) {
|
if (region_id < this->region_volumes.size()) {
|
||||||
for (int volume_id : this->region_volumes[region_id]) {
|
for (const std::pair<t_layer_height_range, int> &volume_and_range : this->region_volumes[region_id]) {
|
||||||
const ModelVolume *volume = this->model_object()->volumes[volume_id];
|
const ModelVolume *volume = this->model_object()->volumes[volume_and_range.second];
|
||||||
if (modifier ? volume->is_modifier() : volume->is_model_part())
|
if (volume->is_model_part())
|
||||||
volumes.emplace_back(volume);
|
volumes.emplace_back(volume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this->_slice_volumes(z, volumes);
|
return this->slice_volumes(z, volumes);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ExPolygons> PrintObject::slice_support_enforcers() const
|
// Z ranges are not applicable to modifier meshes, therefore a sinle volume will be found in volume_and_range at most once.
|
||||||
|
std::vector<ExPolygons> PrintObject::slice_modifiers(size_t region_id, const std::vector<float> &slice_zs) const
|
||||||
|
{
|
||||||
|
std::vector<ExPolygons> out;
|
||||||
|
if (region_id < this->region_volumes.size())
|
||||||
|
{
|
||||||
|
std::vector<std::vector<t_layer_height_range>> volume_ranges;
|
||||||
|
const std::vector<std::pair<t_layer_height_range, int>> &volumes_and_ranges = this->region_volumes[region_id];
|
||||||
|
volume_ranges.reserve(volumes_and_ranges.size());
|
||||||
|
for (size_t i = 0; i < volumes_and_ranges.size(); ) {
|
||||||
|
int volume_id = volumes_and_ranges[i].second;
|
||||||
|
const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
|
||||||
|
if (model_volume->is_modifier()) {
|
||||||
|
std::vector<t_layer_height_range> ranges;
|
||||||
|
ranges.emplace_back(volumes_and_ranges[i].first);
|
||||||
|
size_t j = i + 1;
|
||||||
|
for (; j < volumes_and_ranges.size() && volume_id == volumes_and_ranges[j].second; ++ j) {
|
||||||
|
if (! ranges.empty() && std::abs(ranges.back().second - volumes_and_ranges[j].first.first) < EPSILON)
|
||||||
|
ranges.back().second = volumes_and_ranges[j].first.second;
|
||||||
|
else
|
||||||
|
ranges.emplace_back(volumes_and_ranges[j].first);
|
||||||
|
}
|
||||||
|
volume_ranges.emplace_back(std::move(ranges));
|
||||||
|
i = j;
|
||||||
|
} else
|
||||||
|
++ i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! volume_ranges.empty())
|
||||||
|
{
|
||||||
|
bool equal_ranges = true;
|
||||||
|
for (size_t i = 1; i < volume_ranges.size(); ++ i) {
|
||||||
|
assert(! volume_ranges[i].empty());
|
||||||
|
if (volume_ranges.front() != volume_ranges[i]) {
|
||||||
|
equal_ranges = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (equal_ranges && volume_ranges.front().size() == 1 && volume_ranges.front().front() == t_layer_height_range(0, DBL_MAX)) {
|
||||||
|
// No modifier in this region was split to layer spans.
|
||||||
|
std::vector<const ModelVolume*> volumes;
|
||||||
|
for (const std::pair<t_layer_height_range, int> &volume_and_range : this->region_volumes[region_id]) {
|
||||||
|
const ModelVolume *volume = this->model_object()->volumes[volume_and_range.second];
|
||||||
|
if (volume->is_modifier())
|
||||||
|
volumes.emplace_back(volume);
|
||||||
|
}
|
||||||
|
out = this->slice_volumes(slice_zs, volumes);
|
||||||
|
} else {
|
||||||
|
// Some modifier in this region was split to layer spans.
|
||||||
|
std::vector<char> merge;
|
||||||
|
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
||||||
|
const std::vector<std::pair<t_layer_height_range, int>> &volumes_and_ranges = this->region_volumes[region_id];
|
||||||
|
for (size_t i = 0; i < volumes_and_ranges.size(); ) {
|
||||||
|
int volume_id = volumes_and_ranges[i].second;
|
||||||
|
const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
|
||||||
|
if (model_volume->is_modifier()) {
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "Slicing modifiers - volume " << volume_id;
|
||||||
|
// Find the ranges of this volume. Ranges in volumes_and_ranges must not overlap for a single volume.
|
||||||
|
std::vector<t_layer_height_range> ranges;
|
||||||
|
ranges.emplace_back(volumes_and_ranges[i].first);
|
||||||
|
size_t j = i + 1;
|
||||||
|
for (; j < volumes_and_ranges.size() && volume_id == volumes_and_ranges[j].second; ++ j)
|
||||||
|
ranges.emplace_back(volumes_and_ranges[j].first);
|
||||||
|
// slicing in parallel
|
||||||
|
std::vector<ExPolygons> this_slices = this->slice_volume(slice_zs, ranges, *model_volume);
|
||||||
|
if (out.empty()) {
|
||||||
|
out = std::move(this_slices);
|
||||||
|
merge.assign(out.size(), false);
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < out.size(); ++ i)
|
||||||
|
if (! this_slices[i].empty())
|
||||||
|
if (! out[i].empty()) {
|
||||||
|
append(out[i], this_slices[i]);
|
||||||
|
merge[i] = true;
|
||||||
|
} else
|
||||||
|
out[i] = std::move(this_slices[i]);
|
||||||
|
}
|
||||||
|
i = j;
|
||||||
|
} else
|
||||||
|
++ i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < merge.size(); ++ i)
|
||||||
|
if (merge[i])
|
||||||
|
out[i] = union_ex(out[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ExPolygons> PrintObject::slice_support_volumes(const ModelVolumeType &model_volume_type) const
|
||||||
{
|
{
|
||||||
std::vector<const ModelVolume*> volumes;
|
std::vector<const ModelVolume*> volumes;
|
||||||
for (const ModelVolume *volume : this->model_object()->volumes)
|
for (const ModelVolume *volume : this->model_object()->volumes)
|
||||||
if (volume->is_support_enforcer())
|
if (volume->type() == model_volume_type)
|
||||||
volumes.emplace_back(volume);
|
volumes.emplace_back(volume);
|
||||||
std::vector<float> zs;
|
std::vector<float> zs;
|
||||||
zs.reserve(this->layers().size());
|
zs.reserve(this->layers().size());
|
||||||
for (const Layer *l : this->layers())
|
for (const Layer *l : this->layers())
|
||||||
zs.emplace_back((float)l->slice_z);
|
zs.emplace_back((float)l->slice_z);
|
||||||
return this->_slice_volumes(zs, volumes);
|
return this->slice_volumes(zs, volumes);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ExPolygons> PrintObject::slice_support_blockers() const
|
std::vector<ExPolygons> PrintObject::slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const
|
||||||
{
|
|
||||||
std::vector<const ModelVolume*> volumes;
|
|
||||||
for (const ModelVolume *volume : this->model_object()->volumes)
|
|
||||||
if (volume->is_support_blocker())
|
|
||||||
volumes.emplace_back(volume);
|
|
||||||
std::vector<float> zs;
|
|
||||||
zs.reserve(this->layers().size());
|
|
||||||
for (const Layer *l : this->layers())
|
|
||||||
zs.emplace_back((float)l->slice_z);
|
|
||||||
return this->_slice_volumes(zs, volumes);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const
|
|
||||||
{
|
{
|
||||||
std::vector<ExPolygons> layers;
|
std::vector<ExPolygons> layers;
|
||||||
if (! volumes.empty()) {
|
if (! volumes.empty()) {
|
||||||
@ -1829,34 +1945,71 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
|
|||||||
return layers;
|
return layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z, const ModelVolume &volume) const
|
std::vector<ExPolygons> PrintObject::slice_volume(const std::vector<float> &z, const ModelVolume &volume) const
|
||||||
{
|
{
|
||||||
std::vector<ExPolygons> layers;
|
std::vector<ExPolygons> layers;
|
||||||
// Compose mesh.
|
if (! z.empty()) {
|
||||||
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
|
// Compose mesh.
|
||||||
TriangleMesh mesh(volume.mesh());
|
//FIXME better to split the mesh into separate shells, perform slicing over each shell separately and then to use a Boolean operation to merge them.
|
||||||
mesh.transform(volume.get_matrix(), true);
|
TriangleMesh mesh(volume.mesh());
|
||||||
if (mesh.repaired) {
|
mesh.transform(volume.get_matrix(), true);
|
||||||
//FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it.
|
if (mesh.repaired) {
|
||||||
stl_check_facets_exact(&mesh.stl);
|
//FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it.
|
||||||
|
stl_check_facets_exact(&mesh.stl);
|
||||||
|
}
|
||||||
|
if (mesh.stl.stats.number_of_facets > 0) {
|
||||||
|
mesh.transform(m_trafo, true);
|
||||||
|
// apply XY shift
|
||||||
|
mesh.translate(- unscale<float>(m_copies_shift(0)), - unscale<float>(m_copies_shift(1)), 0);
|
||||||
|
// perform actual slicing
|
||||||
|
TriangleMeshSlicer mslicer;
|
||||||
|
const Print *print = this->print();
|
||||||
|
auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
|
||||||
|
// TriangleMeshSlicer needs the shared vertices.
|
||||||
|
mesh.require_shared_vertices();
|
||||||
|
mslicer.init(&mesh, callback);
|
||||||
|
mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
|
||||||
|
m_print->throw_if_canceled();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (mesh.stl.stats.number_of_facets > 0) {
|
|
||||||
mesh.transform(m_trafo, true);
|
|
||||||
// apply XY shift
|
|
||||||
mesh.translate(- unscale<float>(m_copies_shift(0)), - unscale<float>(m_copies_shift(1)), 0);
|
|
||||||
// perform actual slicing
|
|
||||||
TriangleMeshSlicer mslicer;
|
|
||||||
const Print *print = this->print();
|
|
||||||
auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
|
|
||||||
// TriangleMeshSlicer needs the shared vertices.
|
|
||||||
mesh.require_shared_vertices();
|
|
||||||
mslicer.init(&mesh, callback);
|
|
||||||
mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
|
|
||||||
m_print->throw_if_canceled();
|
|
||||||
}
|
|
||||||
return layers;
|
return layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter the zs not inside the ranges. The ranges are closed at the botton and open at the top, they are sorted lexicographically and non overlapping.
|
||||||
|
std::vector<ExPolygons> PrintObject::slice_volume(const std::vector<float> &z, const std::vector<t_layer_height_range> &ranges, const ModelVolume &volume) const
|
||||||
|
{
|
||||||
|
std::vector<ExPolygons> out;
|
||||||
|
if (! z.empty() && ! ranges.empty()) {
|
||||||
|
if (ranges.size() == 1 && z.front() >= ranges.front().first && z.back() < ranges.front().second) {
|
||||||
|
// All layers fit into a single range.
|
||||||
|
out = this->slice_volume(z, volume);
|
||||||
|
} else {
|
||||||
|
std::vector<float> z_filtered;
|
||||||
|
std::vector<std::pair<size_t, size_t>> n_filtered;
|
||||||
|
z_filtered.reserve(z.size());
|
||||||
|
n_filtered.reserve(2 * ranges.size());
|
||||||
|
size_t i = 0;
|
||||||
|
for (const t_layer_height_range &range : ranges) {
|
||||||
|
for (; i < z.size() && z[i] < range.first; ++ i) ;
|
||||||
|
size_t first = i;
|
||||||
|
for (; i < z.size() && z[i] < range.second; ++ i)
|
||||||
|
z_filtered.emplace_back(z[i]);
|
||||||
|
if (i > first)
|
||||||
|
n_filtered.emplace_back(std::make_pair(first, i));
|
||||||
|
}
|
||||||
|
if (! n_filtered.empty()) {
|
||||||
|
std::vector<ExPolygons> layers = this->slice_volume(z_filtered, volume);
|
||||||
|
out.assign(z.size(), ExPolygons());
|
||||||
|
i = 0;
|
||||||
|
for (const std::pair<size_t, size_t> &span : n_filtered)
|
||||||
|
for (size_t j = span.first; j < span.second; ++ j)
|
||||||
|
out[j] = std::move(layers[i ++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
std::string PrintObject::_fix_slicing_errors()
|
std::string PrintObject::_fix_slicing_errors()
|
||||||
{
|
{
|
||||||
// Collect layers with slicing errors.
|
// Collect layers with slicing errors.
|
||||||
@ -2120,7 +2273,7 @@ void PrintObject::clip_fill_surfaces()
|
|||||||
//Should the pw not be half of the current value?
|
//Should the pw not be half of the current value?
|
||||||
float pw = FLT_MAX;
|
float pw = FLT_MAX;
|
||||||
for (const LayerRegion *layerm : layer->m_regions)
|
for (const LayerRegion *layerm : layer->m_regions)
|
||||||
pw = std::min<float>(pw, layerm->flow(frPerimeter).scaled_width());
|
pw = std::min(pw, (float)layerm->flow(frPerimeter).scaled_width());
|
||||||
// Append such thick perimeters to the areas that need support
|
// Append such thick perimeters to the areas that need support
|
||||||
polygons_append(overhangs, offset2(perimeters, -pw, +pw));
|
polygons_append(overhangs, offset2(perimeters, -pw, +pw));
|
||||||
}
|
}
|
||||||
|
@ -153,29 +153,33 @@ SlicingParameters SlicingParameters::create_from_config(
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert layer_height_ranges to layer_height_profile. Both are referenced to z=0, meaning the raft layers are not accounted for
|
std::vector<std::pair<t_layer_height_range, coordf_t>> layer_height_ranges(const t_layer_config_ranges &config_ranges)
|
||||||
|
{
|
||||||
|
std::vector<std::pair<t_layer_height_range, coordf_t>> out;
|
||||||
|
out.reserve(config_ranges.size());
|
||||||
|
for (const auto &kvp : config_ranges)
|
||||||
|
out.emplace_back(kvp.first, kvp.second.option("layer_height")->getFloat());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert layer_config_ranges to layer_height_profile. Both are referenced to z=0, meaning the raft layers are not accounted for
|
||||||
// in the height profile and the printed object may be lifted by the raft thickness at the time of the G-code generation.
|
// in the height profile and the printed object may be lifted by the raft thickness at the time of the G-code generation.
|
||||||
std::vector<coordf_t> layer_height_profile_from_ranges(
|
std::vector<coordf_t> layer_height_profile_from_ranges(
|
||||||
const SlicingParameters &slicing_params,
|
const SlicingParameters &slicing_params,
|
||||||
// const t_layer_height_ranges &layer_height_ranges)
|
|
||||||
const t_layer_config_ranges &layer_config_ranges) // #ys_FIXME_experiment
|
const t_layer_config_ranges &layer_config_ranges) // #ys_FIXME_experiment
|
||||||
{
|
{
|
||||||
// 1) If there are any height ranges, trim one by the other to make them non-overlapping. Insert the 1st layer if fixed.
|
// 1) If there are any height ranges, trim one by the other to make them non-overlapping. Insert the 1st layer if fixed.
|
||||||
std::vector<std::pair<t_layer_height_range,coordf_t>> ranges_non_overlapping;
|
std::vector<std::pair<t_layer_height_range,coordf_t>> ranges_non_overlapping;
|
||||||
// ranges_non_overlapping.reserve(layer_height_ranges.size() * 4);
|
|
||||||
ranges_non_overlapping.reserve(layer_config_ranges.size() * 4); // #ys_FIXME_experiment
|
ranges_non_overlapping.reserve(layer_config_ranges.size() * 4); // #ys_FIXME_experiment
|
||||||
if (slicing_params.first_object_layer_height_fixed())
|
if (slicing_params.first_object_layer_height_fixed())
|
||||||
ranges_non_overlapping.push_back(std::pair<t_layer_height_range,coordf_t>(
|
ranges_non_overlapping.push_back(std::pair<t_layer_height_range,coordf_t>(
|
||||||
t_layer_height_range(0., slicing_params.first_object_layer_height),
|
t_layer_height_range(0., slicing_params.first_object_layer_height),
|
||||||
slicing_params.first_object_layer_height));
|
slicing_params.first_object_layer_height));
|
||||||
// The height ranges are sorted lexicographically by low / high layer boundaries.
|
// The height ranges are sorted lexicographically by low / high layer boundaries.
|
||||||
// for (t_layer_height_ranges::const_iterator it_range = layer_height_ranges.begin(); it_range != layer_height_ranges.end(); ++ it_range) {
|
for (t_layer_config_ranges::const_iterator it_range = layer_config_ranges.begin(); it_range != layer_config_ranges.end(); ++ it_range) {
|
||||||
for (t_layer_config_ranges::const_iterator it_range = layer_config_ranges.begin();
|
|
||||||
it_range != layer_config_ranges.end(); ++ it_range) { // #ys_FIXME_experiment
|
|
||||||
coordf_t lo = it_range->first.first;
|
coordf_t lo = it_range->first.first;
|
||||||
coordf_t hi = std::min(it_range->first.second, slicing_params.object_print_z_height());
|
coordf_t hi = std::min(it_range->first.second, slicing_params.object_print_z_height());
|
||||||
// coordf_t height = it_range->second;
|
coordf_t height = it_range->second.option("layer_height")->getFloat();
|
||||||
coordf_t height = it_range->second.option("layer_height")->getFloat(); // #ys_FIXME_experiment
|
|
||||||
if (! ranges_non_overlapping.empty())
|
if (! ranges_non_overlapping.empty())
|
||||||
// Trim current low with the last high.
|
// Trim current low with the last high.
|
||||||
lo = std::max(lo, ranges_non_overlapping.back().first.second);
|
lo = std::max(lo, ranges_non_overlapping.back().first.second);
|
||||||
@ -224,7 +228,7 @@ std::vector<coordf_t> layer_height_profile_from_ranges(
|
|||||||
// Fill layer_height_profile by heights ensuring a prescribed maximum cusp height.
|
// Fill layer_height_profile by heights ensuring a prescribed maximum cusp height.
|
||||||
std::vector<coordf_t> layer_height_profile_adaptive(
|
std::vector<coordf_t> layer_height_profile_adaptive(
|
||||||
const SlicingParameters &slicing_params,
|
const SlicingParameters &slicing_params,
|
||||||
const t_layer_height_ranges &layer_height_ranges,
|
const t_layer_config_ranges & /* layer_config_ranges */,
|
||||||
const ModelVolumePtrs &volumes)
|
const ModelVolumePtrs &volumes)
|
||||||
{
|
{
|
||||||
// 1) Initialize the SlicingAdaptive class with the object meshes.
|
// 1) Initialize the SlicingAdaptive class with the object meshes.
|
||||||
|
@ -130,17 +130,17 @@ inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef std::pair<coordf_t,coordf_t> t_layer_height_range;
|
typedef std::pair<coordf_t,coordf_t> t_layer_height_range;
|
||||||
typedef std::map<t_layer_height_range,coordf_t> t_layer_height_ranges;
|
|
||||||
typedef std::map<t_layer_height_range, DynamicPrintConfig> t_layer_config_ranges;
|
typedef std::map<t_layer_height_range, DynamicPrintConfig> t_layer_config_ranges;
|
||||||
|
|
||||||
|
extern std::vector<std::pair<t_layer_height_range, coordf_t>> layer_height_ranges(const t_layer_config_ranges &config_ranges);
|
||||||
|
|
||||||
extern std::vector<coordf_t> layer_height_profile_from_ranges(
|
extern std::vector<coordf_t> layer_height_profile_from_ranges(
|
||||||
const SlicingParameters &slicing_params,
|
const SlicingParameters &slicing_params,
|
||||||
// const t_layer_height_ranges &layer_height_ranges);
|
|
||||||
const t_layer_config_ranges &layer_config_ranges);
|
const t_layer_config_ranges &layer_config_ranges);
|
||||||
|
|
||||||
extern std::vector<coordf_t> layer_height_profile_adaptive(
|
extern std::vector<coordf_t> layer_height_profile_adaptive(
|
||||||
const SlicingParameters &slicing_params,
|
const SlicingParameters &slicing_params,
|
||||||
const t_layer_height_ranges &layer_height_ranges,
|
const t_layer_config_ranges &layer_config_ranges,
|
||||||
const ModelVolumePtrs &volumes);
|
const ModelVolumePtrs &volumes);
|
||||||
|
|
||||||
|
|
||||||
|
@ -829,7 +829,7 @@ namespace SupportMaterialInternal {
|
|||||||
assert(expansion_scaled >= 0.f);
|
assert(expansion_scaled >= 0.f);
|
||||||
for (const ExtrusionPath &ep : loop.paths)
|
for (const ExtrusionPath &ep : loop.paths)
|
||||||
if (ep.role() == erOverhangPerimeter && ! ep.polyline.empty()) {
|
if (ep.role() == erOverhangPerimeter && ! ep.polyline.empty()) {
|
||||||
float exp = 0.5f * scale_(ep.width) + expansion_scaled;
|
float exp = 0.5f * (float)scale_(ep.width) + expansion_scaled;
|
||||||
if (ep.is_closed()) {
|
if (ep.is_closed()) {
|
||||||
if (ep.size() >= 3) {
|
if (ep.size() >= 3) {
|
||||||
// This is a complete loop.
|
// This is a complete loop.
|
||||||
@ -2214,7 +2214,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
|
|||||||
// Expand the bases of the support columns in the 1st layer.
|
// Expand the bases of the support columns in the 1st layer.
|
||||||
columns_base->polygons = diff(
|
columns_base->polygons = diff(
|
||||||
offset(columns_base->polygons, inflate_factor_1st_layer),
|
offset(columns_base->polygons, inflate_factor_1st_layer),
|
||||||
offset(m_object->layers().front()->slices.expolygons, scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
offset(m_object->layers().front()->slices.expolygons, (float)scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||||
if (contacts != nullptr)
|
if (contacts != nullptr)
|
||||||
columns_base->polygons = diff(columns_base->polygons, interface_polygons);
|
columns_base->polygons = diff(columns_base->polygons, interface_polygons);
|
||||||
}
|
}
|
||||||
@ -3226,7 +3226,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
|
|||||||
// TODO: use brim ordering algorithm
|
// TODO: use brim ordering algorithm
|
||||||
Polygons to_infill_polygons = to_polygons(to_infill);
|
Polygons to_infill_polygons = to_polygons(to_infill);
|
||||||
// TODO: use offset2_ex()
|
// TODO: use offset2_ex()
|
||||||
to_infill = offset_ex(to_infill, - 0.4 * float(flow.scaled_spacing()));
|
to_infill = offset_ex(to_infill, - 0.4f * float(flow.scaled_spacing()));
|
||||||
extrusion_entities_append_paths(
|
extrusion_entities_append_paths(
|
||||||
base_layer.extrusions,
|
base_layer.extrusions,
|
||||||
to_polylines(std::move(to_infill_polygons)),
|
to_polylines(std::move(to_infill_polygons)),
|
||||||
|
@ -600,12 +600,12 @@ void Bed3D::render_prusa_shader(bool transparent) const
|
|||||||
if (position_id != -1)
|
if (position_id != -1)
|
||||||
{
|
{
|
||||||
glsafe(::glEnableVertexAttribArray(position_id));
|
glsafe(::glEnableVertexAttribArray(position_id));
|
||||||
glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset()));
|
glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_position_offset()));
|
||||||
}
|
}
|
||||||
if (tex_coords_id != -1)
|
if (tex_coords_id != -1)
|
||||||
{
|
{
|
||||||
glsafe(::glEnableVertexAttribArray(tex_coords_id));
|
glsafe(::glEnableVertexAttribArray(tex_coords_id));
|
||||||
glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset()));
|
glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_tex_coords_offset()));
|
||||||
}
|
}
|
||||||
|
|
||||||
glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count()));
|
glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count()));
|
||||||
|
@ -1922,9 +1922,6 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
|
|||||||
}
|
}
|
||||||
|
|
||||||
object->ensure_on_bed();
|
object->ensure_on_bed();
|
||||||
|
|
||||||
// print.auto_assign_extruders(object);
|
|
||||||
// print.add_model_object(object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AUTOPLACEMENT_ON_LOAD
|
#ifdef AUTOPLACEMENT_ON_LOAD
|
||||||
|
@ -1129,7 +1129,6 @@ void Selection::copy_to_clipboard()
|
|||||||
dst_object->config = src_object->config;
|
dst_object->config = src_object->config;
|
||||||
dst_object->sla_support_points = src_object->sla_support_points;
|
dst_object->sla_support_points = src_object->sla_support_points;
|
||||||
dst_object->sla_points_status = src_object->sla_points_status;
|
dst_object->sla_points_status = src_object->sla_points_status;
|
||||||
// dst_object->layer_height_ranges = src_object->layer_height_ranges;
|
|
||||||
dst_object->layer_config_ranges = src_object->layer_config_ranges; // #ys_FIXME_experiment
|
dst_object->layer_config_ranges = src_object->layer_config_ranges; // #ys_FIXME_experiment
|
||||||
dst_object->layer_height_profile = src_object->layer_height_profile;
|
dst_object->layer_height_profile = src_object->layer_height_profile;
|
||||||
dst_object->origin_translation = src_object->origin_translation;
|
dst_object->origin_translation = src_object->origin_translation;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use Test::More tests => 6;
|
use Test::More tests => 2;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
@ -31,6 +31,8 @@ use Slic3r::Test;
|
|||||||
ok abs(unscale($center->[Y]) - $print_center->[Y]) < 0.005, 'print is centered around print_center (Y)';
|
ok abs(unscale($center->[Y]) - $print_center->[Y]) < 0.005, 'print is centered around print_center (Y)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# This is really testing a path, which is no more used by the slicer, just by the test cases.
|
||||||
|
if (0)
|
||||||
{
|
{
|
||||||
# this represents the aggregate config from presets
|
# this represents the aggregate config from presets
|
||||||
my $config = Slic3r::Config::new_from_defaults;
|
my $config = Slic3r::Config::new_from_defaults;
|
||||||
@ -40,7 +42,7 @@ use Slic3r::Test;
|
|||||||
|
|
||||||
# user sets a per-region option
|
# user sets a per-region option
|
||||||
$print->print->objects->[0]->model_object->config->set('fill_density', 100);
|
$print->print->objects->[0]->model_object->config->set('fill_density', 100);
|
||||||
$print->print->reload_object(0);
|
# $print->print->reload_object(0);
|
||||||
is $print->print->regions->[0]->config->fill_density, 100, 'region config inherits model object config';
|
is $print->print->regions->[0]->config->fill_density, 100, 'region config inherits model object config';
|
||||||
|
|
||||||
# user exports G-code, thus the default config is reapplied
|
# user exports G-code, thus the default config is reapplied
|
||||||
@ -51,7 +53,7 @@ use Slic3r::Test;
|
|||||||
# user assigns object extruders
|
# user assigns object extruders
|
||||||
$print->print->objects->[0]->model_object->config->set('extruder', 3);
|
$print->print->objects->[0]->model_object->config->set('extruder', 3);
|
||||||
$print->print->objects->[0]->model_object->config->set('perimeter_extruder', 2);
|
$print->print->objects->[0]->model_object->config->set('perimeter_extruder', 2);
|
||||||
$print->print->reload_object(0);
|
# $print->print->reload_object(0);
|
||||||
|
|
||||||
is $print->print->regions->[0]->config->infill_extruder, 3, 'extruder setting is correctly expanded';
|
is $print->print->regions->[0]->config->infill_extruder, 3, 'extruder setting is correctly expanded';
|
||||||
is $print->print->regions->[0]->config->perimeter_extruder, 2, 'extruder setting does not override explicitely specified extruders';
|
is $print->print->regions->[0]->config->perimeter_extruder, 2, 'extruder setting does not override explicitely specified extruders';
|
||||||
|
@ -100,7 +100,6 @@ _constant()
|
|||||||
%code%{ RETVAL = const_cast<PrintObjectPtrs*>(&THIS->objects()); %};
|
%code%{ RETVAL = const_cast<PrintObjectPtrs*>(&THIS->objects()); %};
|
||||||
Ref<PrintObject> get_object(int idx)
|
Ref<PrintObject> get_object(int idx)
|
||||||
%code%{ RETVAL = THIS->objects()[idx]; %};
|
%code%{ RETVAL = THIS->objects()[idx]; %};
|
||||||
void reload_object(int idx);
|
|
||||||
size_t object_count()
|
size_t object_count()
|
||||||
%code%{ RETVAL = THIS->objects().size(); %};
|
%code%{ RETVAL = THIS->objects().size(); %};
|
||||||
|
|
||||||
@ -141,7 +140,6 @@ _constant()
|
|||||||
}
|
}
|
||||||
%};
|
%};
|
||||||
|
|
||||||
void add_model_object(ModelObject* model_object, int idx = -1);
|
|
||||||
bool apply_config_perl_tests_only(DynamicPrintConfig* config)
|
bool apply_config_perl_tests_only(DynamicPrintConfig* config)
|
||||||
%code%{ RETVAL = THIS->apply_config_perl_tests_only(*config); %};
|
%code%{ RETVAL = THIS->apply_config_perl_tests_only(*config); %};
|
||||||
bool has_infinite_skirt();
|
bool has_infinite_skirt();
|
||||||
|
Loading…
Reference in New Issue
Block a user