ENH: enhance extruder unprintable area detection
1. Detect unprintable area for extruder when slicing 2. Always do filament map again if object pos changed jira:STUDIO-9473 Signed-off-by: xun.zhang <xun.zhang@bambulab.com> Change-Id: Ic01b8be8e3b08ba6b34efb2d3c451c9e985a03e8
This commit is contained in:
parent
2a07fcf8b9
commit
f1445ff047
|
@ -38,82 +38,6 @@ static std::set<int>get_filament_by_type(const std::vector<unsigned int>& used_f
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Determines the unprintable filaments for each extruder based on its physical attributes
|
||||
*
|
||||
* Currently, the criteria for determining unprintable filament include the following:
|
||||
* 1. TPU filaments can only be placed in the master extruder and must be grouped alone.
|
||||
* 2. We only support at most 1 tpu filament.
|
||||
* 3. An extruder can only accommodate filament with a hardness requirement lower than that of its nozzle.
|
||||
* If extruder num is 1, just return an empty vector.
|
||||
*
|
||||
* @param used_filaments Totally used filaments when slicing
|
||||
* @param config Config that stores releted params
|
||||
* @return A vector of sets representing unprintable filaments for each extruder
|
||||
*/
|
||||
std::vector<std::set<int>> ToolOrdering::get_physical_unprintables(const std::vector<unsigned int>& used_filaments, const PrintConfig* config)
|
||||
{
|
||||
// master saved in config is 1 based,so we should transfer to 0 based here
|
||||
int master_extruder_id = config->master_extruder_id.value - 1;
|
||||
auto tpu_filaments = get_filament_by_type(used_filaments, config, "TPU");
|
||||
if (tpu_filaments.size() > 1) {
|
||||
throw Slic3r::RuntimeError(std::string("Only supports up to one TPU filament."));
|
||||
}
|
||||
|
||||
int extruder_num = config->nozzle_diameter.size();
|
||||
// consider tpu, only place tpu in extruder with ams
|
||||
std::vector<std::set<int>>physical_unprintables(extruder_num);
|
||||
if (extruder_num < 2)
|
||||
return physical_unprintables;
|
||||
|
||||
int extruder_without_tpu = 1 - master_extruder_id;
|
||||
for (auto& f : tpu_filaments)
|
||||
physical_unprintables[extruder_without_tpu].insert(f);
|
||||
|
||||
// consider nozzle hrc, nozzle hrc should larger than filament hrc
|
||||
for (size_t eid = 0; eid < physical_unprintables.size(); ++eid) {
|
||||
auto nozzle_type = config->nozzle_type.get_at(eid);
|
||||
int nozzle_hrc = Print::get_hrc_by_nozzle_type(NozzleType(nozzle_type));
|
||||
for (auto& f : used_filaments) {
|
||||
int filament_hrc = config->required_nozzle_HRC.get_at(f);
|
||||
if(filament_hrc>nozzle_hrc){
|
||||
physical_unprintables[eid].insert(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return physical_unprintables;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines the unprintable filaments for each extruder based on its printable area.
|
||||
*
|
||||
* The returned array will always have the same size as the number of extruders.
|
||||
* If extruder num is 1, just return an empty vector.
|
||||
* If an extruder has no unprintable filaments, an empty set will also be returned
|
||||
*
|
||||
* @param unprintable_arrs An array of unprintable filaments for each extruder
|
||||
* @param config Containing extruder nums or any other info requested
|
||||
* @return A vector of sets representing unprintable filaments for each extruder
|
||||
*/
|
||||
std::vector<std::set<int>> ToolOrdering::get_geometrical_unprintables(const std::vector<std::vector<int>>& unprintable_arrs, const PrintConfig* config)
|
||||
{
|
||||
auto arrs_idx_switched = unprintable_arrs;
|
||||
int extruder_nums = config->nozzle_diameter.size();
|
||||
std::vector<std::set<int>> unprintables(extruder_nums);
|
||||
if(extruder_nums < 2)
|
||||
return unprintables;
|
||||
|
||||
for (auto& arr : arrs_idx_switched)
|
||||
for (auto& item : arr)
|
||||
item -= 1;
|
||||
|
||||
for (size_t idx = 0; idx < arrs_idx_switched.size(); ++idx)
|
||||
unprintables[idx] = std::set<int>(arrs_idx_switched[idx].begin(), arrs_idx_switched[idx].end());
|
||||
|
||||
return unprintables;
|
||||
}
|
||||
|
||||
// Returns true in case that extruder a comes before b (b does not have to be present). False otherwise.
|
||||
bool LayerTools::is_extruder_order(unsigned int a, unsigned int b) const
|
||||
{
|
||||
|
@ -1147,8 +1071,8 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first
|
|||
|
||||
std::vector<unsigned int> used_filaments = collect_sorted_used_filaments(layer_filaments);
|
||||
|
||||
std::vector<std::set<int>>geometric_unprintables = get_geometrical_unprintables(m_print->get_unprintable_filament_ids(), print_config);
|
||||
std::vector<std::set<int>>physical_unprintables = get_physical_unprintables(used_filaments, print_config);
|
||||
std::vector<std::set<int>>geometric_unprintables = m_print->get_geometric_unprintable_filaments();
|
||||
std::vector<std::set<int>>physical_unprintables = m_print->get_physical_unprintable_filaments(used_filaments);
|
||||
|
||||
filament_maps = m_print->get_filament_maps();
|
||||
map_mode = m_print->get_filament_map_mode();
|
||||
|
|
|
@ -242,8 +242,6 @@ public:
|
|||
*/
|
||||
static std::vector<int> get_recommended_filament_maps(const std::vector<std::vector<unsigned int>>& layer_filaments, const Print* print,const FilamentMapMode mode, const std::vector<std::set<int>>& physical_unprintables, const std::vector<std::set<int>>& geometric_unprintables);
|
||||
|
||||
static std::vector<std::set<int>> get_physical_unprintables(const std::vector<unsigned int>& layer_filaments, const PrintConfig* config);
|
||||
static std::vector<std::set<int>> get_geometrical_unprintables(const std::vector<std::vector<int>>& unprintable_arrs, const PrintConfig* config);
|
||||
static bool check_tpu_group(const std::vector<unsigned int>&used_filaments,const std::vector<int>& filament_maps,const PrintConfig* config);
|
||||
|
||||
// should be called after doing reorder
|
||||
|
|
|
@ -1820,7 +1820,22 @@ void Print::process(std::unordered_map<std::string, long long>* slice_time, bool
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (this->set_started(psWipeTower)) {
|
||||
{
|
||||
std::vector<std::set<int>> geometric_unprintables(m_config.nozzle_diameter.size());
|
||||
for (PrintObject* obj : m_objects) {
|
||||
std::vector<std::set<int>> obj_geometric_unprintables = obj->detect_extruder_geometric_unprintables();
|
||||
for (size_t idx = 0; idx < obj_geometric_unprintables.size(); ++idx) {
|
||||
if (idx < geometric_unprintables.size()) {
|
||||
geometric_unprintables[idx].insert(obj_geometric_unprintables[idx].begin(), obj_geometric_unprintables[idx].end());
|
||||
}
|
||||
}
|
||||
}
|
||||
this->set_geometric_unprintable_filaments(geometric_unprintables);
|
||||
}
|
||||
|
||||
m_wipe_tower_data.clear();
|
||||
m_tool_ordering.clear();
|
||||
if (this->has_wipe_tower()) {
|
||||
|
@ -1875,9 +1890,8 @@ void Print::process(std::unordered_map<std::string, long long>* slice_time, bool
|
|||
}
|
||||
|
||||
auto used_filaments = collect_sorted_used_filaments(all_filaments);
|
||||
auto physical_unprintables = ToolOrdering::get_physical_unprintables(used_filaments, &m_config);
|
||||
auto geometric_unprintables = ToolOrdering::get_geometrical_unprintables(get_unprintable_filament_ids(), &m_config);
|
||||
|
||||
auto physical_unprintables = this->get_physical_unprintable_filaments(used_filaments);
|
||||
auto geometric_unprintables = this->get_geometric_unprintable_filaments();
|
||||
std::vector<int>filament_maps = this->get_filament_maps();
|
||||
auto map_mode = get_filament_map_mode();
|
||||
// get recommended filament map
|
||||
|
@ -2397,10 +2411,6 @@ void Print::update_filament_maps_to_config(std::vector<int> f_maps)
|
|||
m_has_auto_filament_map_result = true;
|
||||
}
|
||||
|
||||
const std::vector<std::vector<int>>& Print::get_unprintable_filament_ids() const
|
||||
{
|
||||
return m_config.unprintable_filament_map.values;
|
||||
}
|
||||
|
||||
std::vector<int> Print::get_filament_maps() const
|
||||
{
|
||||
|
@ -2412,6 +2422,44 @@ FilamentMapMode Print::get_filament_map_mode() const
|
|||
return m_config.filament_map_mode;
|
||||
}
|
||||
|
||||
std::vector<std::set<int>> Print::get_physical_unprintable_filaments(const std::vector<unsigned int>& used_filaments) const
|
||||
{
|
||||
// master saved in config is 1 based,so we should transfer to 0 based here
|
||||
int master_extruder_id = m_config.master_extruder_id.value - 1;
|
||||
std::set<int> tpu_filaments;
|
||||
for (auto f : used_filaments) {
|
||||
if (m_config.filament_type.get_at(f) == "TPU")
|
||||
tpu_filaments.insert(f);
|
||||
}
|
||||
if (tpu_filaments.size() > 1) {
|
||||
throw Slic3r::RuntimeError(std::string("Only supports up to one TPU filament."));
|
||||
}
|
||||
|
||||
int extruder_num = m_config.nozzle_diameter.size();
|
||||
// consider tpu, only place tpu in extruder with ams
|
||||
std::vector<std::set<int>>physical_unprintables(extruder_num);
|
||||
if (extruder_num < 2)
|
||||
return physical_unprintables;
|
||||
|
||||
int extruder_without_tpu = 1 - master_extruder_id;
|
||||
for (auto& f : tpu_filaments)
|
||||
physical_unprintables[extruder_without_tpu].insert(f);
|
||||
|
||||
// consider nozzle hrc, nozzle hrc should larger than filament hrc
|
||||
for (size_t eid = 0; eid < physical_unprintables.size(); ++eid) {
|
||||
auto nozzle_type = m_config.nozzle_type.get_at(eid);
|
||||
int nozzle_hrc = get_hrc_by_nozzle_type(NozzleType(nozzle_type));
|
||||
for (auto& f : used_filaments) {
|
||||
int filament_hrc = m_config.required_nozzle_HRC.get_at(f);
|
||||
if(filament_hrc>nozzle_hrc){
|
||||
physical_unprintables[eid].insert(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
return physical_unprintables;
|
||||
}
|
||||
|
||||
|
||||
std::vector<double> Print::get_extruder_printable_height() const
|
||||
{
|
||||
return m_config.extruder_printable_height.values;
|
||||
|
|
|
@ -436,7 +436,7 @@ public:
|
|||
//BBS
|
||||
BoundingBox get_first_layer_bbox(float& area, float& layer_height, std::string& name);
|
||||
void get_certain_layers(float start, float end, std::vector<LayerPtrs> &out, std::vector<BoundingBox> &boundingbox_objects);
|
||||
std::vector<Point> get_instances_shift_without_plate_offset();
|
||||
std::vector<Point> get_instances_shift_without_plate_offset() const;
|
||||
PrintObject* get_shared_object() const { return m_shared_object; }
|
||||
void set_shared_object(PrintObject *object);
|
||||
void clear_shared_object();
|
||||
|
@ -485,6 +485,17 @@ private:
|
|||
void generate_support_material();
|
||||
void simplify_extrusion_path();
|
||||
|
||||
/**
|
||||
* @brief Determines the unprintable filaments for each extruder based on its printable area.
|
||||
*
|
||||
* The returned array will always have the same size as the number of extruders.
|
||||
* If extruder num is 1, just return an empty vector.
|
||||
* If an extruder has no unprintable filaments, an empty set will also be returned
|
||||
*
|
||||
* @return A vector of sets representing unprintable filaments for each extruder
|
||||
*/
|
||||
std::vector<std::set<int>> detect_extruder_geometric_unprintables() const;
|
||||
|
||||
void slice_volumes();
|
||||
//BBS
|
||||
ExPolygons _shrink_contour_holes(double contour_delta, double hole_delta, const ExPolygons& polys) const;
|
||||
|
@ -831,8 +842,21 @@ public:
|
|||
const std::vector<std::vector<DynamicPrintConfig>>& get_extruder_filament_info() const { return m_extruder_filament_info; }
|
||||
void set_extruder_filament_info(const std::vector<std::vector<DynamicPrintConfig>>& filament_info) { m_extruder_filament_info = filament_info; }
|
||||
|
||||
// 1 based ids
|
||||
const std::vector<std::vector<int>> &get_unprintable_filament_ids() const;
|
||||
void set_geometric_unprintable_filaments(const std::vector<std::set<int>> &unprintables_filament_ids) { m_geometric_unprintable_filaments = unprintables_filament_ids; }
|
||||
std::vector<std::set<int>> get_geometric_unprintable_filaments() const { return m_geometric_unprintable_filaments;}
|
||||
|
||||
/**
|
||||
* @brief Determines the unprintable filaments for each extruder based on its physical attributes
|
||||
*
|
||||
* Currently, the criteria for determining unprintable filament include the following:
|
||||
* 1. TPU filaments can only be placed in the master extruder and must be grouped alone.
|
||||
* 2. We only support at most 1 tpu filament.
|
||||
* 3. An extruder can only accommodate filament with a hardness requirement lower than that of its nozzle.
|
||||
*
|
||||
* @param used_filaments Totally used filaments when slicing
|
||||
* @return A vector of sets representing unprintable filaments for each extruder.Return an empty vecto if extruder num is 1
|
||||
*/
|
||||
std::vector<std::set<int>> get_physical_unprintable_filaments(const std::vector<unsigned int>& used_filaments) const;
|
||||
|
||||
std::vector<double> get_extruder_printable_height() const;
|
||||
std::vector<Polygons> get_extruder_printable_polygons() const;
|
||||
|
@ -958,7 +982,7 @@ private:
|
|||
FakeWipeTower m_fake_wipe_tower;
|
||||
bool m_has_auto_filament_map_result{false};
|
||||
|
||||
std::vector<std::vector<int>> m_unprintable_filament_ids;
|
||||
std::vector<std::set<int>> m_geometric_unprintable_filaments;
|
||||
|
||||
// OrcaSlicer: calibration
|
||||
Calib_Params m_calib_params;
|
||||
|
|
|
@ -1521,8 +1521,13 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||
} else {
|
||||
// The PrintObject already exists and the copies differ.
|
||||
PrintBase::ApplyStatus status = (*it_old)->print_object->set_instances(std::move(new_instances.instances));
|
||||
if (status != PrintBase::APPLY_STATUS_UNCHANGED)
|
||||
if (status != PrintBase::APPLY_STATUS_UNCHANGED) {
|
||||
size_t extruder_num = new_full_config.option<ConfigOptionFloatsNullable>("nozzle_diameter")->size();
|
||||
if (extruder_num > 1) {
|
||||
update_apply_status(this->invalidate_steps({ psWipeTower,psSkirtBrim, psGCodeExport }));
|
||||
}
|
||||
update_apply_status(status == PrintBase::APPLY_STATUS_INVALIDATED);
|
||||
}
|
||||
print_objects_new.emplace_back((*it_old)->print_object);
|
||||
const_cast<PrintObjectStatus*>(*it_old)->status = PrintObjectStatus::Reused;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/concurrent_vector.h>
|
||||
#include <tbb/concurrent_unordered_set.h>
|
||||
|
||||
#include <Shiny/Shiny.h>
|
||||
|
||||
|
@ -190,6 +191,92 @@ void PrintObject::merge_layer_node(const size_t layer_id, int &max_merged_id, st
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::set<int>> PrintObject::detect_extruder_geometric_unprintables() const
|
||||
{
|
||||
int extruder_size = m_print->config().nozzle_diameter.size();
|
||||
if(extruder_size == 1)
|
||||
return std::vector<std::set<int>>(1, std::set<int>());
|
||||
|
||||
std::vector<tbb::concurrent_unordered_set<int>> tbb_geometric_unprintables(extruder_size);
|
||||
std::vector<Polygons> unprintable_area_in_obj_coord = m_print->get_extruder_unprintable_polygons();
|
||||
std::vector<BoundingBox> unprintable_area_bbox;
|
||||
|
||||
for (auto& polys : unprintable_area_in_obj_coord) {
|
||||
for (auto& poly : polys) {
|
||||
poly.translate(-m_instances.front().shift_without_plate_offset());
|
||||
}
|
||||
unprintable_area_bbox.emplace_back(get_extents(polys));
|
||||
}
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, m_layers.size()),
|
||||
[this, &tbb_geometric_unprintables, &unprintable_area_in_obj_coord, &unprintable_area_bbox](const tbb::blocked_range<int>& range) {
|
||||
for (int j = range.begin(); j < range.end(); ++j) {
|
||||
auto layer = m_layers[j];
|
||||
for (auto layerm : layer->regions()) {
|
||||
const auto& region = layerm->region();
|
||||
int wall_filament = region.config().wall_filament;
|
||||
int solid_infill_filament = region.config().solid_infill_filament;
|
||||
int sparse_infill_filament = region.config().sparse_infill_filament;
|
||||
std::optional<ExPolygons> fill_expolys;
|
||||
BoundingBox fill_bbox;
|
||||
std::optional<ExPolygons> wall_expolys;
|
||||
BoundingBox wall_bbox;
|
||||
|
||||
for (size_t idx = 0; idx < unprintable_area_in_obj_coord.size(); ++idx) {
|
||||
bool do_infill_filament_detect = (solid_infill_filament > 0 && tbb_geometric_unprintables[idx].count(solid_infill_filament - 1) == 0) ||
|
||||
(sparse_infill_filament > 0 && tbb_geometric_unprintables[idx].count(sparse_infill_filament-1) == 0);
|
||||
|
||||
bool infill_unprintable = !layerm->fills.entities.empty() &&
|
||||
((solid_infill_filament > 0 && tbb_geometric_unprintables[idx].count(solid_infill_filament - 1) > 0) ||
|
||||
(sparse_infill_filament > 0 && tbb_geometric_unprintables[idx].count(sparse_infill_filament - 1) > 0));
|
||||
|
||||
if (!layerm->fills.entities.empty() && do_infill_filament_detect) {
|
||||
if (!fill_expolys) {
|
||||
fill_expolys = layerm->fill_expolygons;
|
||||
fill_bbox = get_extents(*fill_expolys);
|
||||
}
|
||||
if (fill_bbox.overlap(unprintable_area_bbox[idx]) &&
|
||||
!intersection(*fill_expolys, unprintable_area_in_obj_coord[idx]).empty()) {
|
||||
if (solid_infill_filament > 0)
|
||||
tbb_geometric_unprintables[idx].insert(solid_infill_filament - 1);
|
||||
if (sparse_infill_filament > 0)
|
||||
tbb_geometric_unprintables[idx].insert(sparse_infill_filament - 1);
|
||||
infill_unprintable = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool do_wall_filament_detect = wall_filament > 0 && tbb_geometric_unprintables[idx].count(wall_filament - 1) == 0;
|
||||
if (!layerm->perimeters.entities.empty() && do_wall_filament_detect) {
|
||||
if (infill_unprintable) {
|
||||
tbb_geometric_unprintables[idx].insert(wall_filament - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!wall_expolys) {
|
||||
if (!fill_expolys) {
|
||||
fill_expolys = layerm->fill_expolygons;
|
||||
fill_bbox = get_extents(*fill_expolys);
|
||||
}
|
||||
wall_expolys = diff_ex(layerm->raw_slices, *fill_expolys);
|
||||
wall_bbox = get_extents(*wall_expolys);
|
||||
}
|
||||
|
||||
if (wall_bbox.overlap(unprintable_area_bbox[idx]) &&
|
||||
!intersection(*wall_expolys, unprintable_area_in_obj_coord[idx]).empty()) {
|
||||
tbb_geometric_unprintables[idx].insert(wall_filament - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
std::vector<std::set<int>> ret(tbb_geometric_unprintables.size());
|
||||
for (size_t idx = 0; idx < ret.size(); ++idx)
|
||||
ret[idx] = std::set<int>(tbb_geometric_unprintables[idx].begin(), tbb_geometric_unprintables[idx].end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 1) Merges typed region slices into stInternal type.
|
||||
// 2) Increases an "extra perimeters" counter at region slices where needed.
|
||||
// 3) Generates perimeters, gap fills and fill regions (fill regions of type stInternal).
|
||||
|
@ -3055,7 +3142,7 @@ void PrintObject::get_certain_layers(float start, float end, std::vector<LayerPt
|
|||
out.emplace_back(std::move(out_temp));
|
||||
};
|
||||
|
||||
std::vector<Point> PrintObject::get_instances_shift_without_plate_offset()
|
||||
std::vector<Point> PrintObject::get_instances_shift_without_plate_offset() const
|
||||
{
|
||||
std::vector<Point> out;
|
||||
out.reserve(m_instances.size());
|
||||
|
|
Loading…
Reference in New Issue