mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-22 14:50:59 +00:00
Keep Layer Pauses on Their Own Layer in the Preview
The G-code processor remembers where a pause, color change or custom G-code vertex sits in the move list, so it can move that vertex to the first extrusion after it. A pause flushes the time planner first, which inserts actual speed moves ahead of the vertex, so the remembered index pointed at an earlier move: the previous layer's last extrusion was moved instead, a real move was erased, and the time blocks queued after the vertex were left one move off. Shift the remembered index by the moves each flush inserts before it, and shift the queued blocks after the erase. The Preview numbers layers from the move order, so the stray move showed up as extra layers and listed pauses on the wrong layer.
This commit is contained in:
1 parent
069bd402d9
commit
7b05bc5ea1
3 files changed
+74
-6
No files matched your search
@@ -5234,7 +5234,15 @@ void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes
|
||||
|
||||
if (origin == G1DiscretizationOrigin::G1)
|
||||
m_extruded_last_z = m_end_position[Z];
|
||||
m_options_z_corrector.update(m_height);
|
||||
// The queued blocks of the moves after the erased one follow them down the list.
|
||||
if (const std::optional<size_t> erased = m_options_z_corrector.update(m_height)) {
|
||||
for (TimeMachine& machine : m_time_processor.machines) {
|
||||
for (TimeBlock& block : machine.blocks) {
|
||||
if (block.move_id > *erased)
|
||||
--block.move_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_forced_width > 0.0f)
|
||||
m_width = m_forced_width;
|
||||
@@ -7958,6 +7966,7 @@ void GCodeProcessor::calculate_time(GCodeProcessorResult& result, size_t keep_la
|
||||
it->second : block.move_id + (unsigned int)inserted_actual_speed_moves_count;
|
||||
}
|
||||
}
|
||||
m_options_z_corrector.on_moves_inserted(m_actual_speed_id_map);
|
||||
}
|
||||
|
||||
void GCodeProcessor::simulate_st_synchronize(float additional_time, EMoveType target_move_type)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
@@ -1076,18 +1077,34 @@ inline constexpr float DEFAULT_FILAMENT_DENSITY = 1.245f;
|
||||
m_custom_gcode_per_print_z_id = m_result.custom_gcode_per_print_z.size() - 1;
|
||||
}
|
||||
|
||||
void update(float height) {
|
||||
if (!m_move_id.has_value() || !m_custom_gcode_per_print_z_id.has_value())
|
||||
// The time pass inserts actual speed moves in front of the moves of its blocks, and the stored
|
||||
// vertex has no block of its own, so it shifts with every insertion made before it.
|
||||
void on_moves_inserted(const std::vector<std::pair<unsigned int, unsigned int>>& id_map) {
|
||||
if (!m_move_id.has_value())
|
||||
return;
|
||||
auto it = std::lower_bound(id_map.begin(), id_map.end(), *m_move_id,
|
||||
[](const std::pair<unsigned int, unsigned int>& entry, size_t id) { return entry.first < id; });
|
||||
if (it != id_map.begin()) {
|
||||
--it;
|
||||
*m_move_id += it->second - it->first;
|
||||
}
|
||||
}
|
||||
|
||||
const Vec3f position = m_result.moves.back().position;
|
||||
// Returns the index of the move erased from the list, if any.
|
||||
std::optional<size_t> update(float height) {
|
||||
if (!m_move_id.has_value() || !m_custom_gcode_per_print_z_id.has_value())
|
||||
return std::nullopt;
|
||||
|
||||
GCodeProcessorResult::MoveVertex& move = m_result.moves.emplace_back(m_result.moves[*m_move_id]);
|
||||
const Vec3f position = m_result.moves.back().position;
|
||||
const size_t erased = *m_move_id;
|
||||
|
||||
GCodeProcessorResult::MoveVertex& move = m_result.moves.emplace_back(m_result.moves[erased]);
|
||||
move.position = position;
|
||||
move.height = height;
|
||||
m_result.moves.erase(m_result.moves.begin() + *m_move_id);
|
||||
m_result.moves.erase(m_result.moves.begin() + erased);
|
||||
m_result.custom_gcode_per_print_z[*m_custom_gcode_per_print_z_id].print_z = position.z();
|
||||
reset();
|
||||
return erased;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
|
||||
@@ -282,6 +282,48 @@ TEST_CASE("A seam takes the actual speed of the move it follows", "[GCodeProcess
|
||||
REQUIRE(seams > 0);
|
||||
}
|
||||
|
||||
TEST_CASE("A pause keeps the moves around it in order and on their own layers", "[GCodeProcessor][Regression]")
|
||||
{
|
||||
// libvgcode numbers layers from the order of the moves, so the moves around a pause must stay in layer and
|
||||
// line order. The pause vertex itself moves to the first extrusion after it and keeps its own line.
|
||||
std::ostringstream gcode;
|
||||
gcode << "M83\nG90\n";
|
||||
for (int layer = 1; layer <= 3; ++layer) {
|
||||
gcode << "; CHANGE_LAYER\n; LAYER_HEIGHT: 0.2\n";
|
||||
if (layer == 2)
|
||||
gcode << "G1 E-0.8 F3000\n; PAUSE_PRINTING\nM601\n";
|
||||
gcode << "G1 X10 Y10 F12000\nG1 Z" << 0.2 * layer << "\n";
|
||||
if (layer == 2)
|
||||
gcode << "G1 E0.8 F3000\n";
|
||||
gcode << "; FEATURE: Outer wall\n"
|
||||
<< "G1 X50 Y10 E2 F3000\nG1 X50 Y50 E2\nG1 X10 Y50 E2\nG1 X10 Y10 E2\n";
|
||||
}
|
||||
GCodeProcessorResult result;
|
||||
process_gcode(gcode.str(), result);
|
||||
const auto &moves = result.moves;
|
||||
|
||||
REQUIRE(result.custom_gcode_per_print_z.size() == 1);
|
||||
CHECK_THAT(result.custom_gcode_per_print_z.front().print_z, Catch::Matchers::WithinAbs(0.4, 1e-4));
|
||||
REQUIRE(std::count_if(moves.begin(), moves.end(), [](const auto &move) { return move.internal_only; }) > 0);
|
||||
|
||||
const auto pause = std::find_if(moves.begin(), moves.end(), [](const auto &move) { return move.type == EMoveType::Pause_Print; });
|
||||
REQUIRE(pause != moves.end());
|
||||
CHECK(pause->layer_id == 1);
|
||||
CHECK_THAT(pause->position.z(), Catch::Matchers::WithinAbs(0.4f, 1e-4f));
|
||||
|
||||
const GCodeProcessorResult::MoveVertex *previous = nullptr;
|
||||
for (const auto &move : moves) {
|
||||
if (move.type == EMoveType::Pause_Print)
|
||||
continue;
|
||||
if (previous != nullptr) {
|
||||
CAPTURE(previous->gcode_id, move.gcode_id, static_cast<int>(move.type));
|
||||
CHECK(move.layer_id >= previous->layer_id);
|
||||
CHECK(move.gcode_id >= previous->gcode_id);
|
||||
}
|
||||
previous = &move;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Line ends of the exported G-code mark every newline in the file", "[GCodeProcessor]")
|
||||
{
|
||||
struct Case
|
||||
|
||||
Reference in new issue
Block a user