mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-16 13:32:44 +00:00
.
This commit is contained in:
@@ -339,21 +339,32 @@ public:
|
|||||||
ExtrusionPaths paths;
|
ExtrusionPaths paths;
|
||||||
|
|
||||||
ExtrusionMultiPath() {}
|
ExtrusionMultiPath() {}
|
||||||
ExtrusionMultiPath(const ExtrusionMultiPath &rhs) : paths(rhs.paths), m_can_reverse(rhs.m_can_reverse) {}
|
ExtrusionMultiPath(const ExtrusionMultiPath &rhs) : ExtrusionEntity(rhs), paths(rhs.paths), m_can_reverse(rhs.m_can_reverse) {}
|
||||||
ExtrusionMultiPath(ExtrusionMultiPath &&rhs) : paths(std::move(rhs.paths)), m_can_reverse(rhs.m_can_reverse) {}
|
ExtrusionMultiPath(ExtrusionMultiPath &&rhs) : ExtrusionEntity(rhs), paths(std::move(rhs.paths)), m_can_reverse(rhs.m_can_reverse) {}
|
||||||
ExtrusionMultiPath(const ExtrusionPaths &paths) : paths(paths) {}
|
ExtrusionMultiPath(const ExtrusionPaths &paths) : paths(paths)
|
||||||
ExtrusionMultiPath(const ExtrusionPath &path) {this->paths.push_back(path); m_can_reverse = path.can_reverse(); }
|
{
|
||||||
|
if (!paths.empty())
|
||||||
|
this->inset_idx = paths.front().inset_idx;
|
||||||
|
}
|
||||||
|
ExtrusionMultiPath(const ExtrusionPath &path)
|
||||||
|
{
|
||||||
|
this->paths.push_back(path);
|
||||||
|
this->inset_idx = path.inset_idx;
|
||||||
|
m_can_reverse = path.can_reverse();
|
||||||
|
}
|
||||||
|
|
||||||
ExtrusionMultiPath &operator=(const ExtrusionMultiPath &rhs)
|
ExtrusionMultiPath &operator=(const ExtrusionMultiPath &rhs)
|
||||||
{
|
{
|
||||||
this->paths = rhs.paths;
|
this->paths = rhs.paths;
|
||||||
m_can_reverse = rhs.m_can_reverse;
|
this->inset_idx = rhs.inset_idx;
|
||||||
|
m_can_reverse = rhs.m_can_reverse;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
ExtrusionMultiPath &operator=(ExtrusionMultiPath &&rhs)
|
ExtrusionMultiPath &operator=(ExtrusionMultiPath &&rhs)
|
||||||
{
|
{
|
||||||
this->paths = std::move(rhs.paths);
|
this->paths = std::move(rhs.paths);
|
||||||
m_can_reverse = rhs.m_can_reverse;
|
this->inset_idx = rhs.inset_idx;
|
||||||
|
m_can_reverse = rhs.m_can_reverse;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,12 +415,27 @@ public:
|
|||||||
ExtrusionPaths paths;
|
ExtrusionPaths paths;
|
||||||
|
|
||||||
ExtrusionLoop(ExtrusionLoopRole role = elrDefault) : m_loop_role(role) {}
|
ExtrusionLoop(ExtrusionLoopRole role = elrDefault) : m_loop_role(role) {}
|
||||||
ExtrusionLoop(const ExtrusionPaths &paths, ExtrusionLoopRole role = elrDefault) : paths(paths), m_loop_role(role) {}
|
ExtrusionLoop(const ExtrusionPaths &paths, ExtrusionLoopRole role = elrDefault) : paths(paths), m_loop_role(role)
|
||||||
ExtrusionLoop(ExtrusionPaths &&paths, ExtrusionLoopRole role = elrDefault) : paths(std::move(paths)), m_loop_role(role) {}
|
{
|
||||||
|
if (!paths.empty())
|
||||||
|
this->inset_idx = paths.front().inset_idx;
|
||||||
|
}
|
||||||
|
ExtrusionLoop(ExtrusionPaths &&paths, ExtrusionLoopRole role = elrDefault) : paths(std::move(paths)), m_loop_role(role)
|
||||||
|
{
|
||||||
|
if (!this->paths.empty())
|
||||||
|
this->inset_idx = this->paths.front().inset_idx;
|
||||||
|
}
|
||||||
ExtrusionLoop(const ExtrusionPath &path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role)
|
ExtrusionLoop(const ExtrusionPath &path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role)
|
||||||
{ this->paths.push_back(path); }
|
{
|
||||||
|
this->paths.push_back(path);
|
||||||
|
this->inset_idx = path.inset_idx;
|
||||||
|
}
|
||||||
ExtrusionLoop(const ExtrusionPath &&path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role)
|
ExtrusionLoop(const ExtrusionPath &&path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role)
|
||||||
{ this->paths.emplace_back(std::move(path)); }
|
{
|
||||||
|
this->paths.emplace_back(std::move(path));
|
||||||
|
if (!this->paths.empty())
|
||||||
|
this->inset_idx = this->paths.front().inset_idx;
|
||||||
|
}
|
||||||
bool is_loop() const override{ return true; }
|
bool is_loop() const override{ return true; }
|
||||||
bool can_reverse() const override { return false; }
|
bool can_reverse() const override { return false; }
|
||||||
ExtrusionEntity* clone() const override{ return new ExtrusionLoop (*this); }
|
ExtrusionEntity* clone() const override{ return new ExtrusionLoop (*this); }
|
||||||
|
|||||||
+50
-22
@@ -4770,15 +4770,32 @@ LayerResult GCode::process_layer(const Print& print,
|
|||||||
auto configured_filament_id_1based = [&layer_tools](const GCode::ObjectByExtruder::Island::Region::Type entity_type,
|
auto configured_filament_id_1based = [&layer_tools](const GCode::ObjectByExtruder::Island::Region::Type entity_type,
|
||||||
const ExtrusionEntityCollection& entities,
|
const ExtrusionEntityCollection& entities,
|
||||||
const PrintRegion& region) -> unsigned int {
|
const PrintRegion& region) -> unsigned int {
|
||||||
|
auto raw_sparse_infill_filament_id_1based = [&layer_tools, ®ion]() -> unsigned int {
|
||||||
|
const PrintRegionConfig &config = region.config();
|
||||||
|
if (!config.enable_infill_filament_override.value)
|
||||||
|
return unsigned(config.wall_filament.value);
|
||||||
|
if (layer_tools.object_layer_count <= 0)
|
||||||
|
return unsigned(config.sparse_infill_filament.value);
|
||||||
|
|
||||||
|
const int first_layers = std::max(0, config.infill_filament_use_base_first_layers.value);
|
||||||
|
const int last_layers = std::max(0, config.infill_filament_use_base_last_layers.value);
|
||||||
|
return (layer_tools.layer_index < first_layers ||
|
||||||
|
layer_tools.layer_index >= layer_tools.object_layer_count - last_layers)
|
||||||
|
? unsigned(config.wall_filament.value)
|
||||||
|
: unsigned(config.sparse_infill_filament.value);
|
||||||
|
};
|
||||||
|
|
||||||
if (entity_type == GCode::ObjectByExtruder::Island::Region::INFILL) {
|
if (entity_type == GCode::ObjectByExtruder::Island::Region::INFILL) {
|
||||||
|
if (layer_tools.extruder_override != 0)
|
||||||
|
return layer_tools.extruder_override;
|
||||||
const ExtrusionRole role = entities.entities.empty() ? erNone : entities.entities.front()->role();
|
const ExtrusionRole role = entities.entities.empty() ? erNone : entities.entities.front()->role();
|
||||||
if (role == erSolidInfill && std::abs(region.config().sparse_infill_density.value - 100.) < EPSILON)
|
if (role == erSolidInfill && std::abs(region.config().sparse_infill_density.value - 100.) < EPSILON)
|
||||||
return layer_tools.sparse_infill_filament(region) + 1;
|
return raw_sparse_infill_filament_id_1based();
|
||||||
if (is_solid_infill(role))
|
if (is_solid_infill(role))
|
||||||
return layer_tools.solid_infill_filament(region) + 1;
|
return unsigned(region.config().solid_infill_filament.value);
|
||||||
return layer_tools.sparse_infill_filament(region) + 1;
|
return raw_sparse_infill_filament_id_1based();
|
||||||
}
|
}
|
||||||
return layer_tools.wall_filament(region) + 1;
|
return layer_tools.extruder_override == 0 ? unsigned(region.config().wall_filament.value) : layer_tools.extruder_override;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto configured_extruder_id = [&layer_tools](const GCode::ObjectByExtruder::Island::Region::Type entity_type,
|
auto configured_extruder_id = [&layer_tools](const GCode::ObjectByExtruder::Island::Region::Type entity_type,
|
||||||
@@ -5318,28 +5335,39 @@ LayerResult GCode::process_layer(const Print& print,
|
|||||||
layer_tools.num_physical,
|
layer_tools.num_physical,
|
||||||
layer_tools.layer_index,
|
layer_tools.layer_index,
|
||||||
split_by_extruder,
|
split_by_extruder,
|
||||||
bucket_count) &&
|
bucket_count)) {
|
||||||
bucket_count >= 2) {
|
if (bucket_count >= 2) {
|
||||||
for (size_t extruder_idx = 0; extruder_idx < split_by_extruder.size(); ++extruder_idx) {
|
for (size_t extruder_idx = 0; extruder_idx < split_by_extruder.size(); ++extruder_idx) {
|
||||||
std::unique_ptr<ExtrusionEntityCollection>& split_collection = split_by_extruder[extruder_idx];
|
std::unique_ptr<ExtrusionEntityCollection>& split_collection = split_by_extruder[extruder_idx];
|
||||||
if (!split_collection || split_collection->entities.empty())
|
if (!split_collection || split_collection->entities.empty())
|
||||||
continue;
|
continue;
|
||||||
const ExtrusionEntityCollection* split_ptr = split_collection.get();
|
const ExtrusionEntityCollection* split_ptr = split_collection.get();
|
||||||
local_z_clipped_collections.emplace_back(std::move(split_collection));
|
local_z_clipped_collections.emplace_back(std::move(split_collection));
|
||||||
std::vector<ObjectByExtruder::Island>& islands =
|
std::vector<ObjectByExtruder::Island>& islands =
|
||||||
object_islands_by_extruder(by_extruder, unsigned(extruder_idx), layer_to_print_idx, layers.size(), n_slices + 1);
|
object_islands_by_extruder(by_extruder, unsigned(extruder_idx), layer_to_print_idx, layers.size(), n_slices + 1);
|
||||||
for (size_t i = 0; i <= n_slices; ++i) {
|
for (size_t i = 0; i <= n_slices; ++i) {
|
||||||
const bool last = i == n_slices;
|
const bool last = i == n_slices;
|
||||||
const size_t island_idx = last ? n_slices : slices_test_order[i];
|
const size_t island_idx = last ? n_slices : slices_test_order[i];
|
||||||
if (last || point_inside_surface(island_idx, split_ptr->first_point())) {
|
if (last || point_inside_surface(island_idx, split_ptr->first_point())) {
|
||||||
if (islands[island_idx].by_region.empty())
|
if (islands[island_idx].by_region.empty())
|
||||||
islands[island_idx].by_region.assign(print.num_print_regions(), ObjectByExtruder::Island::Region());
|
islands[island_idx].by_region.assign(print.num_print_regions(), ObjectByExtruder::Island::Region());
|
||||||
islands[island_idx].by_region[region.print_region_id()].append(entity_type, split_ptr, nullptr);
|
islands[island_idx].by_region[region.print_region_id()].append(entity_type, split_ptr, nullptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (bucket_count == 1) {
|
||||||
|
for (size_t extruder_idx = 0; extruder_idx < split_by_extruder.size(); ++extruder_idx) {
|
||||||
|
const std::unique_ptr<ExtrusionEntityCollection>& split_collection = split_by_extruder[extruder_idx];
|
||||||
|
if (split_collection && !split_collection->entities.empty()) {
|
||||||
|
// by_extruder keys and LayerTools runtime extruder IDs are zero-based here.
|
||||||
|
correct_extruder_id = int(extruder_idx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,24 @@ unsigned int grouped_manual_pattern_mixed_filament_id_for_layer(const LayerTools
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int grouped_manual_pattern_infill_filament_1based(const LayerTools& layer_tools,
|
||||||
|
const PrintRegion& region,
|
||||||
|
unsigned int configured_filament_id_1based)
|
||||||
|
{
|
||||||
|
const unsigned int grouped_id =
|
||||||
|
grouped_manual_pattern_mixed_filament_id_for_layer(layer_tools, configured_filament_id_1based);
|
||||||
|
if (grouped_id == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const int innermost_perimeter_index = std::max(0, region.config().wall_loops.value - 1);
|
||||||
|
return layer_tools.mixed_mgr->resolve_perimeter(grouped_id,
|
||||||
|
layer_tools.num_physical,
|
||||||
|
layer_tools.layer_index,
|
||||||
|
innermost_perimeter_index,
|
||||||
|
float(layer_tools.print_z),
|
||||||
|
float(layer_tools.layer_height));
|
||||||
|
}
|
||||||
|
|
||||||
void remove_duplicates_preserve_order(std::vector<unsigned int> &values)
|
void remove_duplicates_preserve_order(std::vector<unsigned int> &values)
|
||||||
{
|
{
|
||||||
std::vector<unsigned int> ordered;
|
std::vector<unsigned int> ordered;
|
||||||
@@ -279,14 +297,16 @@ unsigned int LayerTools::sparse_infill_filament(const PrintRegion ®ion) const
|
|||||||
{
|
{
|
||||||
assert(region.config().wall_filament.value > 0);
|
assert(region.config().wall_filament.value > 0);
|
||||||
unsigned int id = (this->extruder_override == 0) ? sparse_infill_filament_id_1based(*this, region) : this->extruder_override;
|
unsigned int id = (this->extruder_override == 0) ? sparse_infill_filament_id_1based(*this, region) : this->extruder_override;
|
||||||
return resolve_mixed_1based(id) - 1;
|
const unsigned int grouped = grouped_manual_pattern_infill_filament_1based(*this, region, id);
|
||||||
|
return ((grouped != 0) ? grouped : resolve_mixed_1based(id)) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int LayerTools::solid_infill_filament(const PrintRegion ®ion) const
|
unsigned int LayerTools::solid_infill_filament(const PrintRegion ®ion) const
|
||||||
{
|
{
|
||||||
assert(region.config().solid_infill_filament.value > 0);
|
assert(region.config().solid_infill_filament.value > 0);
|
||||||
unsigned int id = (this->extruder_override == 0) ? region.config().solid_infill_filament.value : this->extruder_override;
|
unsigned int id = (this->extruder_override == 0) ? region.config().solid_infill_filament.value : this->extruder_override;
|
||||||
return resolve_mixed_1based(id) - 1;
|
const unsigned int grouped = grouped_manual_pattern_infill_filament_1based(*this, region, id);
|
||||||
|
return ((grouped != 0) ? grouped : resolve_mixed_1based(id)) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden.
|
// Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden.
|
||||||
@@ -295,19 +315,13 @@ unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, c
|
|||||||
assert(region.config().wall_filament.value > 0);
|
assert(region.config().wall_filament.value > 0);
|
||||||
assert(region.config().sparse_infill_filament.value > 0);
|
assert(region.config().sparse_infill_filament.value > 0);
|
||||||
assert(region.config().solid_infill_filament.value > 0);
|
assert(region.config().solid_infill_filament.value > 0);
|
||||||
// 1 based extruder ID.
|
if (extrusions.has_infill()) {
|
||||||
unsigned int extruder = 1;
|
const ExtrusionRole role = extrusions.entities.empty() ? erNone : extrusions.entities.front()->role();
|
||||||
if (this->extruder_override == 0) {
|
if (internal_solid_infill_uses_sparse_filament(region, role))
|
||||||
if (extrusions.has_infill()) {
|
return sparse_infill_filament(region);
|
||||||
const ExtrusionRole role = extrusions.entities.empty() ? erNone : extrusions.entities.front()->role();
|
return is_solid_infill(role) ? solid_infill_filament(region) : sparse_infill_filament(region);
|
||||||
extruder = infill_filament_id_1based(*this, region, role);
|
}
|
||||||
} else
|
return wall_filament(region);
|
||||||
extruder = region.config().wall_filament.value;
|
|
||||||
} else
|
|
||||||
extruder = this->extruder_override;
|
|
||||||
|
|
||||||
extruder = resolve_mixed_1based(extruder);
|
|
||||||
return (extruder == 0) ? 0 : extruder - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static double calc_max_layer_height(const PrintConfig &config, double max_object_layer_height)
|
static double calc_max_layer_height(const PrintConfig &config, double max_object_layer_height)
|
||||||
@@ -718,8 +732,9 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
|||||||
layerCount,
|
layerCount,
|
||||||
float(layer->print_z),
|
float(layer->print_z),
|
||||||
float(layer->height));
|
float(layer->height));
|
||||||
if (ordered.size() >= 2) {
|
if (!ordered.empty()) {
|
||||||
layer_tools.preserve_extruder_order = true;
|
if (ordered.size() >= 2)
|
||||||
|
layer_tools.preserve_extruder_order = true;
|
||||||
for (unsigned int extruder_id : ordered) {
|
for (unsigned int extruder_id : ordered) {
|
||||||
layer_tools.extruders.emplace_back(extruder_id);
|
layer_tools.extruders.emplace_back(extruder_id);
|
||||||
if (layerCount == 0 &&
|
if (layerCount == 0 &&
|
||||||
@@ -764,10 +779,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
|||||||
if (something_nonoverriddable || !m_print_config_ptr) {
|
if (something_nonoverriddable || !m_print_config_ptr) {
|
||||||
if (extruder_override == 0) {
|
if (extruder_override == 0) {
|
||||||
if (has_solid_infill)
|
if (has_solid_infill)
|
||||||
layer_tools.extruders.emplace_back(resolve_mixed(region.config().solid_infill_filament,
|
layer_tools.extruders.emplace_back(layer_tools.solid_infill_filament(region) + 1);
|
||||||
layerCount,
|
|
||||||
float(layer->print_z),
|
|
||||||
float(layer->height)));
|
|
||||||
if (has_sparse_infill)
|
if (has_sparse_infill)
|
||||||
layer_tools.extruders.emplace_back(layer_tools.sparse_infill_filament(region) + 1);
|
layer_tools.extruders.emplace_back(layer_tools.sparse_infill_filament(region) + 1);
|
||||||
} else if (has_solid_infill || has_sparse_infill)
|
} else if (has_solid_infill || has_sparse_infill)
|
||||||
|
|||||||
@@ -46,6 +46,39 @@ unsigned int effective_layer_filament_id(const Layer &layer, unsigned int filame
|
|||||||
float(layer.height));
|
float(layer.height));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int effective_infill_filament_id(const Layer &layer, const PrintRegionConfig &config, unsigned int filament_id)
|
||||||
|
{
|
||||||
|
const unsigned int effective = effective_layer_filament_id(layer, filament_id);
|
||||||
|
if (effective != filament_id || filament_id == 0)
|
||||||
|
return effective;
|
||||||
|
|
||||||
|
const PrintObject *object = layer.object();
|
||||||
|
const Print *print = object ? object->print() : nullptr;
|
||||||
|
if (print == nullptr)
|
||||||
|
return filament_id;
|
||||||
|
|
||||||
|
const size_t num_physical = print->config().filament_diameter.size();
|
||||||
|
if (num_physical == 0)
|
||||||
|
return filament_id;
|
||||||
|
|
||||||
|
const MixedFilamentManager &mixed_mgr = print->mixed_filament_manager();
|
||||||
|
const MixedFilament *mixed_row = mixed_mgr.mixed_filament_from_id(filament_id, num_physical);
|
||||||
|
if (mixed_row == nullptr)
|
||||||
|
return filament_id;
|
||||||
|
|
||||||
|
const std::string normalized_pattern = MixedFilamentManager::normalize_manual_pattern(mixed_row->manual_pattern);
|
||||||
|
if (normalized_pattern.find(',') == std::string::npos)
|
||||||
|
return filament_id;
|
||||||
|
|
||||||
|
const int innermost_perimeter_index = std::max(0, config.wall_loops.value - 1);
|
||||||
|
return mixed_mgr.resolve_perimeter(filament_id,
|
||||||
|
num_physical,
|
||||||
|
int(layer.id()),
|
||||||
|
innermost_perimeter_index,
|
||||||
|
float(layer.print_z),
|
||||||
|
float(layer.height));
|
||||||
|
}
|
||||||
|
|
||||||
bool use_base_infill_filament(const PrintRegionConfig &config, int layer_index, int layer_count)
|
bool use_base_infill_filament(const PrintRegionConfig &config, int layer_index, int layer_count)
|
||||||
{
|
{
|
||||||
if (!config.enable_infill_filament_override.value)
|
if (!config.enable_infill_filament_override.value)
|
||||||
@@ -71,7 +104,9 @@ unsigned int LayerRegion::extruder(FlowRole role) const
|
|||||||
else
|
else
|
||||||
filament_id = this->region().extruder(role);
|
filament_id = this->region().extruder(role);
|
||||||
|
|
||||||
return effective_layer_filament_id(*m_layer, filament_id);
|
return (role == frInfill || role == frSolidInfill) ?
|
||||||
|
effective_infill_filament_id(*m_layer, config, filament_id) :
|
||||||
|
effective_layer_filament_id(*m_layer, filament_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Flow LayerRegion::flow(FlowRole role) const
|
Flow LayerRegion::flow(FlowRole role) const
|
||||||
|
|||||||
@@ -570,6 +570,10 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
|
|||||||
|
|
||||||
// Append paths to collection.
|
// Append paths to collection.
|
||||||
if (!paths.empty()) {
|
if (!paths.empty()) {
|
||||||
|
const int inset_idx = int(extrusion->inset_idx);
|
||||||
|
for (ExtrusionPath &path : paths)
|
||||||
|
path.inset_idx = inset_idx;
|
||||||
|
|
||||||
if (extrusion->is_closed) {
|
if (extrusion->is_closed) {
|
||||||
ExtrusionLoop extrusion_loop(std::move(paths), pg_extrusion.is_contour ? elrDefault : elrHole);
|
ExtrusionLoop extrusion_loop(std::move(paths), pg_extrusion.is_contour ? elrDefault : elrHole);
|
||||||
extrusion_loop.make_counter_clockwise();
|
extrusion_loop.make_counter_clockwise();
|
||||||
@@ -581,6 +585,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
|
|||||||
}
|
}
|
||||||
assert(extrusion_loop.paths.front().first_point() == extrusion_loop.paths.back().last_point());
|
assert(extrusion_loop.paths.front().first_point() == extrusion_loop.paths.back().last_point());
|
||||||
|
|
||||||
|
extrusion_loop.inset_idx = inset_idx;
|
||||||
extrusion_coll.append(std::move(extrusion_loop));
|
extrusion_coll.append(std::move(extrusion_loop));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -593,11 +598,13 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p
|
|||||||
}
|
}
|
||||||
ExtrusionMultiPath multi_path;
|
ExtrusionMultiPath multi_path;
|
||||||
multi_path.paths.emplace_back(std::move(paths.front()));
|
multi_path.paths.emplace_back(std::move(paths.front()));
|
||||||
|
multi_path.inset_idx = inset_idx;
|
||||||
|
|
||||||
for (auto it_path = std::next(paths.begin()); it_path != paths.end(); ++it_path) {
|
for (auto it_path = std::next(paths.begin()); it_path != paths.end(); ++it_path) {
|
||||||
if (multi_path.paths.back().last_point() != it_path->first_point()) {
|
if (multi_path.paths.back().last_point() != it_path->first_point()) {
|
||||||
extrusion_coll.append(ExtrusionMultiPath(std::move(multi_path)));
|
extrusion_coll.append(ExtrusionMultiPath(std::move(multi_path)));
|
||||||
multi_path = ExtrusionMultiPath();
|
multi_path = ExtrusionMultiPath();
|
||||||
|
multi_path.inset_idx = inset_idx;
|
||||||
}
|
}
|
||||||
multi_path.paths.emplace_back(std::move(*it_path));
|
multi_path.paths.emplace_back(std::move(*it_path));
|
||||||
}
|
}
|
||||||
|
|||||||
+130
-31
@@ -4566,6 +4566,7 @@ struct MixedFilamentPreviewSettings
|
|||||||
double preferred_a_height { 0.0 };
|
double preferred_a_height { 0.0 };
|
||||||
double preferred_b_height { 0.0 };
|
double preferred_b_height { 0.0 };
|
||||||
bool local_z_mode { false };
|
bool local_z_mode { false };
|
||||||
|
size_t wall_loops { 1 };
|
||||||
};
|
};
|
||||||
|
|
||||||
// Inline editor panel for configuring a single mixed filament
|
// Inline editor panel for configuring a single mixed filament
|
||||||
@@ -4634,7 +4635,11 @@ private:
|
|||||||
// Helper functions (copied from update_mixed_filament_panel)
|
// Helper functions (copied from update_mixed_filament_panel)
|
||||||
static std::vector<unsigned int> decode_gradient_ids(const std::string &s);
|
static std::vector<unsigned int> decode_gradient_ids(const std::string &s);
|
||||||
static std::string encode_gradient_ids(const std::vector<unsigned int> &ids);
|
static std::string encode_gradient_ids(const std::vector<unsigned int> &ids);
|
||||||
static std::vector<unsigned int> decode_manual_pattern_ids(const std::string &pattern, unsigned int a, unsigned int b);
|
static std::vector<unsigned int> decode_manual_pattern_ids(const std::string &pattern,
|
||||||
|
unsigned int a,
|
||||||
|
unsigned int b,
|
||||||
|
size_t num_physical,
|
||||||
|
size_t wall_loops = 0);
|
||||||
static std::vector<int> decode_gradient_weights(const std::string &s, size_t n);
|
static std::vector<int> decode_gradient_weights(const std::string &s, size_t n);
|
||||||
static std::vector<int> normalize_gradient_weights(const std::vector<int> &w, size_t n);
|
static std::vector<int> normalize_gradient_weights(const std::vector<int> &w, size_t n);
|
||||||
static std::string encode_gradient_weights(const std::vector<int> &w);
|
static std::string encode_gradient_weights(const std::vector<int> &w);
|
||||||
@@ -4784,6 +4789,100 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Implementation of MixedFilamentConfigPanel helper functions
|
// Implementation of MixedFilamentConfigPanel helper functions
|
||||||
|
static std::vector<std::string> split_manual_pattern_preview_groups(const std::string &pattern)
|
||||||
|
{
|
||||||
|
std::vector<std::string> groups;
|
||||||
|
if (pattern.empty())
|
||||||
|
return groups;
|
||||||
|
|
||||||
|
std::string current;
|
||||||
|
for (const char c : pattern) {
|
||||||
|
if (c == ',') {
|
||||||
|
if (!current.empty()) {
|
||||||
|
groups.emplace_back(std::move(current));
|
||||||
|
current.clear();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
current.push_back(c);
|
||||||
|
}
|
||||||
|
if (!current.empty())
|
||||||
|
groups.emplace_back(std::move(current));
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int decode_manual_pattern_preview_token(char token, unsigned int component_a, unsigned int component_b, size_t num_physical)
|
||||||
|
{
|
||||||
|
unsigned int extruder_id = 0;
|
||||||
|
if (token == '1')
|
||||||
|
extruder_id = component_a;
|
||||||
|
else if (token == '2')
|
||||||
|
extruder_id = component_b;
|
||||||
|
else if (token >= '3' && token <= '9')
|
||||||
|
extruder_id = unsigned(token - '0');
|
||||||
|
|
||||||
|
return (extruder_id >= 1 && extruder_id <= num_physical) ? extruder_id : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<unsigned int> build_grouped_manual_pattern_preview_sequence(const std::string &pattern,
|
||||||
|
unsigned int component_a,
|
||||||
|
unsigned int component_b,
|
||||||
|
size_t num_physical,
|
||||||
|
size_t wall_loops)
|
||||||
|
{
|
||||||
|
std::vector<unsigned int> sequence;
|
||||||
|
if (num_physical == 0)
|
||||||
|
return sequence;
|
||||||
|
|
||||||
|
const std::string normalized = MixedFilamentManager::normalize_manual_pattern(pattern);
|
||||||
|
if (normalized.empty())
|
||||||
|
return sequence;
|
||||||
|
|
||||||
|
const std::vector<std::string> groups = split_manual_pattern_preview_groups(normalized);
|
||||||
|
if (groups.empty())
|
||||||
|
return sequence;
|
||||||
|
|
||||||
|
if (groups.size() == 1) {
|
||||||
|
sequence.reserve(normalized.size());
|
||||||
|
for (const char token : normalized) {
|
||||||
|
const unsigned int extruder_id =
|
||||||
|
decode_manual_pattern_preview_token(token, component_a, component_b, num_physical);
|
||||||
|
if (extruder_id != 0)
|
||||||
|
sequence.emplace_back(extruder_id);
|
||||||
|
}
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t k_max_preview_cycle = 48;
|
||||||
|
size_t cycle = 1;
|
||||||
|
for (const std::string &group : groups) {
|
||||||
|
if (group.empty())
|
||||||
|
continue;
|
||||||
|
cycle = std::lcm(cycle, group.size());
|
||||||
|
if (cycle >= k_max_preview_cycle) {
|
||||||
|
cycle = k_max_preview_cycle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t preview_wall_loops = std::max<size_t>(1, wall_loops == 0 ? groups.size() : wall_loops);
|
||||||
|
sequence.reserve(preview_wall_loops * cycle);
|
||||||
|
for (size_t layer_idx = 0; layer_idx < cycle; ++layer_idx) {
|
||||||
|
for (size_t wall_idx = 0; wall_idx < preview_wall_loops; ++wall_idx) {
|
||||||
|
const std::string &group = groups[std::min(wall_idx, groups.size() - 1)];
|
||||||
|
if (group.empty())
|
||||||
|
continue;
|
||||||
|
const char token = group[layer_idx % group.size()];
|
||||||
|
const unsigned int extruder_id =
|
||||||
|
decode_manual_pattern_preview_token(token, component_a, component_b, num_physical);
|
||||||
|
if (extruder_id != 0)
|
||||||
|
sequence.emplace_back(extruder_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<unsigned int> MixedFilamentConfigPanel::decode_gradient_ids(const std::string &s)
|
std::vector<unsigned int> MixedFilamentConfigPanel::decode_gradient_ids(const std::string &s)
|
||||||
{
|
{
|
||||||
std::vector<unsigned int> ids;
|
std::vector<unsigned int> ids;
|
||||||
@@ -4816,15 +4915,13 @@ std::string MixedFilamentConfigPanel::encode_gradient_ids(const std::vector<unsi
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned int> MixedFilamentConfigPanel::decode_manual_pattern_ids(const std::string &pattern, unsigned int a, unsigned int b)
|
std::vector<unsigned int> MixedFilamentConfigPanel::decode_manual_pattern_ids(const std::string &pattern,
|
||||||
|
unsigned int a,
|
||||||
|
unsigned int b,
|
||||||
|
size_t num_physical,
|
||||||
|
size_t wall_loops)
|
||||||
{
|
{
|
||||||
std::vector<unsigned int> seq;
|
return build_grouped_manual_pattern_preview_sequence(pattern, a, b, num_physical, wall_loops);
|
||||||
for (char c : pattern) {
|
|
||||||
if (c == '1' || c == 'A' || c == 'a') seq.emplace_back(a);
|
|
||||||
else if (c == '2' || c == 'B' || c == 'b') seq.emplace_back(b);
|
|
||||||
else if (c >= '3' && c <= '9') seq.emplace_back(unsigned(c - '0'));
|
|
||||||
}
|
|
||||||
return seq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> MixedFilamentConfigPanel::decode_gradient_weights(const std::string &s, size_t n)
|
std::vector<int> MixedFilamentConfigPanel::decode_gradient_weights(const std::string &s, size_t n)
|
||||||
@@ -5947,7 +6044,11 @@ void MixedFilamentConfigPanel::build_ui()
|
|||||||
m_mf.pointillism_all_filaments = false;
|
m_mf.pointillism_all_filaments = false;
|
||||||
m_mf.gradient_component_ids.clear();
|
m_mf.gradient_component_ids.clear();
|
||||||
m_mf.gradient_component_weights.clear();
|
m_mf.gradient_component_weights.clear();
|
||||||
preview_sequence = decode_manual_pattern_ids(m_mf.manual_pattern, m_mf.component_a, m_mf.component_b);
|
preview_sequence = decode_manual_pattern_ids(m_mf.manual_pattern,
|
||||||
|
m_mf.component_a,
|
||||||
|
m_mf.component_b,
|
||||||
|
m_num_physical,
|
||||||
|
m_preview_settings.wall_loops);
|
||||||
} else {
|
} else {
|
||||||
std::vector<unsigned int> selected_ids;
|
std::vector<unsigned int> selected_ids;
|
||||||
selected_ids.reserve(4);
|
selected_ids.reserve(4);
|
||||||
@@ -6254,7 +6355,11 @@ void MixedFilamentConfigPanel::update_preview()
|
|||||||
|
|
||||||
std::vector<unsigned int> initial_sequence;
|
std::vector<unsigned int> initial_sequence;
|
||||||
if (pattern_row_mode) {
|
if (pattern_row_mode) {
|
||||||
initial_sequence = decode_manual_pattern_ids(normalized_pattern, m_mf.component_a, m_mf.component_b);
|
initial_sequence = decode_manual_pattern_ids(normalized_pattern,
|
||||||
|
m_mf.component_a,
|
||||||
|
m_mf.component_b,
|
||||||
|
m_num_physical,
|
||||||
|
m_preview_settings.wall_loops);
|
||||||
} else {
|
} else {
|
||||||
std::vector<unsigned int> initial_gradient_ids = simple_mode ? std::vector<unsigned int>() : decode_gradient_ids(m_mf.gradient_component_ids);
|
std::vector<unsigned int> initial_gradient_ids = simple_mode ? std::vector<unsigned int>() : decode_gradient_ids(m_mf.gradient_component_ids);
|
||||||
if (initial_gradient_ids.size() >= 3)
|
if (initial_gradient_ids.size() >= 3)
|
||||||
@@ -6707,24 +6812,11 @@ void Sidebar::update_mixed_filament_panel(bool sync_manager)
|
|||||||
sequence = filtered_ids;
|
sequence = filtered_ids;
|
||||||
return sequence;
|
return sequence;
|
||||||
};
|
};
|
||||||
auto decode_manual_pattern_ids = [num_physical](const std::string &pattern, unsigned int component_a, unsigned int component_b) {
|
auto decode_manual_pattern_ids = [num_physical](const std::string &pattern,
|
||||||
std::vector<unsigned int> sequence;
|
unsigned int component_a,
|
||||||
if (num_physical == 0)
|
unsigned int component_b,
|
||||||
return sequence;
|
size_t wall_loops) {
|
||||||
const std::string normalized = MixedFilamentManager::normalize_manual_pattern(pattern);
|
return build_grouped_manual_pattern_preview_sequence(pattern, component_a, component_b, num_physical, wall_loops);
|
||||||
sequence.reserve(normalized.size());
|
|
||||||
for (const char token : normalized) {
|
|
||||||
unsigned int extruder_id = 0;
|
|
||||||
if (token == '1')
|
|
||||||
extruder_id = component_a;
|
|
||||||
else if (token == '2')
|
|
||||||
extruder_id = component_b;
|
|
||||||
else if (token >= '3' && token <= '9')
|
|
||||||
extruder_id = unsigned(token - '0');
|
|
||||||
if (extruder_id >= 1 && extruder_id <= num_physical)
|
|
||||||
sequence.emplace_back(extruder_id);
|
|
||||||
}
|
|
||||||
return sequence;
|
|
||||||
};
|
};
|
||||||
const bool height_weighted_mode = get_mixed_mode(false);
|
const bool height_weighted_mode = get_mixed_mode(false);
|
||||||
int gradient_mode = height_weighted_mode ? 1 : 0;
|
int gradient_mode = height_weighted_mode ? 1 : 0;
|
||||||
@@ -6736,6 +6828,9 @@ void Sidebar::update_mixed_filament_panel(bool sync_manager)
|
|||||||
if (print_cfg && print_cfg->has("layer_height"))
|
if (print_cfg && print_cfg->has("layer_height"))
|
||||||
nominal_layer_height = float(print_cfg->opt_float("layer_height"));
|
nominal_layer_height = float(print_cfg->opt_float("layer_height"));
|
||||||
nominal_layer_height = std::max(0.01f, nominal_layer_height);
|
nominal_layer_height = std::max(0.01f, nominal_layer_height);
|
||||||
|
size_t wall_loops = 1;
|
||||||
|
if (print_cfg && print_cfg->has("wall_loops"))
|
||||||
|
wall_loops = std::max<size_t>(1, size_t(std::max(1, print_cfg->opt_int("wall_loops"))));
|
||||||
const bool local_z_mode = get_mixed_bool("dithering_local_z_mode", false);
|
const bool local_z_mode = get_mixed_bool("dithering_local_z_mode", false);
|
||||||
float pointillism_pixel_size = std::max(0.f, get_mixed_float("mixed_filament_pointillism_pixel_size", 0.f));
|
float pointillism_pixel_size = std::max(0.f, get_mixed_float("mixed_filament_pointillism_pixel_size", 0.f));
|
||||||
float pointillism_line_gap = std::max(0.f, get_mixed_float("mixed_filament_pointillism_line_gap", 0.f));
|
float pointillism_line_gap = std::max(0.f, get_mixed_float("mixed_filament_pointillism_line_gap", 0.f));
|
||||||
@@ -6748,7 +6843,8 @@ void Sidebar::update_mixed_filament_panel(bool sync_manager)
|
|||||||
upper_bound,
|
upper_bound,
|
||||||
preferred_local_z_a,
|
preferred_local_z_a,
|
||||||
preferred_local_z_b,
|
preferred_local_z_b,
|
||||||
local_z_mode
|
local_z_mode,
|
||||||
|
wall_loops
|
||||||
};
|
};
|
||||||
auto summarize_sequence = [num_physical](const std::vector<unsigned int> &sequence) {
|
auto summarize_sequence = [num_physical](const std::vector<unsigned int> &sequence) {
|
||||||
if (sequence.empty() || num_physical == 0)
|
if (sequence.empty() || num_physical == 0)
|
||||||
@@ -6814,7 +6910,10 @@ void Sidebar::update_mixed_filament_panel(bool sync_manager)
|
|||||||
build_weighted_multi_sequence, preview_settings](const MixedFilament &entry) {
|
build_weighted_multi_sequence, preview_settings](const MixedFilament &entry) {
|
||||||
const std::string normalized_pattern = MixedFilamentManager::normalize_manual_pattern(entry.manual_pattern);
|
const std::string normalized_pattern = MixedFilamentManager::normalize_manual_pattern(entry.manual_pattern);
|
||||||
if (!normalized_pattern.empty())
|
if (!normalized_pattern.empty())
|
||||||
return decode_manual_pattern_ids(normalized_pattern, entry.component_a, entry.component_b);
|
return decode_manual_pattern_ids(normalized_pattern,
|
||||||
|
entry.component_a,
|
||||||
|
entry.component_b,
|
||||||
|
preview_settings.wall_loops);
|
||||||
|
|
||||||
const bool simple_mode = entry.distribution_mode == int(MixedFilament::Simple);
|
const bool simple_mode = entry.distribution_mode == int(MixedFilament::Simple);
|
||||||
if (!simple_mode) {
|
if (!simple_mode) {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "libslic3r/ExtrusionEntity.hpp"
|
#include "libslic3r/ExtrusionEntity.hpp"
|
||||||
#include "libslic3r/PresetBundle.hpp"
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
|
#include "libslic3r/Print.hpp"
|
||||||
|
#include "libslic3r/GCode/ToolOrdering.hpp"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -221,6 +223,119 @@ TEST_CASE("Mixed filament perimeter resolver uses grouped manual patterns by ins
|
|||||||
CHECK(ordered_layer1[1] == 1);
|
CHECK(ordered_layer1[1] == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Grouped manual perimeter patterns keep grouped resolution on collapsed single-tool layers", "[MixedFilament]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> colors = {"#00FFFF", "#FF00FF"};
|
||||||
|
|
||||||
|
MixedFilamentManager mgr;
|
||||||
|
mgr.add_custom_filament(1, 2, 50, colors);
|
||||||
|
REQUIRE(mgr.mixed_filaments().size() == 1);
|
||||||
|
|
||||||
|
MixedFilament &row = mgr.mixed_filaments().front();
|
||||||
|
row.manual_pattern = MixedFilamentManager::normalize_manual_pattern("2,12");
|
||||||
|
REQUIRE(row.manual_pattern == "2,12");
|
||||||
|
|
||||||
|
const unsigned int mixed_filament_id = 3;
|
||||||
|
|
||||||
|
// The flattened row cadence resolves this layer to component A, but both
|
||||||
|
// perimeter groups collapse onto physical filament 2. G-code generation
|
||||||
|
// and tool ordering must keep using the grouped perimeter result here.
|
||||||
|
CHECK(mgr.resolve(mixed_filament_id, 2, 1) == 1);
|
||||||
|
|
||||||
|
const std::vector<unsigned int> ordered_layer1 = mgr.ordered_perimeter_extruders(mixed_filament_id, 2, 1);
|
||||||
|
REQUIRE(ordered_layer1.size() == 1);
|
||||||
|
CHECK(ordered_layer1.front() == 2);
|
||||||
|
|
||||||
|
CHECK(mgr.resolve_perimeter(mixed_filament_id, 2, 1, 0) == 2);
|
||||||
|
CHECK(mgr.resolve_perimeter(mixed_filament_id, 2, 1, 1) == 2);
|
||||||
|
CHECK(mgr.resolve_perimeter(mixed_filament_id, 2, 1, 2) == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Grouped manual perimeter patterns resolve overlapping singleton inner groups", "[MixedFilament]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> colors = {"#00FFFF", "#FF00FF"};
|
||||||
|
|
||||||
|
MixedFilamentManager mgr;
|
||||||
|
mgr.add_custom_filament(1, 2, 50, colors);
|
||||||
|
REQUIRE(mgr.mixed_filaments().size() == 1);
|
||||||
|
|
||||||
|
MixedFilament &row = mgr.mixed_filaments().front();
|
||||||
|
row.manual_pattern = MixedFilamentManager::normalize_manual_pattern("12,1");
|
||||||
|
REQUIRE(row.manual_pattern == "12,1");
|
||||||
|
|
||||||
|
const unsigned int mixed_filament_id = 3;
|
||||||
|
|
||||||
|
const std::vector<unsigned int> ordered_layer0 = mgr.ordered_perimeter_extruders(mixed_filament_id, 2, 0);
|
||||||
|
const std::vector<unsigned int> ordered_layer1 = mgr.ordered_perimeter_extruders(mixed_filament_id, 2, 1);
|
||||||
|
|
||||||
|
REQUIRE(ordered_layer0.size() == 1);
|
||||||
|
CHECK(ordered_layer0.front() == 1);
|
||||||
|
REQUIRE(ordered_layer1.size() == 2);
|
||||||
|
CHECK(ordered_layer1[0] == 2);
|
||||||
|
CHECK(ordered_layer1[1] == 1);
|
||||||
|
|
||||||
|
CHECK(mgr.resolve_perimeter(mixed_filament_id, 2, 0, 0) == 1);
|
||||||
|
CHECK(mgr.resolve_perimeter(mixed_filament_id, 2, 0, 1) == 1);
|
||||||
|
CHECK(mgr.resolve_perimeter(mixed_filament_id, 2, 1, 0) == 2);
|
||||||
|
CHECK(mgr.resolve_perimeter(mixed_filament_id, 2, 1, 1) == 1);
|
||||||
|
CHECK(mgr.resolve_perimeter(mixed_filament_id, 2, 2, 0) == 1);
|
||||||
|
CHECK(mgr.resolve_perimeter(mixed_filament_id, 2, 2, 1) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Grouped manual wall patterns make infill follow the innermost perimeter tool", "[MixedFilament]")
|
||||||
|
{
|
||||||
|
const std::vector<std::string> colors = {"#00FFFF", "#FF00FF"};
|
||||||
|
|
||||||
|
MixedFilamentManager mgr;
|
||||||
|
mgr.add_custom_filament(1, 2, 50, colors);
|
||||||
|
REQUIRE(mgr.mixed_filaments().size() == 1);
|
||||||
|
|
||||||
|
MixedFilament &row = mgr.mixed_filaments().front();
|
||||||
|
row.manual_pattern = MixedFilamentManager::normalize_manual_pattern("12,1");
|
||||||
|
REQUIRE(row.manual_pattern == "12,1");
|
||||||
|
|
||||||
|
PrintRegionConfig region_config = static_cast<const PrintRegionConfig &>(FullPrintConfig::defaults());
|
||||||
|
region_config.wall_filament.value = 3;
|
||||||
|
region_config.wall_loops.value = 2;
|
||||||
|
region_config.enable_infill_filament_override.value = false;
|
||||||
|
region_config.sparse_infill_density.value = 15.;
|
||||||
|
region_config.sparse_infill_filament.value = 2;
|
||||||
|
region_config.solid_infill_filament.value = 3;
|
||||||
|
|
||||||
|
PrintRegion region(region_config);
|
||||||
|
|
||||||
|
LayerTools layer0(0.2);
|
||||||
|
layer0.layer_index = 0;
|
||||||
|
layer0.object_layer_count = 6;
|
||||||
|
layer0.layer_height = 0.2;
|
||||||
|
layer0.mixed_mgr = &mgr;
|
||||||
|
layer0.num_physical = 2;
|
||||||
|
|
||||||
|
LayerTools layer1(0.4);
|
||||||
|
layer1.layer_index = 1;
|
||||||
|
layer1.object_layer_count = 6;
|
||||||
|
layer1.layer_height = 0.2;
|
||||||
|
layer1.mixed_mgr = &mgr;
|
||||||
|
layer1.num_physical = 2;
|
||||||
|
|
||||||
|
CHECK(layer0.wall_filament(region) == 0);
|
||||||
|
CHECK(layer1.wall_filament(region) == 1);
|
||||||
|
CHECK(layer0.sparse_infill_filament(region) == 0);
|
||||||
|
CHECK(layer1.sparse_infill_filament(region) == 0);
|
||||||
|
CHECK(layer0.solid_infill_filament(region) == 0);
|
||||||
|
CHECK(layer1.solid_infill_filament(region) == 0);
|
||||||
|
|
||||||
|
region_config.enable_infill_filament_override.value = true;
|
||||||
|
region_config.sparse_infill_filament.value = 2;
|
||||||
|
region_config.solid_infill_filament.value = 2;
|
||||||
|
PrintRegion overridden_region(region_config);
|
||||||
|
|
||||||
|
CHECK(layer0.sparse_infill_filament(overridden_region) == 1);
|
||||||
|
CHECK(layer1.sparse_infill_filament(overridden_region) == 1);
|
||||||
|
CHECK(layer0.solid_infill_filament(overridden_region) == 1);
|
||||||
|
CHECK(layer1.solid_infill_filament(overridden_region) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Mixed filament painted-region resolver collapses ordinary mixed rows to the active physical extruder", "[MixedFilament]")
|
TEST_CASE("Mixed filament painted-region resolver collapses ordinary mixed rows to the active physical extruder", "[MixedFilament]")
|
||||||
{
|
{
|
||||||
const std::vector<std::string> colors = {"#FF0000", "#00FF00"};
|
const std::vector<std::string> colors = {"#FF0000", "#00FF00"};
|
||||||
@@ -269,3 +384,26 @@ TEST_CASE("ExtrusionPath copies preserve inset index", "[MixedFilament]")
|
|||||||
assigned = src;
|
assigned = src;
|
||||||
CHECK(assigned.inset_idx == 3);
|
CHECK(assigned.inset_idx == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Extrusion loop and multipath entities preserve inset index", "[MixedFilament]")
|
||||||
|
{
|
||||||
|
ExtrusionPath src(erPerimeter);
|
||||||
|
src.inset_idx = 2;
|
||||||
|
|
||||||
|
ExtrusionMultiPath multi_from_path(src);
|
||||||
|
CHECK(multi_from_path.inset_idx == 2);
|
||||||
|
|
||||||
|
ExtrusionMultiPath multi_copy(multi_from_path);
|
||||||
|
CHECK(multi_copy.inset_idx == 2);
|
||||||
|
|
||||||
|
ExtrusionMultiPath multi_assigned;
|
||||||
|
multi_assigned.inset_idx = 0;
|
||||||
|
multi_assigned = multi_from_path;
|
||||||
|
CHECK(multi_assigned.inset_idx == 2);
|
||||||
|
|
||||||
|
ExtrusionLoop loop_from_path(src);
|
||||||
|
CHECK(loop_from_path.inset_idx == 2);
|
||||||
|
|
||||||
|
ExtrusionLoop loop_copy(loop_from_path);
|
||||||
|
CHECK(loop_copy.inset_idx == 2);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user