Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/gcode_export/FixedGCodePart.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace cura
class FixedGCodePart : public GCodePart
{
public:
explicit FixedGCodePart();
explicit FixedGCodePart(const GCodePartType type);

/*! \brief Gets the full piece of GCode to be exported */
std::string str() const override;
Expand Down
15 changes: 14 additions & 1 deletion include/gcode_export/GCodePart.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include <string>

#include "gcode_export/GCodePartType.h"

namespace cura
{

Expand All @@ -18,8 +20,19 @@ class GCodePart
/*! \brief Gets the full piece of GCode to be exported */
virtual std::string str() const = 0;

GCodePartType type() const
{
return type_;
}

protected:
explicit GCodePart() = default;
explicit GCodePart(const GCodePartType type = GCodePartType::Management)
: type_(type)
{
}

private:
const GCodePartType type_;
};

} // namespace cura
Expand Down
20 changes: 20 additions & 0 deletions include/gcode_export/GCodePartType.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) 2026 UltiMaker
// CuraEngine is released under the terms of the AGPLv3 or higher

#ifndef GCODEEXPORT_GCODEPARTTYPE_H
#define GCODEEXPORT_GCODEPARTTYPE_H

namespace cura
{

enum class GCodePartType
{
Header, // The header, only made of useful comments
Management, // Management commands, like heating, extruder switching, custom gcode, ...
Print, // Actual model print commands

};

} // namespace cura

#endif
17 changes: 8 additions & 9 deletions include/gcode_export/gcodeExport.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "PrintInformation.h"
#include "TravelAntiOozing.h"
#include "gcode_export/GCodePartType.h"
#include "gcode_export/ResolvingExtruderContext.h"
#include "geometry/Point2LL.h"
#include "settings/EnumSettings.h"
Expand Down Expand Up @@ -409,13 +410,11 @@ class GCodeExport : public NoCopy
*/
bool needPrimeBlob() const;

/*
* Function is used to write the content of output_stream to the gcode file
/*!
* \brief Creates a new instance of fixed GCode part and sets it as the current container for fixed GCode parts.
* \param print_code Whether the GCode actually contains print instructions, or management commands (heating, extruder switch, ...)
*/
void flushOutputStream();

/*! \brief Creates a new instance of fixed GCode part and sets it as the current container for fixed GCode parts. */
void prepareNewFixedGCodePart();
void prepareNewFixedGCodePart(const GCodePartType type = GCodePartType::Management);

/*!
* \brief Write a piece of resolvable GCode
Expand Down Expand Up @@ -556,9 +555,6 @@ class GCodeExport : public NoCopy
static PrintFeatureType
sendTravel(const Point3LL& p, const Velocity& speed, const ExtruderTrainAttributes& extruder_attr, const std::optional<RetractionAmounts>& retraction_amounts);

/*! \brief Resolves and sends all the pieces of GCode that have been created during slicing */
void sendFinalGCode();

/*! \brief Calculates the end-of-print data about material consumption */
std::vector<std::optional<ExtruderPrintInformation>> calculateMaterialPrintInformation() const;

Expand Down Expand Up @@ -775,6 +771,9 @@ class GCodeExport : public NoCopy
* Indicates whether the printer handles the retraction/priming, totally or with specific commands
*/
bool machineHandlesRetraction() const;

/*! \brief Resolves and sends all the pieces of GCode that have been created during slicing */
void sendFinalGCode();
};

} // namespace cura
Expand Down
2 changes: 1 addition & 1 deletion src/FffGcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4288,7 +4288,7 @@ void FffGcodeWriter::finalize()
}

