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 collapsed = diff(
|
||||
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);
|
||||
Polygons to_subtract;
|
||||
to_subtract.reserve(collapsed.size() + number_polygons(surfaces));
|
||||
@ -137,7 +137,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
||||
surfaces_append(
|
||||
surfaces,
|
||||
intersection_ex(
|
||||
offset(collapsed, distance_between_surfaces),
|
||||
offset(collapsed, (float)distance_between_surfaces),
|
||||
to_subtract,
|
||||
true),
|
||||
stInternalSolid);
|
||||
@ -219,14 +219,14 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
||||
f->z = layerm.layer()->print_z;
|
||||
f->angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
|
||||
// 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.
|
||||
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;
|
||||
|
||||
// apply half spacing using this flow's own spacing and generate infill
|
||||
FillParams params;
|
||||
params.density = 0.01 * density;
|
||||
params.density = float(0.01 * density);
|
||||
// params.dont_adjust = true;
|
||||
params.dont_adjust = false;
|
||||
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
|
||||
// been applied to $f->flow_spacing
|
||||
} 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.
|
||||
|
@ -2031,7 +2031,7 @@ namespace Slic3r {
|
||||
return false;
|
||||
}
|
||||
|
||||
vertices_count += its.vertices.size();
|
||||
vertices_count += (int)its.vertices.size();
|
||||
|
||||
const Transform3d& matrix = volume->get_matrix();
|
||||
|
||||
@ -2061,7 +2061,7 @@ namespace Slic3r {
|
||||
|
||||
// updates triangle offsets
|
||||
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;
|
||||
|
||||
for (size_t i = 0; i < its.indices.size(); ++ i)
|
||||
|
@ -192,7 +192,7 @@ struct AMFParserContext
|
||||
};
|
||||
|
||||
// Version of the amf file
|
||||
unsigned int m_version;
|
||||
unsigned int m_version;
|
||||
// Current Expat XML parser instance.
|
||||
XML_Parser m_parser;
|
||||
// Model to receive objects extracted from an AMF file.
|
||||
@ -616,7 +616,7 @@ void AMFParserContext::endElement(const char * /* name */)
|
||||
if (end != nullptr)
|
||||
*end = 0;
|
||||
|
||||
point(coord_idx) = atof(p);
|
||||
point(coord_idx) = float(atof(p));
|
||||
if (++coord_idx == 5) {
|
||||
m_object->sla_support_points.push_back(sla::SupportPoint(point));
|
||||
coord_idx = 0;
|
||||
@ -628,8 +628,8 @@ void AMFParserContext::endElement(const char * /* name */)
|
||||
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 &&
|
||||
m_object && strcmp(opt_key, "layer_height_ranges") == 0) {
|
||||
// Parse object's layer_height_ranges, a semicolon separated doubles.
|
||||
m_object && strcmp(opt_key, "layer_height_range") == 0) {
|
||||
// Parse object's layer_height_range, a semicolon separated doubles.
|
||||
char* p = const_cast<char*>(m_value[1].c_str());
|
||||
char* end = strchr(p, ';');
|
||||
*end = 0;
|
||||
@ -946,7 +946,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
||||
for (auto range : config_ranges) {
|
||||
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";
|
||||
|
||||
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 << " </vertex>\n";
|
||||
}
|
||||
num_vertices += its.vertices.size();
|
||||
num_vertices += (int)its.vertices.size();
|
||||
}
|
||||
stream << " </vertices>\n";
|
||||
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->sla_support_points = rhs.sla_support_points;
|
||||
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_height_profile = rhs.layer_height_profile;
|
||||
this->origin_translation = rhs.origin_translation;
|
||||
@ -630,7 +629,6 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
|
||||
this->config = std::move(rhs.config);
|
||||
this->sla_support_points = std::move(rhs.sla_support_points);
|
||||
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_height_profile = std::move(rhs.layer_height_profile);
|
||||
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()))
|
||||
return true;
|
||||
|
||||
++i_old;
|
||||
++ i_old;
|
||||
++ i_new;
|
||||
}
|
||||
for (; i_old < model_object_old.volumes.size(); ++ i_old) {
|
||||
|
@ -179,10 +179,8 @@ public:
|
||||
ModelVolumePtrs volumes;
|
||||
// Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings.
|
||||
DynamicPrintConfig config;
|
||||
// Variation of a layer thickness for spans of Z coordinates.
|
||||
t_layer_height_ranges layer_height_ranges;
|
||||
// Variation of a layer thickness for spans of Z coordinates.
|
||||
t_layer_config_ranges layer_config_ranges;
|
||||
// Variation of a layer thickness for spans of Z coordinates + optional parameter overrides.
|
||||
t_layer_config_ranges layer_config_ranges;
|
||||
// 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.
|
||||
std::vector<coordf_t> layer_height_profile;
|
||||
|
@ -41,36 +41,6 @@ void Print::clear()
|
||||
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()
|
||||
{
|
||||
m_regions.emplace_back(new PrintRegion(this));
|
||||
@ -335,7 +305,7 @@ unsigned int Print::num_object_instances() const
|
||||
{
|
||||
unsigned int instances = 0;
|
||||
for (const PrintObject *print_object : m_objects)
|
||||
instances += print_object->copies().size();
|
||||
instances += (unsigned int)print_object->copies().size();
|
||||
return instances;
|
||||
}
|
||||
|
||||
@ -360,7 +330,7 @@ double Print::max_allowed_layer_height() const
|
||||
|
||||
// Caller is responsible for supplying models whose objects don't collide
|
||||
// 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());
|
||||
// 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);
|
||||
}
|
||||
|
||||
size_t volume_id = 0;
|
||||
int volume_id = 0;
|
||||
for (const ModelVolume *volume : model_object->volumes) {
|
||||
if (! volume->is_model_part() && ! volume->is_modifier())
|
||||
continue;
|
||||
// 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.
|
||||
size_t region_id = size_t(-1);
|
||||
for (size_t i = 0; i < m_regions.size(); ++ i)
|
||||
int region_id = -1;
|
||||
for (int i = 0; i < (int)m_regions.size(); ++ i)
|
||||
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 == size_t(-1)) {
|
||||
region_id = m_regions.size();
|
||||
if (region_id == -1) {
|
||||
region_id = (int)m_regions.size();
|
||||
this->add_region(config);
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -489,18 +459,18 @@ bool Print::apply_config_perl_tests_only(DynamicPrintConfig config)
|
||||
bool this_region_config_set = false;
|
||||
for (PrintObject *object : m_objects) {
|
||||
if (region_id < object->region_volumes.size()) {
|
||||
for (int volume_id : object->region_volumes[region_id]) {
|
||||
const ModelVolume &volume = *object->model_object()->volumes[volume_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_and_range.second];
|
||||
if (this_region_config_set) {
|
||||
// If the new config for this volume differs from the other
|
||||
// volume configs currently associated to this region, it means
|
||||
// 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;
|
||||
goto exit_for_rearrange_regions;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
for (const PrintRegionConfig &cfg : other_region_configs) {
|
||||
@ -540,7 +510,7 @@ exit_for_rearrange_regions:
|
||||
model_objects.push_back(object->model_object());
|
||||
this->clear();
|
||||
for (ModelObject *mo : model_objects)
|
||||
this->add_model_object(mo);
|
||||
this->add_model_object_perl_tests_only(mo);
|
||||
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)
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
@ -724,6 +725,50 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
||||
// Handle changes to regions config defaults
|
||||
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 {
|
||||
enum Status {
|
||||
Unknown,
|
||||
@ -733,8 +778,9 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
||||
Deleted,
|
||||
};
|
||||
ModelObjectStatus(ModelID id, Status status = Unknown) : id(id), status(status) {}
|
||||
ModelID id;
|
||||
Status status;
|
||||
ModelID id;
|
||||
Status status;
|
||||
LayerRanges layer_ranges;
|
||||
// Search by 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()));
|
||||
assert(it_status != model_object_status.end());
|
||||
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)
|
||||
// PrintObject instances will be added in the next loop.
|
||||
continue;
|
||||
// Update the ModelObject instance, possibly invalidate the linked PrintObjects.
|
||||
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.
|
||||
// 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 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_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER);
|
||||
if (model_parts_differ || modifiers_differ ||
|
||||
model_object.origin_translation != model_object_new.origin_translation ||
|
||||
// model_object.layer_height_ranges != model_object_new.layer_height_ranges ||
|
||||
model_object.layer_config_ranges != model_object_new.layer_config_ranges || // #ys_FIXME_experiment
|
||||
model_object.layer_height_profile != model_object_new.layer_height_profile) {
|
||||
model_object.layer_height_profile != model_object_new.layer_height_profile ||
|
||||
! layer_height_ranges_equal(model_object.layer_config_ranges, model_object_new.layer_config_ranges, model_object_new.layer_height_profile.empty())) {
|
||||
// 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()));
|
||||
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?
|
||||
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);
|
||||
// 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.input_file = model_object_new.input_file;
|
||||
model_object.clear_instances();
|
||||
@ -1028,19 +1076,27 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
||||
PrintRegionConfig this_region_config;
|
||||
bool this_region_config_set = false;
|
||||
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()) {
|
||||
for (int volume_id : print_object->region_volumes[region_id]) {
|
||||
const ModelVolume &volume = *print_object->model_object()->volumes[volume_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_and_range.second];
|
||||
const DynamicPrintConfig *layer_range_config = layer_ranges->config(volume_and_range.first);
|
||||
if (this_region_config_set) {
|
||||
// If the new config for this volume differs from the other
|
||||
// volume configs currently associated to this region, it means
|
||||
// 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.
|
||||
goto print_object_end;
|
||||
} else {
|
||||
this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders);
|
||||
for (size_t i = 0; i < region_id; ++i) {
|
||||
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) {
|
||||
const PrintRegion ®ion_other = *m_regions[i];
|
||||
if (region_other.m_refcnt != 0 && region_other.config().equals(this_region_config))
|
||||
// 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());
|
||||
// Decrease the references to regions from this volume.
|
||||
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())
|
||||
-- m_regions[ireg]->m_refcnt;
|
||||
++ 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) {
|
||||
PrintObject &print_object0 = *m_objects[idx_print_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) {
|
||||
PrintObject &print_object = *m_objects[i];
|
||||
bool fresh = print_object.region_volumes.empty();
|
||||
unsigned int volume_id = 0;
|
||||
unsigned int idx_region_in_object = 0;
|
||||
for (const ModelVolume *volume : model_object.volumes) {
|
||||
if (! volume->is_model_part() && ! volume->is_modifier()) {
|
||||
++ volume_id;
|
||||
continue;
|
||||
}
|
||||
int region_id = -1;
|
||||
if (&print_object == &print_object0) {
|
||||
// Get the config applied to this volume.
|
||||
PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, num_extruders);
|
||||
// Find an existing print region with the same config.
|
||||
int idx_empty_slot = -1;
|
||||
for (int i = 0; i < (int)m_regions.size(); ++ i) {
|
||||
if (m_regions[i]->m_refcnt == 0) {
|
||||
if (idx_empty_slot == -1)
|
||||
idx_empty_slot = i;
|
||||
} else if (config.equals(m_regions[i]->config())) {
|
||||
region_id = i;
|
||||
break;
|
||||
// Filter the layer ranges, so they do not overlap and they contain at least a single layer.
|
||||
// Now insert a volume with a layer range to its own region.
|
||||
for (auto it_range = layer_ranges->begin(); it_range != layer_ranges->end(); ++ it_range) {
|
||||
int region_id = -1;
|
||||
if (&print_object == &print_object0) {
|
||||
// Get the config applied to this volume.
|
||||
PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, it_range->second, *volume, num_extruders);
|
||||
// Find an existing print region with the same config.
|
||||
int idx_empty_slot = -1;
|
||||
for (int i = 0; i < (int)m_regions.size(); ++ i) {
|
||||
if (m_regions[i]->m_refcnt == 0) {
|
||||
if (idx_empty_slot == -1)
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
regions_in_object.emplace_back(region_id);
|
||||
} else
|
||||
region_id = regions_in_object[idx_region_in_object ++];
|
||||
// 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, it_range->first);
|
||||
}
|
||||
}
|
||||
++ volume_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1176,7 +1245,7 @@ std::string Print::validate() const
|
||||
Polygon convex_hull0 = offset(
|
||||
print_object->model_object()->convex_hull_2d(
|
||||
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.
|
||||
for (const Point © : print_object->m_copies) {
|
||||
Polygon convex_hull = convex_hull0;
|
||||
@ -1228,7 +1297,6 @@ std::string Print::validate() const
|
||||
bool has_custom_layering = false;
|
||||
std::vector<std::vector<coordf_t>> layer_height_profiles;
|
||||
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
|
||||
if (has_custom_layering) {
|
||||
layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>());
|
||||
@ -1437,9 +1505,9 @@ Flow Print::brim_flow() const
|
||||
generation as well. */
|
||||
return Flow::new_from_config_width(
|
||||
frPerimeter,
|
||||
width,
|
||||
m_config.nozzle_diameter.get_at(m_regions.front()->config().perimeter_extruder-1),
|
||||
this->skirt_first_layer_height(),
|
||||
width,
|
||||
(float)m_config.nozzle_diameter.get_at(m_regions.front()->config().perimeter_extruder-1),
|
||||
(float)this->skirt_first_layer_height(),
|
||||
0
|
||||
);
|
||||
}
|
||||
@ -1459,9 +1527,9 @@ Flow Print::skirt_flow() const
|
||||
generation as well. */
|
||||
return Flow::new_from_config_width(
|
||||
frPerimeter,
|
||||
width,
|
||||
m_config.nozzle_diameter.get_at(m_objects.front()->config().support_material_extruder-1),
|
||||
this->skirt_first_layer_height(),
|
||||
width,
|
||||
(float)m_config.nozzle_diameter.get_at(m_objects.front()->config().support_material_extruder-1),
|
||||
(float)this->skirt_first_layer_height(),
|
||||
0
|
||||
);
|
||||
}
|
||||
@ -1636,20 +1704,20 @@ void Print::_make_skirt()
|
||||
|
||||
// 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.
|
||||
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());
|
||||
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.
|
||||
// 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.);
|
||||
for (int i = n_skirts, extruder_idx = 0; i > 0; -- i) {
|
||||
this->throw_if_canceled();
|
||||
// Offset the skirt outside.
|
||||
distance += coord_t(scale_(spacing));
|
||||
distance += float(scale_(spacing));
|
||||
// Generate the skirt centerline.
|
||||
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);
|
||||
if (loops.empty())
|
||||
break;
|
||||
@ -1660,9 +1728,9 @@ void Print::_make_skirt()
|
||||
eloop.paths.emplace_back(ExtrusionPath(
|
||||
ExtrusionPath(
|
||||
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,
|
||||
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();
|
||||
m_skirt.append(eloop);
|
||||
@ -1788,7 +1856,7 @@ void Print::_make_wipe_tower()
|
||||
// Insert the new support layer.
|
||||
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.
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1815,19 +1883,19 @@ void Print::_make_wipe_tower()
|
||||
WipeTowerPrusaMM::parse_material(m_config.filament_type.get_at(i).c_str()),
|
||||
m_config.temperature.get_at(i),
|
||||
m_config.first_layer_temperature.get_at(i),
|
||||
m_config.filament_loading_speed.get_at(i),
|
||||
m_config.filament_loading_speed_start.get_at(i),
|
||||
m_config.filament_unloading_speed.get_at(i),
|
||||
m_config.filament_unloading_speed_start.get_at(i),
|
||||
m_config.filament_toolchange_delay.get_at(i),
|
||||
(float)m_config.filament_loading_speed.get_at(i),
|
||||
(float)m_config.filament_loading_speed_start.get_at(i),
|
||||
(float)m_config.filament_unloading_speed.get_at(i),
|
||||
(float)m_config.filament_unloading_speed_start.get_at(i),
|
||||
(float)m_config.filament_toolchange_delay.get_at(i),
|
||||
m_config.filament_cooling_moves.get_at(i),
|
||||
m_config.filament_cooling_initial_speed.get_at(i),
|
||||
m_config.filament_cooling_final_speed.get_at(i),
|
||||
(float)m_config.filament_cooling_initial_speed.get_at(i),
|
||||
(float)m_config.filament_cooling_final_speed.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>(
|
||||
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
|
||||
// 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
|
||||
if (!layer_tools.has_wipe_tower) continue;
|
||||
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) {
|
||||
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
|
||||
// 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:
|
||||
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:
|
||||
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
|
||||
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);
|
||||
current_extruder_id = extruder_id;
|
||||
}
|
||||
|
@ -80,8 +80,8 @@ private: // Prevents erroneous use by other classes.
|
||||
typedef PrintObjectBaseWithState<Print, PrintObjectStep, posCount> Inherited;
|
||||
|
||||
public:
|
||||
// vector of (vectors of volume ids), indexed by region_id
|
||||
std::vector<std::vector<int>> region_volumes;
|
||||
// vector of (layer height ranges and vectors of volume ids), indexed by region_id
|
||||
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
|
||||
// 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)); }
|
||||
|
||||
// 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())
|
||||
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 value is not supposed to be compared with Layer::id
|
||||
@ -141,8 +141,9 @@ public:
|
||||
void slice();
|
||||
|
||||
// Helpers to slice support enforcer / blocker meshes by the support generator.
|
||||
std::vector<ExPolygons> slice_support_enforcers() const;
|
||||
std::vector<ExPolygons> slice_support_blockers() const;
|
||||
std::vector<ExPolygons> slice_support_volumes(const ModelVolumeType &model_volume_type) 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:
|
||||
// to be called from Print only.
|
||||
@ -165,7 +166,7 @@ protected:
|
||||
void update_slicing_parameters();
|
||||
|
||||
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:
|
||||
void make_perimeters();
|
||||
@ -201,9 +202,11 @@ private:
|
||||
LayerPtrs m_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_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_region(size_t region_id, const std::vector<float> &z) const;
|
||||
std::vector<ExPolygons> slice_modifiers(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_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
|
||||
@ -292,8 +295,7 @@ public:
|
||||
ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override;
|
||||
|
||||
// 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(ModelObject* model_object, int idx = -1);
|
||||
void add_model_object_perl_tests_only(ModelObject* model_object, int idx = -1);
|
||||
bool apply_config_perl_tests_only(DynamicPrintConfig config);
|
||||
|
||||
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
|
||||
// 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.
|
||||
// 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).
|
||||
@ -590,7 +590,12 @@ bool PrintObject::invalidate_step(PrintObjectStep step)
|
||||
|
||||
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
|
||||
@ -1354,10 +1359,12 @@ PrintObjectConfig PrintObject::object_config_from_model_object(const PrintObject
|
||||
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;
|
||||
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);
|
||||
if (! volume.material_id().empty())
|
||||
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());
|
||||
}
|
||||
|
||||
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;
|
||||
PrintObjectConfig object_config;
|
||||
PrintRegionConfig default_region_config;
|
||||
print_config .apply(full_config, true);
|
||||
object_config.apply(full_config, true);
|
||||
default_region_config.apply(full_config, true);
|
||||
size_t num_extruders = print_config.nozzle_diameter.size();
|
||||
object_config = object_config_from_model_object(object_config, model_object, num_extruders);
|
||||
PrintConfig print_config;
|
||||
PrintObjectConfig object_config;
|
||||
PrintRegionConfig default_region_config;
|
||||
print_config.apply(full_config, true);
|
||||
object_config.apply(full_config, true);
|
||||
default_region_config.apply(full_config, true);
|
||||
size_t num_extruders = print_config.nozzle_diameter.size();
|
||||
object_config = object_config_from_model_object(object_config, model_object, num_extruders);
|
||||
|
||||
std::vector<unsigned int> object_extruders;
|
||||
for (const ModelVolume *model_volume : model_object.volumes)
|
||||
if (model_volume->is_model_part())
|
||||
PrintRegion::collect_object_printing_extruders(
|
||||
print_config,
|
||||
region_config_from_model_volume(default_region_config, *model_volume, num_extruders),
|
||||
object_extruders);
|
||||
std::vector<unsigned int> object_extruders;
|
||||
for (const ModelVolume* model_volume : model_object.volumes)
|
||||
if (model_volume->is_model_part()) {
|
||||
PrintRegion::collect_object_printing_extruders(
|
||||
print_config,
|
||||
region_config_from_model_volume(default_region_config, nullptr, *model_volume, num_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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1430,13 +1446,12 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
|
||||
layer_height_profile.clear();
|
||||
|
||||
if (layer_height_profile.empty()) {
|
||||
if (0)
|
||||
if (0)
|
||||
// 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
|
||||
// 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
|
||||
updated = true;
|
||||
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); // #ys_FIXME_experiment
|
||||
updated = true;
|
||||
}
|
||||
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.
|
||||
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_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 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];
|
||||
if (model_volume->is_model_part()) {
|
||||
map_volume_to_region[volume_id] = region_id;
|
||||
if (single_volume_region == -2)
|
||||
// first model volume met
|
||||
single_volume_region = region_id;
|
||||
else if (single_volume_region != region_id)
|
||||
// multiple volumes met and they are not equal
|
||||
single_volume_region = -1;
|
||||
++ num_volumes;
|
||||
if (last_volume_id == volume_id) {
|
||||
has_z_ranges = true;
|
||||
} else {
|
||||
last_volume_id = volume_id;
|
||||
if (all_volumes_single_region == -2)
|
||||
// first model volume met
|
||||
all_volumes_single_region = region_id;
|
||||
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())
|
||||
++ num_modifiers;
|
||||
}
|
||||
@ -1515,13 +1536,13 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
||||
// Slice all non-modifier volumes.
|
||||
bool clipped = 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.
|
||||
// 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) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id;
|
||||
// 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();
|
||||
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)
|
||||
@ -1542,15 +1563,29 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
||||
};
|
||||
std::vector<SlicedVolume> sliced_volumes;
|
||||
sliced_volumes.reserve(num_volumes);
|
||||
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id)
|
||||
for (int volume_id : this->region_volumes[region_id]) {
|
||||
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_model_part()) {
|
||||
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
|
||||
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.
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - parallel clipping - start";
|
||||
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) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - region " << region_id;
|
||||
// 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();
|
||||
if (expolygons_by_layer.empty())
|
||||
continue;
|
||||
@ -1620,7 +1655,7 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
||||
Layer *layer = m_layers[layer_id];
|
||||
LayerRegion *layerm = layer->m_regions[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;
|
||||
Polygons other_slices = to_polygons(other_layerm->slices);
|
||||
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";
|
||||
}
|
||||
|
||||
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()) {
|
||||
for (int volume_id : this->region_volumes[region_id]) {
|
||||
const ModelVolume *volume = this->model_object()->volumes[volume_id];
|
||||
if (modifier ? volume->is_modifier() : volume->is_model_part())
|
||||
volumes.emplace_back(volume);
|
||||
}
|
||||
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_model_part())
|
||||
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;
|
||||
for (const ModelVolume *volume : this->model_object()->volumes)
|
||||
if (volume->is_support_enforcer())
|
||||
if (volume->type() == model_volume_type)
|
||||
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);
|
||||
return this->slice_volumes(zs, volumes);
|
||||
}
|
||||
|
||||
std::vector<ExPolygons> PrintObject::slice_support_blockers() 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> PrintObject::slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const
|
||||
{
|
||||
std::vector<ExPolygons> layers;
|
||||
if (! volumes.empty()) {
|
||||
@ -1829,34 +1945,71 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
|
||||
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;
|
||||
// Compose mesh.
|
||||
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
|
||||
TriangleMesh mesh(volume.mesh());
|
||||
mesh.transform(volume.get_matrix(), true);
|
||||
if (mesh.repaired) {
|
||||
//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 (! z.empty()) {
|
||||
// Compose 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.
|
||||
TriangleMesh mesh(volume.mesh());
|
||||
mesh.transform(volume.get_matrix(), true);
|
||||
if (mesh.repaired) {
|
||||
//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;
|
||||
}
|
||||
|
||||
// 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()
|
||||
{
|
||||
// Collect layers with slicing errors.
|
||||
@ -2120,7 +2273,7 @@ void PrintObject::clip_fill_surfaces()
|
||||
//Should the pw not be half of the current value?
|
||||
float pw = FLT_MAX;
|
||||
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
|
||||
polygons_append(overhangs, offset2(perimeters, -pw, +pw));
|
||||
}
|
||||
|
@ -153,29 +153,33 @@ SlicingParameters SlicingParameters::create_from_config(
|
||||
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.
|
||||
std::vector<coordf_t> layer_height_profile_from_ranges(
|
||||
const SlicingParameters &slicing_params,
|
||||
// const t_layer_height_ranges &layer_height_ranges)
|
||||
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.
|
||||
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
|
||||
if (slicing_params.first_object_layer_height_fixed())
|
||||
ranges_non_overlapping.push_back(std::pair<t_layer_height_range,coordf_t>(
|
||||
t_layer_height_range(0., slicing_params.first_object_layer_height),
|
||||
slicing_params.first_object_layer_height));
|
||||
// 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) { // #ys_FIXME_experiment
|
||||
for (t_layer_config_ranges::const_iterator it_range = layer_config_ranges.begin(); it_range != layer_config_ranges.end(); ++ it_range) {
|
||||
coordf_t lo = it_range->first.first;
|
||||
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(); // #ys_FIXME_experiment
|
||||
coordf_t height = it_range->second.option("layer_height")->getFloat();
|
||||
if (! ranges_non_overlapping.empty())
|
||||
// Trim current low with the last high.
|
||||
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.
|
||||
std::vector<coordf_t> layer_height_profile_adaptive(
|
||||
const SlicingParameters &slicing_params,
|
||||
const t_layer_height_ranges &layer_height_ranges,
|
||||
const t_layer_config_ranges & /* layer_config_ranges */,
|
||||
const ModelVolumePtrs &volumes)
|
||||
{
|
||||
// 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::map<t_layer_height_range,coordf_t> t_layer_height_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(
|
||||
const SlicingParameters &slicing_params,
|
||||
// const t_layer_height_ranges &layer_height_ranges);
|
||||
const t_layer_config_ranges &layer_config_ranges);
|
||||
|
||||
extern std::vector<coordf_t> layer_height_profile_adaptive(
|
||||
const SlicingParameters &slicing_params,
|
||||
const t_layer_height_ranges &layer_height_ranges,
|
||||
const t_layer_config_ranges &layer_config_ranges,
|
||||
const ModelVolumePtrs &volumes);
|
||||
|
||||
|
||||
|
@ -829,7 +829,7 @@ namespace SupportMaterialInternal {
|
||||
assert(expansion_scaled >= 0.f);
|
||||
for (const ExtrusionPath &ep : loop.paths)
|
||||
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.size() >= 3) {
|
||||
// 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.
|
||||
columns_base->polygons = diff(
|
||||
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)
|
||||
columns_base->polygons = diff(columns_base->polygons, interface_polygons);
|
||||
}
|
||||
@ -3226,7 +3226,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
|
||||
// TODO: use brim ordering algorithm
|
||||
Polygons to_infill_polygons = to_polygons(to_infill);
|
||||
// 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(
|
||||
base_layer.extrusions,
|
||||
to_polylines(std::move(to_infill_polygons)),
|
||||
|
@ -600,12 +600,12 @@ void Bed3D::render_prusa_shader(bool transparent) const
|
||||
if (position_id != -1)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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()));
|
||||
|
@ -1922,9 +1922,6 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
|
||||
}
|
||||
|
||||
object->ensure_on_bed();
|
||||
|
||||
// print.auto_assign_extruders(object);
|
||||
// print.add_model_object(object);
|
||||
}
|
||||
|
||||
#ifdef AUTOPLACEMENT_ON_LOAD
|
||||
|
@ -1129,7 +1129,6 @@ void Selection::copy_to_clipboard()
|
||||
dst_object->config = src_object->config;
|
||||
dst_object->sla_support_points = src_object->sla_support_points;
|
||||
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_height_profile = src_object->layer_height_profile;
|
||||
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 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)';
|
||||
}
|
||||
|
||||
# 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
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
@ -40,7 +42,7 @@ use Slic3r::Test;
|
||||
|
||||
# user sets a per-region option
|
||||
$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';
|
||||
|
||||
# user exports G-code, thus the default config is reapplied
|
||||
@ -51,7 +53,7 @@ use Slic3r::Test;
|
||||
# user assigns object extruders
|
||||
$print->print->objects->[0]->model_object->config->set('extruder', 3);
|
||||
$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->perimeter_extruder, 2, 'extruder setting does not override explicitely specified extruders';
|
||||
|
@ -100,7 +100,6 @@ _constant()
|
||||
%code%{ RETVAL = const_cast<PrintObjectPtrs*>(&THIS->objects()); %};
|
||||
Ref<PrintObject> get_object(int idx)
|
||||
%code%{ RETVAL = THIS->objects()[idx]; %};
|
||||
void reload_object(int idx);
|
||||
size_t object_count()
|
||||
%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)
|
||||
%code%{ RETVAL = THIS->apply_config_perl_tests_only(*config); %};
|
||||
bool has_infinite_skirt();
|
||||
|
Loading…
Reference in New Issue
Block a user