mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-25 10:57:53 +00:00
Fix belt purge tower activation and placement safety
This commit is contained in:
10
result.json
10
result.json
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"error_string": "Success.",
|
||||
"export_time": 0,
|
||||
"layer_height": 0.0,
|
||||
"plate_index": 0,
|
||||
"prepare_time": 0,
|
||||
"return_code": 0,
|
||||
"sparse_infill_density": 0.0,
|
||||
"wall_loops": 0
|
||||
}
|
||||
@@ -42,10 +42,15 @@ bool Print::has_belt_purge_tower() const
|
||||
{
|
||||
// Its own purge-tower "type", gated by the belt-only enable_belt_purge_tower
|
||||
// option (not the classic enable_prime_tower).
|
||||
return m_config.belt_printer.value
|
||||
&& m_config.enable_belt_purge_tower.value
|
||||
&& !m_config.spiral_mode.value
|
||||
&& m_config.filament_diameter.values.size() > 1;
|
||||
if (!(m_config.belt_printer.value
|
||||
&& m_config.enable_belt_purge_tower.value
|
||||
&& !m_config.spiral_mode.value
|
||||
&& m_config.filament_diameter.values.size() > 1))
|
||||
return false;
|
||||
|
||||
return std::any_of(m_objects.begin(), m_objects.end(), [](const PrintObject *object) {
|
||||
return object->config().belt_purge_tower_object.value;
|
||||
});
|
||||
}
|
||||
|
||||
// Belt mode: align ALL objects on the plate (the printed objects AND the purge
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
// tower to tell which prism fills carry purge vs. which are unclaimed waste.
|
||||
bool is_entity_overridden(const ExtrusionEntity* entity, const PrintObject *object, size_t copy_id) const {
|
||||
auto it = entity_map.find(std::make_tuple(entity, object));
|
||||
return it == entity_map.end() ? false : it->second[copy_id] != -1;
|
||||
return it != entity_map.end() && copy_id < it->second.size() && it->second[copy_id] != -1;
|
||||
}
|
||||
|
||||
bool is_overriddable(const ExtrusionEntityCollection& ee, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const;
|
||||
|
||||
@@ -1477,13 +1477,13 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin
|
||||
|
||||
if (m_config.belt_printer.value && m_config.enable_belt_purge_tower.value
|
||||
&& m_config.print_sequence == PrintSequence::ByObject
|
||||
&& extruders.size() > 1 && warning != nullptr) {
|
||||
&& extruders.size() > 1) {
|
||||
StringObjectException warningtemp;
|
||||
warningtemp.string = L("The belt purge tower is not generated in \"By object\" print sequence; "
|
||||
"filament changes will not be purged.");
|
||||
warningtemp.opt_key = "enable_belt_purge_tower";
|
||||
warningtemp.is_warning = true;
|
||||
*warning = warningtemp;
|
||||
add_warning(warningtemp);
|
||||
}
|
||||
|
||||
if (m_config.enable_prime_tower) {
|
||||
|
||||
@@ -142,7 +142,14 @@ bool ensure_belt_purge_tower(Model &model, PartPlateList &partplate_list, Object
|
||||
}
|
||||
|
||||
// --- Sizing -----------------------------------------------------------
|
||||
const double width = print_config.has("belt_purge_tower_width") ? std::max(1., print_config.opt_float("belt_purge_tower_width")) : 35.;
|
||||
const int n_islands = std::max(1, (int) filaments.size() - 1);
|
||||
const double gap = 1.0;
|
||||
// Every disconnected island needs at least 1 mm of printable width. Honor
|
||||
// the configured total width whenever possible, but never let the island
|
||||
// layout silently grow past the footprint used for placement.
|
||||
const double min_width = n_islands + (n_islands - 1) * gap;
|
||||
const double width = std::max(min_width,
|
||||
print_config.has("belt_purge_tower_width") ? print_config.opt_float("belt_purge_tower_width") : 35.);
|
||||
const double layer_h = print_config.has("layer_height") ? print_config.opt_float("layer_height") : 0.2;
|
||||
|
||||
// Belt geometry. The rotation axis is the gantry tilt axis; the belt
|
||||
@@ -219,6 +226,9 @@ bool ensure_belt_purge_tower(Model &model, PartPlateList &partplate_list, Object
|
||||
new_sig.key[4] = q(belt_max);
|
||||
new_sig.key[5] = q(lat_min);
|
||||
new_sig.key[6] = q(z_max);
|
||||
new_sig.key[7] = static_cast<long>(rot);
|
||||
new_sig.key[8] = std::lround(theta * 10000.0);
|
||||
new_sig.key[9] = q(lat_max);
|
||||
if (prism_idxs.size() == 1 && new_sig == sig)
|
||||
return false; // already up to date — do not touch the model
|
||||
|
||||
@@ -279,15 +289,13 @@ bool ensure_belt_purge_tower(Model &model, PartPlateList &partplate_list, Object
|
||||
// lets each swap claim its own island. Total lateral footprint stays `width`
|
||||
// (each island width/N wide, separated by a small gap), so per-layer capacity
|
||||
// per island ~= max_flush, matching the height sizing.
|
||||
const int n_islands = std::max(1, (int) filaments.size() - 1);
|
||||
// Minimal gap between sub-bars: they must stay just-separated so the slicer
|
||||
// keeps them as distinct islands (hence distinct infill collections, one per
|
||||
// simultaneous swap). Zero gap would union them into one collection and
|
||||
// reintroduce the multi-swap-per-layer absorption bug; a hair over ~2 line
|
||||
// widths also keeps gap-fill from bridging them. 1 mm is about as close as
|
||||
// they can butt up while staying individually purgeable.
|
||||
const double gap = 1.0;
|
||||
const double w_sub = std::max(1.0, (width - (n_islands - 1) * gap) / n_islands);
|
||||
const double w_sub = (width - (n_islands - 1) * gap) / n_islands;
|
||||
|
||||
// --- (Re)create ---------------------------------------------------------
|
||||
if (!prism_idxs.empty())
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#ifndef slic3r_GUI_BeltPurgeTower_hpp_
|
||||
#define slic3r_GUI_BeltPurgeTower_hpp_
|
||||
#pragma once
|
||||
|
||||
// ORCA-Belt: auto-managed purge prism for belt printers.
|
||||
//
|
||||
@@ -23,12 +22,12 @@ struct BeltPurgeSignature
|
||||
{
|
||||
bool valid = false;
|
||||
int filament_count = 0;
|
||||
long key[7] = {0}; // rounded geometry inputs (0.1 mm units)
|
||||
long key[10] = {0}; // rounded geometry inputs (0.1 mm units)
|
||||
bool operator==(const BeltPurgeSignature &o) const
|
||||
{
|
||||
if (valid != o.valid || filament_count != o.filament_count)
|
||||
return false;
|
||||
for (int i = 0; i < 7; ++i)
|
||||
for (int i = 0; i < 10; ++i)
|
||||
if (key[i] != o.key[i])
|
||||
return false;
|
||||
return true;
|
||||
@@ -44,5 +43,3 @@ bool ensure_belt_purge_tower(Model &model, PartPlateList &partplate_list, Object
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_GUI_BeltPurgeTower_hpp_
|
||||
|
||||
@@ -300,6 +300,41 @@ TEST_CASE("Print::validate tolerates a null warnings pointer", "[Print][validate
|
||||
CHECK(err.string.empty());
|
||||
}
|
||||
|
||||
TEST_CASE("Purge tower selection keeps ordinary printers on the classic path", "[Print][PurgeTower][Regression]")
|
||||
{
|
||||
DynamicPrintConfig config = multifilament_config(2, {
|
||||
{ "belt_printer", 0 },
|
||||
{ "enable_prime_tower", 1 },
|
||||
{ "enable_belt_purge_tower", 1 }
|
||||
});
|
||||
config.set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(TimelapseType::tlSmooth));
|
||||
|
||||
Model model;
|
||||
Print print;
|
||||
build_cubes(model, print, config, /*n=*/1, /*overlap=*/false);
|
||||
|
||||
CHECK(print.has_wipe_tower());
|
||||
CHECK_FALSE(print.has_belt_purge_tower());
|
||||
}
|
||||
|
||||
TEST_CASE("Belt purge planning requires its managed purge object", "[Print][PurgeTower][Regression]")
|
||||
{
|
||||
DynamicPrintConfig config = multifilament_config(2, {
|
||||
{ "belt_printer", 1 },
|
||||
{ "enable_belt_purge_tower", 1 }
|
||||
});
|
||||
|
||||
Model model;
|
||||
Print print;
|
||||
build_cubes(model, print, config, /*n=*/1, /*overlap=*/false);
|
||||
CHECK_FALSE(print.has_belt_purge_tower());
|
||||
|
||||
model.objects.front()->config.set_key_value("belt_purge_tower_object", new ConfigOptionBool(true));
|
||||
print.apply(model, config);
|
||||
CHECK(print.has_belt_purge_tower());
|
||||
CHECK_FALSE(print.has_wipe_tower());
|
||||
}
|
||||
|
||||
TEST_CASE("A default slice emits perimeter, infill, and skirt", "[Print]")
|
||||
{
|
||||
const std::string gcode = slice({ cube(20) }, {
|
||||
|
||||
Reference in New Issue
Block a user