gcode.writeComment("End of Gcode");
gcode.flushOutputStream();
gcode.sendFinalGCode();
/*
the profile string below can be executed since the M25 doesn't end the gcode on an UMO and when printing via USB.
gcode.writeCode("M25 ;Stop reading from this point on.");
Expand Down
3 changes: 2 additions & 1 deletion src/gcode_export/FixedGCodePart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
namespace cura
{

FixedGCodePart::FixedGCodePart()
FixedGCodePart::FixedGCodePart(const GCodePartType type)
: GCodePart(type)
{
stream_ << std::fixed;
}
Expand Down
77 changes: 62 additions & 15 deletions src/gcode_export/gcodeExport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <regex>

#include <fmt/chrono.h>
#include <range/v3/algorithm/find_if.hpp>
#include <spdlog/spdlog.h>

#include "Application.h" //To send layer view data.
Expand Down Expand Up @@ -354,7 +355,9 @@ std::string GCodeExport::getFileHeader(const std::vector<bool>& extruder_is_used
void GCodeExport::setLayerNr(const LayerIndex& layer_nr)
{
layer_nr_ = layer_nr;
prepareNewFixedGCodePart(); // Now is a good time to switch to a new buffer

constexpr GCodePartType type = GCodePartType::Print; // Now we are actually going to send print commands
prepareNewFixedGCodePart(type); // Now is a good time to switch to a new buffer
}

bool GCodeExport::getExtruderIsUsed(const int extruder_nr) const
Expand Down Expand Up @@ -1423,8 +1426,55 @@ PrintFeatureType

void GCodeExport::sendFinalGCode()
{
std::shared_ptr<Communication> communication = Application::getInstance().communication_;
{
// For retro-compatibility with the post-processing plugins, merge all the initial gcode parts into a single one
const auto iterator_first_init_part = ranges::find_if(
gcode_parts_,
[](const std::shared_ptr<GCodePart>& part)
{
return part->type() != GCodePartType::Header;
});
const auto iterator_first_print_part = ranges::find_if(
iterator_first_init_part,
gcode_parts_.end(),
[](const std::shared_ptr<GCodePart>& part)
{
return part->type() == GCodePartType::Print;
});
if (std::distance(iterator_first_init_part, iterator_first_print_part) > 1) // If there is none or a single init part, we can skip
{
constexpr auto type = GCodePartType::Management;
auto init_part = std::make_shared<FixedGCodePart>(type);
for (auto iterator = iterator_first_init_part; iterator != iterator_first_print_part; ++iterator)
{
init_part->stream() << (*iterator)->str();
}

// To avoid invalidating iterators, replace the first init part and erase the rest
*iterator_first_init_part = init_part;
gcode_parts_.erase(iterator_first_init_part + 1, iterator_first_print_part);
}
}

{
// For retro-compatibility with the post-processing plugins, merge all the end gcode parts into a single one
auto iterator_last_print_part = gcode_parts_.end() - 1;
while (iterator_last_print_part != gcode_parts_.begin() && (*iterator_last_print_part)->type() != GCodePartType::Print)
{
--iterator_last_print_part;
}

constexpr auto type = GCodePartType::Management;
auto end_part = std::make_shared<FixedGCodePart>(type);
for (auto iterator = iterator_last_print_part + 1; iterator != gcode_parts_.end(); ++iterator)
{
end_part->stream() << (*iterator)->str();
}
gcode_parts_.erase(iterator_last_print_part + 1, gcode_parts_.end());
gcode_parts_.push_back(end_part);
}

std::shared_ptr<Communication> communication = Application::getInstance().communication_;
run_multiple_producers_ordered_consumer(
0,
gcode_parts_.size(),
Expand Down Expand Up @@ -2027,13 +2077,15 @@ void GCodeExport::finalize(const std::string& end_code, PrintInformation& print_

template_resolver_->prepareForResolving(print_info.initial_extruder_nr.value_or(0), extra_global_settings);

std::shared_ptr<Communication> communication = Application::getInstance().communication_;

communication->sendGCodePart(getFileHeader(is_extruder_used_bool, filaments_volumes, materials_ids));

sendFinalGCode();
{
// Prepend the header as a full separate part
constexpr GCodePartType type = GCodePartType::Header;
auto header_part = std::make_shared<FixedGCodePart>(type);
header_part->stream() << getFileHeader(is_extruder_used_bool, filaments_volumes, materials_ids);
gcode_parts_.insert(gcode_parts_.begin(), header_part);
}

communication->sendPrintInformation(total_print_times_, print_info);
Application::getInstance().communication_->sendPrintInformation(total_print_times_, print_info);
}

void GCodeExport::finalizeExtruder(const std::string& extruder_end_code)
Expand All @@ -2043,14 +2095,9 @@ void GCodeExport::finalizeExtruder(const std::string& extruder_end_code)
writeCodeWithAbsoluteExtrusion(extruder_end_code, getExtruderNr(), extra_settings);
}

void GCodeExport::flushOutputStream()
{
prepareNewFixedGCodePart();
}

void GCodeExport::prepareNewFixedGCodePart()
void GCodeExport::prepareNewFixedGCodePart(const GCodePartType type)
{
auto fixed_gcode_part = std::make_shared<FixedGCodePart>();
const auto fixed_gcode_part = std::make_shared<FixedGCodePart>(type);
gcode_parts_.push_back(fixed_gcode_part);
output_stream_ = &fixed_gcode_part->stream();
}
Expand Down
Loading