mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-01 02:32:02 +08:00
Merge branch 'et_spe1784_binary_gcode' into master_262
This commit is contained in:
commit
529f1fb395
9
deps/CMakeLists.txt
vendored
9
deps/CMakeLists.txt
vendored
@ -20,8 +20,8 @@
|
|||||||
# therefore, unfortunatelly, the installation cannot be copied/moved elsewhere without re-installing wxWidgets.
|
# therefore, unfortunatelly, the installation cannot be copied/moved elsewhere without re-installing wxWidgets.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(PrusaSlicer-deps)
|
project(PrusaSlicer-deps)
|
||||||
cmake_minimum_required(VERSION 3.2)
|
|
||||||
|
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
include(ProcessorCount)
|
include(ProcessorCount)
|
||||||
@ -62,6 +62,10 @@ if (NOT _is_multi AND NOT CMAKE_BUILD_TYPE)
|
|||||||
message(STATUS "Forcing CMAKE_BUILD_TYPE to Release as it was not specified.")
|
message(STATUS "Forcing CMAKE_BUILD_TYPE to Release as it was not specified.")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.24)
|
||||||
|
cmake_policy(SET CMP0135 NEW)
|
||||||
|
endif ()
|
||||||
|
|
||||||
function(prusaslicer_add_cmake_project projectname)
|
function(prusaslicer_add_cmake_project projectname)
|
||||||
cmake_parse_arguments(P_ARGS "" "INSTALL_DIR;BUILD_COMMAND;INSTALL_COMMAND" "CMAKE_ARGS" ${ARGN})
|
cmake_parse_arguments(P_ARGS "" "INSTALL_DIR;BUILD_COMMAND;INSTALL_COMMAND" "CMAKE_ARGS" ${ARGN})
|
||||||
|
|
||||||
@ -195,6 +199,8 @@ include(NanoSVG/NanoSVG.cmake)
|
|||||||
include(wxWidgets/wxWidgets.cmake)
|
include(wxWidgets/wxWidgets.cmake)
|
||||||
include(OCCT/OCCT.cmake)
|
include(OCCT/OCCT.cmake)
|
||||||
|
|
||||||
|
include(LibBGCode/LibBGCode.cmake)
|
||||||
|
|
||||||
set(_dep_list
|
set(_dep_list
|
||||||
dep_Boost
|
dep_Boost
|
||||||
dep_TBB
|
dep_TBB
|
||||||
@ -210,6 +216,7 @@ set(_dep_list
|
|||||||
${PNG_PKG}
|
${PNG_PKG}
|
||||||
${ZLIB_PKG}
|
${ZLIB_PKG}
|
||||||
${EXPAT_PKG}
|
${EXPAT_PKG}
|
||||||
|
dep_LibBGCode
|
||||||
)
|
)
|
||||||
|
|
||||||
# if (NOT MSVC)
|
# if (NOT MSVC)
|
||||||
|
34
deps/LibBGCode/LibBGCode.cmake
vendored
Normal file
34
deps/LibBGCode/LibBGCode.cmake
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
set(LibBGCode_SOURCE_DIR "" CACHE PATH "Optionally specify local LibBGCode source directory")
|
||||||
|
|
||||||
|
set(_source_dir_line
|
||||||
|
URL https://github.com/prusa3d/libbgcode/archive/49e7b47b7a9a7e9365613d3f90ad49d71a0e93d6.zip
|
||||||
|
URL_HASH SHA256=b9513ab2bbaf06a79c35c4d69226d211f1226ca625ce07c04f54b89b93e9bc75
|
||||||
|
)
|
||||||
|
|
||||||
|
if (LibBGCode_SOURCE_DIR)
|
||||||
|
set(_source_dir_line "SOURCE_DIR;${LibBGCode_SOURCE_DIR};BUILD_ALWAYS;ON")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
prusaslicer_add_cmake_project(LibBGCode_deps
|
||||||
|
${_source_dir_line}
|
||||||
|
SOURCE_SUBDIR deps
|
||||||
|
DEPENDS dep_Boost ${ZLIB_PKG}
|
||||||
|
CMAKE_ARGS
|
||||||
|
-DDEP_DOWNLOAD_DIR:PATH=${DEP_DOWNLOAD_DIR}
|
||||||
|
-DDEP_CMAKE_OPTS:STRING=-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON
|
||||||
|
-DLibBGCode_Deps_SELECT_ALL:BOOL=OFF
|
||||||
|
-DLibBGCode_Deps_SELECT_heatshrink:BOOL=ON
|
||||||
|
-DDESTDIR=${DESTDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
prusaslicer_add_cmake_project(LibBGCode
|
||||||
|
${_source_dir_line}
|
||||||
|
DEPENDS dep_LibBGCode_deps
|
||||||
|
CMAKE_ARGS
|
||||||
|
-DLibBGCode_BUILD_TESTS:BOOL=OFF
|
||||||
|
-DLibBGCode_BUILD_CMD_TOOL:BOOL=OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
add_debug_dep(dep_LibBGCode)
|
||||||
|
endif ()
|
93
resources/icons/convert_file.svg
Normal file
93
resources/icons/convert_file.svg
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
version="1.0"
|
||||||
|
id="Layer_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 128 128"
|
||||||
|
enable-background="new 0 0 128 128"
|
||||||
|
xml:space="preserve"
|
||||||
|
sodipodi:docname="convert_file.svg"
|
||||||
|
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs1064">
|
||||||
|
|
||||||
|
|
||||||
|
</defs><sodipodi:namedview
|
||||||
|
id="namedview1062"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#eeeeee"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:pageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="4.8782082"
|
||||||
|
inkscape:cx="62.830447"
|
||||||
|
inkscape:cy="67.750287"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1001"
|
||||||
|
inkscape:window-x="3191"
|
||||||
|
inkscape:window-y="-9"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="Layer_1" />
|
||||||
|
<g
|
||||||
|
id="g1046"
|
||||||
|
style="stroke:none;stroke-opacity:1;fill:#808080;fill-opacity:1">
|
||||||
|
<path
|
||||||
|
fill="#ed6b21"
|
||||||
|
d="M 115.76,51.2 107.7,43.14 C 105.23,40.67 100.73,38.8 97.23,38.8 h -50.8 c -4.2,0 -7.62,3.42 -7.62,7.62 v 66.04 c 0,4.2 3.42,7.62 7.62,7.62 h 66.04 c 4.2,0 7.62,-3.42 7.62,-7.62 v -50.8 c 0,-3.49 -1.86,-7.99 -4.33,-10.46 z m -4.34,2.84 h -6.57 v -6.57 z m 3.59,58.43 c 0,1.4 -1.14,2.54 -2.54,2.54 H 46.43 c -1.4,0 -2.54,-1.14 -2.54,-2.54 V 46.42 c 0,-1.4 1.14,-2.54 2.54,-2.54 h 50.8 c 0.74,0 1.63,0.18 2.54,0.46 v 12.24 c 0,1.4 1.14,2.54 2.54,2.54 h 12.24 c 0.28,0.91 0.46,1.8 0.46,2.54 z"
|
||||||
|
id="path1036"
|
||||||
|
style="stroke:none;stroke-opacity:1;fill:#808080;fill-opacity:1" />
|
||||||
|
<path
|
||||||
|
fill="#ed6b21"
|
||||||
|
d="m 53.97,59.13 h 35.72 c 1.4,0 2.54,-1.14 2.54,-2.54 0,-1.4 -1.14,-2.54 -2.54,-2.54 H 53.97 c -1.4,0 -2.54,1.14 -2.54,2.54 0,1.4 1.13,2.54 2.54,2.54 z"
|
||||||
|
id="path1038"
|
||||||
|
style="stroke:none;stroke-opacity:1;fill:#808080;fill-opacity:1" />
|
||||||
|
<path
|
||||||
|
fill="#ed6b21"
|
||||||
|
d="M 104.93,69.29 H 53.97 c -1.4,0 -2.54,1.14 -2.54,2.54 0,1.4 1.14,2.54 2.54,2.54 h 50.96 c 1.4,0 2.54,-1.14 2.54,-2.54 0,-1.4 -1.14,-2.54 -2.54,-2.54 z"
|
||||||
|
id="path1040"
|
||||||
|
style="stroke:none;stroke-opacity:1;fill:#808080;fill-opacity:1" />
|
||||||
|
<path
|
||||||
|
fill="#ed6b21"
|
||||||
|
d="M 104.93,84.53 H 53.97 c -1.4,0 -2.54,1.14 -2.54,2.54 0,1.4 1.14,2.54 2.54,2.54 h 50.96 c 1.4,0 2.54,-1.14 2.54,-2.54 0,-1.4 -1.14,-2.54 -2.54,-2.54 z"
|
||||||
|
id="path1042"
|
||||||
|
style="stroke:none;stroke-opacity:1;fill:#808080;fill-opacity:1" />
|
||||||
|
<path
|
||||||
|
fill="#ed6b21"
|
||||||
|
d="M 104.93,99.77 H 53.97 c -1.4,0 -2.54,1.14 -2.54,2.54 0,1.4 1.14,2.54 2.54,2.54 h 50.96 c 1.4,0 2.54,-1.14 2.54,-2.54 0,-1.4 -1.14,-2.54 -2.54,-2.54 z"
|
||||||
|
id="path1044"
|
||||||
|
style="stroke:none;stroke-opacity:1;fill:#808080;fill-opacity:1" />
|
||||||
|
</g><g
|
||||||
|
id="g1058">
|
||||||
|
<path
|
||||||
|
fill="#808080"
|
||||||
|
d="M 85.27,20.71 77.21,12.65 C 74.74,10.18 70.24,8.31 66.74,8.31 h -50.8 c -4.2,0 -7.62,3.42 -7.62,7.62 v 66.04 c 0,4.2 3.42,7.62 7.62,7.62 h 17.78 c 1.4,0 2.54,-1.14 2.54,-2.54 0,-1.4 -1.14,-2.54 -2.54,-2.54 H 15.94 c -1.4,0 -2.54,-1.14 -2.54,-2.54 V 15.94 c 0,-1.4 1.14,-2.54 2.54,-2.54 h 50.8 c 0.74,0 1.63,0.18 2.54,0.46 V 26.1 c 0,1.4 1.14,2.54 2.54,2.54 h 12.45 c 0.16,0.49 0.25,0.93 0.25,1.27 v 3.81 c 0,1.4 1.14,2.54 2.54,2.54 1.4,0 2.54,-1.14 2.54,-2.54 v -3.81 c 0.01,-2.77 -1.85,-6.72 -4.33,-9.2 z m -10.9,-3.72 6.57,6.57 h -6.57 z"
|
||||||
|
id="path1048" />
|
||||||
|
<path
|
||||||
|
fill="#808080"
|
||||||
|
d="M 59.21,23.56 H 23.48 c -1.4,0 -2.54,1.14 -2.54,2.54 0,1.4 1.14,2.54 2.54,2.54 H 59.2 c 1.4,0 2.54,-1.14 2.54,-2.54 0,-1.4 -1.13,-2.54 -2.53,-2.54 z"
|
||||||
|
id="path1050" />
|
||||||
|
<path
|
||||||
|
fill="#808080"
|
||||||
|
d="m 28.73,38.8 h -5.24 c -1.4,0 -2.54,1.14 -2.54,2.54 0,1.4 1.14,2.54 2.54,2.54 h 5.24 c 1.4,0 2.54,-1.14 2.54,-2.54 0,-1.4 -1.14,-2.54 -2.54,-2.54 z"
|
||||||
|
id="path1052" />
|
||||||
|
<path
|
||||||
|
fill="#808080"
|
||||||
|
d="m 28.73,54.04 h -5.24 c -1.4,0 -2.54,1.14 -2.54,2.54 0,1.4 1.14,2.54 2.54,2.54 h 5.24 c 1.4,0 2.54,-1.14 2.54,-2.54 0,-1.4 -1.14,-2.54 -2.54,-2.54 z"
|
||||||
|
id="path1054" />
|
||||||
|
<path
|
||||||
|
fill="#808080"
|
||||||
|
d="m 28.73,69.29 h -5.24 c -1.4,0 -2.54,1.14 -2.54,2.54 0,1.4 1.14,2.54 2.54,2.54 h 5.24 c 1.4,0 2.54,-1.14 2.54,-2.54 0,-1.4 -1.14,-2.54 -2.54,-2.54 z"
|
||||||
|
id="path1056" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
d="M 104.85,54.04 82.71545,76.15908 60.58864,54.03226 66.08342,48.53747 78.78283,61.23685 V 43.51678 C 78.76993,34.93742 71.81821,27.98568 63.23888,27.97284 H 47.69494 v -7.77197 h 15.54394 c 12.87167,0.0129 23.30304,10.44422 23.31591,23.31591 V 61.33793 L 99.34746,48.54524 Z"
|
||||||
|
id="path1427"
|
||||||
|
style="stroke-width:0.233159;fill:#ed6b21;fill-opacity:1" /></svg>
|
After Width: | Height: | Size: 4.6 KiB |
@ -14,6 +14,11 @@ if (TARGET OpenVDB::openvdb)
|
|||||||
set(OpenVDBUtils_SOURCES OpenVDBUtils.cpp OpenVDBUtils.hpp OpenVDBUtilsLegacy.hpp)
|
set(OpenVDBUtils_SOURCES OpenVDBUtils.cpp OpenVDBUtils.hpp OpenVDBUtilsLegacy.hpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
find_package(LibBGCode REQUIRED COMPONENTS Convert)
|
||||||
|
slic3r_remap_configs(LibBGCode::bgcode_core RelWithDebInfo Release)
|
||||||
|
slic3r_remap_configs(LibBGCode::bgcode_binarize RelWithDebInfo Release)
|
||||||
|
slic3r_remap_configs(LibBGCode::bgcode_convert RelWithDebInfo Release)
|
||||||
|
|
||||||
set(SLIC3R_SOURCES
|
set(SLIC3R_SOURCES
|
||||||
pchheader.cpp
|
pchheader.cpp
|
||||||
pchheader.hpp
|
pchheader.hpp
|
||||||
@ -571,6 +576,7 @@ target_link_libraries(libslic3r
|
|||||||
ZLIB::ZLIB
|
ZLIB::ZLIB
|
||||||
JPEG::JPEG
|
JPEG::JPEG
|
||||||
qoi
|
qoi
|
||||||
|
LibBGCode::bgcode_convert
|
||||||
)
|
)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
@ -23,6 +23,10 @@
|
|||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
#include <LibBGCode/binarize/binarize.hpp>
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
//FIXME for GCodeFlavor and gcfMarlin (for forward-compatibility conversion)
|
//FIXME for GCodeFlavor and gcfMarlin (for forward-compatibility conversion)
|
||||||
// This is not nice, likely it would be better to pass the ConfigSubstitutionContext to handle_legacy().
|
// This is not nice, likely it would be better to pass the ConfigSubstitutionContext to handle_legacy().
|
||||||
#include "PrintConfig.hpp"
|
#include "PrintConfig.hpp"
|
||||||
@ -720,11 +724,43 @@ void ConfigBase::setenv_() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigSubstitutions ConfigBase::load(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule)
|
ConfigSubstitutions ConfigBase::load(const std::string& filename, ForwardCompatibilitySubstitutionRule compatibility_rule)
|
||||||
{
|
{
|
||||||
return is_gcode_file(file) ?
|
#if ENABLE_BINARIZED_GCODE
|
||||||
this->load_from_gcode_file(file, compatibility_rule) :
|
enum class EFileType
|
||||||
this->load_from_ini(file, compatibility_rule);
|
{
|
||||||
|
Ini,
|
||||||
|
AsciiGCode,
|
||||||
|
BinaryGCode
|
||||||
|
};
|
||||||
|
|
||||||
|
EFileType file_type;
|
||||||
|
|
||||||
|
if (is_gcode_file(filename)) {
|
||||||
|
FILE* file = boost::nowide::fopen(filename.c_str(), "rb");
|
||||||
|
if (file == nullptr)
|
||||||
|
throw Slic3r::RuntimeError("Error opening the file: " + filename + "\n");
|
||||||
|
|
||||||
|
using namespace bgcode::core;
|
||||||
|
std::vector<uint8_t> cs_buffer(65536);
|
||||||
|
file_type = (is_valid_binary_gcode(*file, true, cs_buffer.data(), cs_buffer.size()) == EResult::Success) ? EFileType::BinaryGCode : EFileType::AsciiGCode;
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
file_type = EFileType::Ini;
|
||||||
|
|
||||||
|
switch (file_type)
|
||||||
|
{
|
||||||
|
case EFileType::Ini: { return this->load_from_ini(filename, compatibility_rule); }
|
||||||
|
case EFileType::AsciiGCode: { return this->load_from_gcode_file(filename, compatibility_rule);}
|
||||||
|
case EFileType::BinaryGCode: { return this->load_from_binary_gcode_file(filename, compatibility_rule);}
|
||||||
|
default: { throw Slic3r::RuntimeError("Invalid file: " + filename + "\n"); }
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return is_gcode_file(filename) ?
|
||||||
|
this->load_from_gcode_file(filename, compatibility_rule) :
|
||||||
|
this->load_from_ini(filename, compatibility_rule);
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigSubstitutions ConfigBase::load_from_ini(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule)
|
ConfigSubstitutions ConfigBase::load_from_ini(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule)
|
||||||
@ -928,15 +964,15 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Load the config keys from the tail of a G-code file.
|
// Load the config keys from the tail of a G-code file.
|
||||||
ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule)
|
ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &filename, ForwardCompatibilitySubstitutionRule compatibility_rule)
|
||||||
{
|
{
|
||||||
// Read a 64k block from the end of the G-code.
|
// Read a 64k block from the end of the G-code.
|
||||||
boost::nowide::ifstream ifs(file, std::ifstream::binary);
|
boost::nowide::ifstream ifs(filename, std::ifstream::binary);
|
||||||
// Look for Slic3r or PrusaSlicer header.
|
// Look for Slic3r or PrusaSlicer header.
|
||||||
// Look for the header across the whole file as the G-code may have been extended at the start by a post-processing script or the user.
|
// Look for the header across the whole file as the G-code may have been extended at the start by a post-processing script or the user.
|
||||||
bool has_delimiters = false;
|
bool has_delimiters = false;
|
||||||
{
|
{
|
||||||
static constexpr const char slic3r_gcode_header[] = "; generated by Slic3r ";
|
static constexpr const char slic3r_gcode_header[] = "; generated by Slic3r ";
|
||||||
static constexpr const char prusaslicer_gcode_header[] = "; generated by PrusaSlicer ";
|
static constexpr const char prusaslicer_gcode_header[] = "; generated by PrusaSlicer ";
|
||||||
std::string header;
|
std::string header;
|
||||||
bool header_found = false;
|
bool header_found = false;
|
||||||
@ -986,7 +1022,7 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, Fo
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (! end_found)
|
if (! end_found)
|
||||||
throw Slic3r::RuntimeError(format("Configuration block closing tag \"; prusaslicer_config = end\" not found when reading %1%", file));
|
throw Slic3r::RuntimeError(format("Configuration block closing tag \"; prusaslicer_config = end\" not found when reading %1%", filename));
|
||||||
std::string key, value;
|
std::string key, value;
|
||||||
while (reader.getline(line)) {
|
while (reader.getline(line)) {
|
||||||
if (line == "; prusaslicer_config = begin") {
|
if (line == "; prusaslicer_config = begin") {
|
||||||
@ -1009,7 +1045,7 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, Fo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (! begin_found)
|
if (! begin_found)
|
||||||
throw Slic3r::RuntimeError(format("Configuration block opening tag \"; prusaslicer_config = begin\" not found when reading %1%", file));
|
throw Slic3r::RuntimeError(format("Configuration block opening tag \"; prusaslicer_config = begin\" not found when reading %1%", filename));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1017,8 +1053,8 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, Fo
|
|||||||
// Try a heuristics reading the G-code from back.
|
// Try a heuristics reading the G-code from back.
|
||||||
ifs.seekg(0, ifs.end);
|
ifs.seekg(0, ifs.end);
|
||||||
auto file_length = ifs.tellg();
|
auto file_length = ifs.tellg();
|
||||||
auto data_length = std::min<std::fstream::pos_type>(65535, file_length - header_end_pos);
|
auto data_length = std::min<std::fstream::pos_type>(65535, file_length - header_end_pos);
|
||||||
ifs.seekg(file_length - data_length, ifs.beg);
|
ifs.seekg(file_length - data_length, ifs.beg);
|
||||||
std::vector<char> data(size_t(data_length) + 1, 0);
|
std::vector<char> data(size_t(data_length) + 1, 0);
|
||||||
ifs.read(data.data(), data_length);
|
ifs.read(data.data(), data_length);
|
||||||
ifs.close();
|
ifs.close();
|
||||||
@ -1026,10 +1062,52 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, Fo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (key_value_pairs < 80)
|
if (key_value_pairs < 80)
|
||||||
throw Slic3r::RuntimeError(format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs));
|
throw Slic3r::RuntimeError(format("Suspiciously low number of configuration values extracted from %1%: %2%", filename, key_value_pairs));
|
||||||
return std::move(substitutions_ctxt.substitutions);
|
return std::move(substitutions_ctxt.substitutions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
ConfigSubstitutions ConfigBase::load_from_binary_gcode_file(const std::string& filename, ForwardCompatibilitySubstitutionRule compatibility_rule)
|
||||||
|
{
|
||||||
|
ConfigSubstitutionContext substitutions_ctxt(compatibility_rule);
|
||||||
|
|
||||||
|
FilePtr file{ boost::nowide::fopen(filename.c_str(), "rb") };
|
||||||
|
if (file.f == nullptr)
|
||||||
|
throw Slic3r::RuntimeError(format("Error opening the file: %1%", filename));
|
||||||
|
|
||||||
|
using namespace bgcode::core;
|
||||||
|
using namespace bgcode::binarize;
|
||||||
|
std::vector<uint8_t> cs_buffer(65536);
|
||||||
|
EResult res = is_valid_binary_gcode(*file.f, true, cs_buffer.data(), cs_buffer.size());
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError(format("The selected file is not a valid binary gcode.\nError: %1%", std::string(translate_result(res))));
|
||||||
|
|
||||||
|
FileHeader file_header;
|
||||||
|
res = read_header(*file.f, file_header, nullptr);
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError(format("Error while reading file '%1%': %2%", filename, std::string(translate_result(res))));
|
||||||
|
|
||||||
|
// searches for config block
|
||||||
|
BlockHeader block_header;
|
||||||
|
res = read_next_block_header(*file.f, file_header, block_header, EBlockType::SlicerMetadata, cs_buffer.data(), cs_buffer.size());
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError(format("Error while reading file '%1%': %2%", filename, std::string(translate_result(res))));
|
||||||
|
if ((EBlockType)block_header.type != EBlockType::SlicerMetadata)
|
||||||
|
throw Slic3r::RuntimeError(format("Unable to find slicer metadata block in file: '%1%'", filename));
|
||||||
|
SlicerMetadataBlock slicer_metadata_block;
|
||||||
|
res = slicer_metadata_block.read_data(*file.f, file_header, block_header);
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError(format("Error while reading file '%1%': %2%", filename, std::string(translate_result(res))));
|
||||||
|
|
||||||
|
// extracts data from block
|
||||||
|
for (const auto& [key, value] : slicer_metadata_block.raw_data) {
|
||||||
|
this->set_deserialize(key, value, substitutions_ctxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(substitutions_ctxt.substitutions);
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
void ConfigBase::save(const std::string &file) const
|
void ConfigBase::save(const std::string &file) const
|
||||||
{
|
{
|
||||||
boost::nowide::ofstream c;
|
boost::nowide::ofstream c;
|
||||||
|
@ -2307,7 +2307,10 @@ public:
|
|||||||
// Loading a "will be one day a legacy format" of configuration stored into 3MF or AMF.
|
// Loading a "will be one day a legacy format" of configuration stored into 3MF or AMF.
|
||||||
// Accepts the same data as load_from_ini_string(), only with each configuration line possibly prefixed with a semicolon (G-code comment).
|
// Accepts the same data as load_from_ini_string(), only with each configuration line possibly prefixed with a semicolon (G-code comment).
|
||||||
ConfigSubstitutions load_from_ini_string_commented(std::string &&data, ForwardCompatibilitySubstitutionRule compatibility_rule);
|
ConfigSubstitutions load_from_ini_string_commented(std::string &&data, ForwardCompatibilitySubstitutionRule compatibility_rule);
|
||||||
ConfigSubstitutions load_from_gcode_file(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule);
|
ConfigSubstitutions load_from_gcode_file(const std::string &filename, ForwardCompatibilitySubstitutionRule compatibility_rule);
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
ConfigSubstitutions load_from_binary_gcode_file(const std::string& filename, ForwardCompatibilitySubstitutionRule compatibility_rule);
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
ConfigSubstitutions load(const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule);
|
ConfigSubstitutions load(const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule);
|
||||||
void save(const std::string &file) const;
|
void save(const std::string &file) const;
|
||||||
|
|
||||||
|
@ -20,7 +20,10 @@
|
|||||||
#include "ClipperUtils.hpp"
|
#include "ClipperUtils.hpp"
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
#include "LocalesUtils.hpp"
|
#include "LocalesUtils.hpp"
|
||||||
#include "libslic3r/format.hpp"
|
#include "format.hpp"
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
#include "libslic3r_version.h"
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@ -556,6 +559,9 @@ void GCodeGenerator::do_export(Print* print, const char* path, GCodeProcessorRes
|
|||||||
|
|
||||||
m_processor.initialize(path_tmp);
|
m_processor.initialize(path_tmp);
|
||||||
m_processor.set_print(print);
|
m_processor.set_print(print);
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
m_processor.get_binary_data() = bgcode::binarize::BinaryData();
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
GCodeOutputStream file(boost::nowide::fopen(path_tmp.c_str(), "wb"), m_processor);
|
GCodeOutputStream file(boost::nowide::fopen(path_tmp.c_str(), "wb"), m_processor);
|
||||||
if (! file.is_open())
|
if (! file.is_open())
|
||||||
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
|
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
|
||||||
@ -688,68 +694,105 @@ namespace DoExport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fill in print_statistics and return formatted string containing filament statistics to be inserted into G-code comment section.
|
// Fill in print_statistics and return formatted string containing filament statistics to be inserted into G-code comment section.
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
static std::string update_print_stats_and_format_filament_stats(
|
static std::string update_print_stats_and_format_filament_stats(
|
||||||
const bool has_wipe_tower,
|
const bool has_wipe_tower,
|
||||||
const WipeTowerData &wipe_tower_data,
|
const WipeTowerData &wipe_tower_data,
|
||||||
|
const FullPrintConfig &config,
|
||||||
|
const std::vector<Extruder> &extruders,
|
||||||
|
unsigned int initial_extruder_id,
|
||||||
|
PrintStatistics &print_statistics,
|
||||||
|
bool export_binary_data,
|
||||||
|
bgcode::binarize::BinaryData &binary_data)
|
||||||
|
#else
|
||||||
|
static std::string update_print_stats_and_format_filament_stats(
|
||||||
|
const bool has_wipe_tower,
|
||||||
|
const WipeTowerData &wipe_tower_data,
|
||||||
const FullPrintConfig &config,
|
const FullPrintConfig &config,
|
||||||
const std::vector<Extruder> &extruders,
|
const std::vector<Extruder> &extruders,
|
||||||
unsigned int initial_extruder_id,
|
unsigned int initial_extruder_id,
|
||||||
PrintStatistics &print_statistics)
|
PrintStatistics &print_statistics)
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
{
|
{
|
||||||
std::string filament_stats_string_out;
|
std::string filament_stats_string_out;
|
||||||
|
|
||||||
print_statistics.clear();
|
print_statistics.clear();
|
||||||
print_statistics.total_toolchanges = std::max(0, wipe_tower_data.number_of_toolchanges);
|
print_statistics.total_toolchanges = std::max(0, wipe_tower_data.number_of_toolchanges);
|
||||||
print_statistics.initial_extruder_id = initial_extruder_id;
|
print_statistics.initial_extruder_id = initial_extruder_id;
|
||||||
std::vector<std::string> filament_types;
|
std::vector<std::string> filament_types;
|
||||||
if (! extruders.empty()) {
|
if (! extruders.empty()) {
|
||||||
std::pair<std::string, unsigned int> out_filament_used_mm ("; filament used [mm] = ", 0);
|
#if ENABLE_BINARIZED_GCODE
|
||||||
std::pair<std::string, unsigned int> out_filament_used_cm3("; filament used [cm3] = ", 0);
|
std::pair<std::string, unsigned int> out_filament_used_mm(PrintStatistics::FilamentUsedMmMask + " ", 0);
|
||||||
std::pair<std::string, unsigned int> out_filament_used_g ("; filament used [g] = ", 0);
|
std::pair<std::string, unsigned int> out_filament_used_cm3(PrintStatistics::FilamentUsedCm3Mask + " ", 0);
|
||||||
std::pair<std::string, unsigned int> out_filament_cost ("; filament cost = ", 0);
|
std::pair<std::string, unsigned int> out_filament_used_g(PrintStatistics::FilamentUsedGMask + " ", 0);
|
||||||
for (const Extruder &extruder : extruders) {
|
std::pair<std::string, unsigned int> out_filament_cost(PrintStatistics::FilamentCostMask + " ", 0);
|
||||||
|
#else
|
||||||
|
std::pair<std::string, unsigned int> out_filament_used_mm("; filament used [mm] = ", 0);
|
||||||
|
std::pair<std::string, unsigned int> out_filament_used_cm3("; filament used [cm3] = ", 0);
|
||||||
|
std::pair<std::string, unsigned int> out_filament_used_g ("; filament used [g] = ", 0);
|
||||||
|
std::pair<std::string, unsigned int> out_filament_cost("; filament cost = ", 0);
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
for (const Extruder &extruder : extruders) {
|
||||||
print_statistics.printing_extruders.emplace_back(extruder.id());
|
print_statistics.printing_extruders.emplace_back(extruder.id());
|
||||||
filament_types.emplace_back(config.filament_type.get_at(extruder.id()));
|
filament_types.emplace_back(config.filament_type.get_at(extruder.id()));
|
||||||
|
|
||||||
double used_filament = extruder.used_filament() + (has_wipe_tower ? wipe_tower_data.used_filament[extruder.id()] : 0.f);
|
double used_filament = extruder.used_filament() + (has_wipe_tower ? wipe_tower_data.used_filament[extruder.id()] : 0.f);
|
||||||
double extruded_volume = extruder.extruded_volume() + (has_wipe_tower ? wipe_tower_data.used_filament[extruder.id()] * 2.4052f : 0.f); // assumes 1.75mm filament diameter
|
double extruded_volume = extruder.extruded_volume() + (has_wipe_tower ? wipe_tower_data.used_filament[extruder.id()] * 2.4052f : 0.f); // assumes 1.75mm filament diameter
|
||||||
double filament_weight = extruded_volume * extruder.filament_density() * 0.001;
|
double filament_weight = extruded_volume * extruder.filament_density() * 0.001;
|
||||||
double filament_cost = filament_weight * extruder.filament_cost() * 0.001;
|
double filament_cost = filament_weight * extruder.filament_cost() * 0.001;
|
||||||
auto append = [&extruder](std::pair<std::string, unsigned int> &dst, const char *tmpl, double value) {
|
auto append = [&extruder](std::pair<std::string, unsigned int> &dst, const char *tmpl, double value) {
|
||||||
assert(is_decimal_separator_point());
|
assert(is_decimal_separator_point());
|
||||||
while (dst.second < extruder.id()) {
|
while (dst.second < extruder.id()) {
|
||||||
// Fill in the non-printing extruders with zeros.
|
// Fill in the non-printing extruders with zeros.
|
||||||
dst.first += (dst.second > 0) ? ", 0" : "0";
|
dst.first += (dst.second > 0) ? ", 0" : "0";
|
||||||
++ dst.second;
|
++ dst.second;
|
||||||
}
|
}
|
||||||
if (dst.second > 0)
|
if (dst.second > 0)
|
||||||
dst.first += ", ";
|
dst.first += ", ";
|
||||||
char buf[64];
|
char buf[64];
|
||||||
sprintf(buf, tmpl, value);
|
sprintf(buf, tmpl, value);
|
||||||
dst.first += buf;
|
dst.first += buf;
|
||||||
++ dst.second;
|
++ dst.second;
|
||||||
};
|
};
|
||||||
append(out_filament_used_mm, "%.2lf", used_filament);
|
#if ENABLE_BINARIZED_GCODE
|
||||||
append(out_filament_used_cm3, "%.2lf", extruded_volume * 0.001);
|
if (!export_binary_data) {
|
||||||
if (filament_weight > 0.) {
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
print_statistics.total_weight = print_statistics.total_weight + filament_weight;
|
append(out_filament_used_mm, "%.2lf", used_filament);
|
||||||
append(out_filament_used_g, "%.2lf", filament_weight);
|
append(out_filament_used_cm3, "%.2lf", extruded_volume * 0.001);
|
||||||
if (filament_cost > 0.) {
|
#if ENABLE_BINARIZED_GCODE
|
||||||
print_statistics.total_cost = print_statistics.total_cost + filament_cost;
|
}
|
||||||
append(out_filament_cost, "%.2lf", filament_cost);
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
}
|
if (filament_weight > 0.) {
|
||||||
}
|
print_statistics.total_weight = print_statistics.total_weight + filament_weight;
|
||||||
print_statistics.total_used_filament += used_filament;
|
#if ENABLE_BINARIZED_GCODE
|
||||||
print_statistics.total_extruded_volume += extruded_volume;
|
if (!export_binary_data)
|
||||||
print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.;
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.;
|
append(out_filament_used_g, "%.2lf", filament_weight);
|
||||||
}
|
if (filament_cost > 0.) {
|
||||||
filament_stats_string_out += out_filament_used_mm.first;
|
print_statistics.total_cost = print_statistics.total_cost + filament_cost;
|
||||||
filament_stats_string_out += "\n" + out_filament_used_cm3.first;
|
#if ENABLE_BINARIZED_GCODE
|
||||||
if (out_filament_used_g.second)
|
if (!export_binary_data)
|
||||||
filament_stats_string_out += "\n" + out_filament_used_g.first;
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
if (out_filament_cost.second)
|
append(out_filament_cost, "%.2lf", filament_cost);
|
||||||
filament_stats_string_out += "\n" + out_filament_cost.first;
|
}
|
||||||
|
}
|
||||||
|
print_statistics.total_used_filament += used_filament;
|
||||||
|
print_statistics.total_extruded_volume += extruded_volume;
|
||||||
|
print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.;
|
||||||
|
print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.;
|
||||||
|
}
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
if (!export_binary_data) {
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
filament_stats_string_out += out_filament_used_mm.first;
|
||||||
|
filament_stats_string_out += "\n" + out_filament_used_cm3.first;
|
||||||
|
if (out_filament_used_g.second)
|
||||||
|
filament_stats_string_out += "\n" + out_filament_used_g.first;
|
||||||
|
if (out_filament_cost.second)
|
||||||
|
filament_stats_string_out += "\n" + out_filament_cost.first;
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
print_statistics.initial_filament_type = config.filament_type.get_at(initial_extruder_id);
|
print_statistics.initial_filament_type = config.filament_type.get_at(initial_extruder_id);
|
||||||
std::sort(filament_types.begin(), filament_types.end());
|
std::sort(filament_types.begin(), filament_types.end());
|
||||||
print_statistics.printing_filament_types = filament_types.front();
|
print_statistics.printing_filament_types = filament_types.front();
|
||||||
@ -830,6 +873,94 @@ static inline GCode::SmoothPathCache smooth_path_interpolate_global(const Print&
|
|||||||
|
|
||||||
void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb)
|
void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||||
{
|
{
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
const bool export_to_binary_gcode = print.full_print_config().option<ConfigOptionBool>("gcode_binary")->value;
|
||||||
|
// if exporting gcode in binary format:
|
||||||
|
// we generate here the data to be passed to the post-processor, who is responsible to export them to file
|
||||||
|
// 1) generate the thumbnails
|
||||||
|
// 2) collect the config data
|
||||||
|
if (export_to_binary_gcode) {
|
||||||
|
bgcode::binarize::BinaryData& binary_data = m_processor.get_binary_data();
|
||||||
|
|
||||||
|
// Unit tests or command line slicing may not define "thumbnails" or "thumbnails_format".
|
||||||
|
// If "thumbnails_format" is not defined, export to PNG.
|
||||||
|
if (std::vector<std::pair<GCodeThumbnailsFormat, Vec2d>> thumbnails = GCodeThumbnails::make_thumbnail_list(print.full_print_config());
|
||||||
|
! thumbnails.empty())
|
||||||
|
GCodeThumbnails::generate_binary_thumbnails(
|
||||||
|
thumbnail_cb, binary_data.thumbnails, thumbnails,
|
||||||
|
[&print]() { print.throw_if_canceled(); });
|
||||||
|
|
||||||
|
// file data
|
||||||
|
binary_data.file_metadata.raw_data.emplace_back("Producer", std::string(SLIC3R_APP_NAME) + " " + std::string(SLIC3R_VERSION));
|
||||||
|
|
||||||
|
// config data
|
||||||
|
encode_full_config(print, binary_data.slicer_metadata.raw_data);
|
||||||
|
|
||||||
|
// printer data
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back("printer_model", print.config().printer_model.value); // duplicated into config data
|
||||||
|
std::string filament_types_str;
|
||||||
|
for (size_t i = 0; i < print.config().filament_type.values.size(); ++i) {
|
||||||
|
filament_types_str += print.config().filament_type.values[i];
|
||||||
|
if (i < print.config().filament_type.values.size() - 1)
|
||||||
|
filament_types_str += ";";
|
||||||
|
}
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back("filament_type", filament_types_str); // duplicated into config data
|
||||||
|
char buf[1024];
|
||||||
|
std::string nozzle_diameters_str;
|
||||||
|
for (size_t i = 0; i < print.config().nozzle_diameter.values.size(); ++i) {
|
||||||
|
sprintf(buf, i < print.config().nozzle_diameter.values.size() - 1 ? "%.2g," : "%.2g", print.config().nozzle_diameter.values[i]);
|
||||||
|
nozzle_diameters_str += buf;
|
||||||
|
}
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back("nozzle_diameter", nozzle_diameters_str); // duplicated into config data
|
||||||
|
std::string bed_temperatures_str;
|
||||||
|
for (size_t i = 0; i < print.config().bed_temperature.values.size(); ++i) {
|
||||||
|
sprintf(buf, i < print.config().bed_temperature.values.size() - 1 ? "%d," : "%d", print.config().bed_temperature.values[i]);
|
||||||
|
bed_temperatures_str += buf;
|
||||||
|
}
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back("bed_temperature", bed_temperatures_str); // duplicated into config data
|
||||||
|
|
||||||
|
const DynamicPrintConfig& cfg = print.full_print_config();
|
||||||
|
if (auto opt = cfg.option("brim_width"); opt != nullptr) {
|
||||||
|
sprintf(buf, "%.2g", dynamic_cast<const ConfigOptionFloat*>(opt)->value);
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back("brim_width", buf); // duplicated into config data
|
||||||
|
}
|
||||||
|
if (auto opt = cfg.option("fill_density"); opt != nullptr) {
|
||||||
|
sprintf(buf, "%.2g%%", dynamic_cast<const ConfigOptionPercent*>(opt)->value);
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back("fill_density", buf); // duplicated into config data
|
||||||
|
}
|
||||||
|
if (auto opt = cfg.option("layer_height"); opt != nullptr) {
|
||||||
|
sprintf(buf, "%.2g", dynamic_cast<const ConfigOptionFloat*>(opt)->value);
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back("layer_height", buf); // duplicated into config data
|
||||||
|
}
|
||||||
|
if (auto opt = cfg.option("temperature"); opt != nullptr) {
|
||||||
|
auto values = dynamic_cast<const ConfigOptionInts*>(opt)->values;
|
||||||
|
std::string temperatures_str;
|
||||||
|
for (size_t i = 0; i < values.size(); ++i) {
|
||||||
|
sprintf(buf, i < values.size() - 1 ? "%d," : "%d", values[i]);
|
||||||
|
temperatures_str += buf;
|
||||||
|
}
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back("temperature", temperatures_str); // duplicated into config data
|
||||||
|
}
|
||||||
|
if (auto opt = cfg.option("ironing"); opt != nullptr)
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back("ironing", dynamic_cast<const ConfigOptionBool*>(opt)->value ? "1" : "0"); // duplicated into config data
|
||||||
|
if (auto opt = cfg.option("support_material"); opt != nullptr)
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back("support_material", dynamic_cast<const ConfigOptionBool*>(opt)->value ? "1" : "0"); // duplicated into config data
|
||||||
|
if (auto opt = cfg.option("extruder_colour"); opt != nullptr) {
|
||||||
|
auto values = dynamic_cast<const ConfigOptionStrings*>(opt)->values;
|
||||||
|
std::string extruder_colours_str;
|
||||||
|
if (values.size() == 1 && values.front().empty())
|
||||||
|
extruder_colours_str = "\"\"";
|
||||||
|
else {
|
||||||
|
for (size_t i = 0; i < values.size(); ++i) {
|
||||||
|
sprintf(buf, i < values.size() - 1 ? "%s;" : "%s", values[i].c_str());
|
||||||
|
extruder_colours_str += buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back("extruder_colour", extruder_colours_str); // duplicated into config data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
// modifies m_silent_time_estimator_enabled
|
// modifies m_silent_time_estimator_enabled
|
||||||
DoExport::init_gcode_processor(print.config(), m_processor, m_silent_time_estimator_enabled);
|
DoExport::init_gcode_processor(print.config(), m_processor, m_silent_time_estimator_enabled);
|
||||||
|
|
||||||
@ -883,42 +1014,24 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
|||||||
this->m_avoid_crossing_curled_overhangs.init_bed_shape(get_bed_shape(print.config()));
|
this->m_avoid_crossing_curled_overhangs.init_bed_shape(get_bed_shape(print.config()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write information on the generator.
|
#if ENABLE_BINARIZED_GCODE
|
||||||
file.write_format("; %s\n\n", Slic3r::header_slic3r_generated().c_str());
|
if (!export_to_binary_gcode)
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
// Write information on the generator.
|
||||||
|
file.write_format("; %s\n\n", Slic3r::header_slic3r_generated().c_str());
|
||||||
|
|
||||||
// ??? Unit tests or command line slicing may not define "thumbnails" or "thumbnails_format".
|
#if ENABLE_BINARIZED_GCODE
|
||||||
// ??? If "thumbnails_format" is not defined, export to PNG.
|
// if exporting gcode in ascii format, generate the thumbnails here
|
||||||
|
if (! export_to_binary_gcode) {
|
||||||
// generate thumbnails data to process it
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
if (std::vector<std::pair<GCodeThumbnailsFormat, Vec2d>> thumbnails = GCodeThumbnails::make_thumbnail_list(print.full_print_config());
|
||||||
std::vector<std::pair<GCodeThumbnailsFormat, Vec2d>> thumbnails_list;
|
! thumbnails.empty())
|
||||||
if (const auto thumbnails_value = print.full_print_config().option<ConfigOptionString>("thumbnails")) {
|
GCodeThumbnails::export_thumbnails_to_file(thumbnail_cb, thumbnails,
|
||||||
std::string str = thumbnails_value->value;
|
[&file](const char* sz) { file.write(sz); },
|
||||||
std::istringstream is(str);
|
[&print]() { print.throw_if_canceled(); });
|
||||||
std::string point_str;
|
#if ENABLE_BINARIZED_GCODE
|
||||||
while (std::getline(is, point_str, ',')) {
|
|
||||||
Vec2d point(Vec2d::Zero());
|
|
||||||
GCodeThumbnailsFormat format;
|
|
||||||
std::istringstream iss(point_str);
|
|
||||||
std::string coord_str;
|
|
||||||
if (std::getline(iss, coord_str, 'x')) {
|
|
||||||
std::istringstream(coord_str) >> point(0);
|
|
||||||
if (std::getline(iss, coord_str, '/')) {
|
|
||||||
std::istringstream(coord_str) >> point(1);
|
|
||||||
std::string ext_str;
|
|
||||||
if (std::getline(iss, ext_str, '/'))
|
|
||||||
format = ext_str == "JPG" ? GCodeThumbnailsFormat::JPG :
|
|
||||||
ext_str == "QOI" ? GCodeThumbnailsFormat::QOI :GCodeThumbnailsFormat::PNG;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thumbnails_list.emplace_back(std::make_pair(format, point));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
if (!thumbnails_list.empty())
|
|
||||||
GCodeThumbnails::export_thumbnails_to_file(thumbnail_cb, thumbnails_list,
|
|
||||||
[&file](const char* sz) { file.write(sz); },
|
|
||||||
[&print]() { print.throw_if_canceled(); });
|
|
||||||
|
|
||||||
// Write notes (content of the Print Settings tab -> Notes)
|
// Write notes (content of the Print Settings tab -> Notes)
|
||||||
{
|
{
|
||||||
@ -940,20 +1053,26 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
|||||||
const double layer_height = first_object->config().layer_height.value;
|
const double layer_height = first_object->config().layer_height.value;
|
||||||
assert(! print.config().first_layer_height.percent);
|
assert(! print.config().first_layer_height.percent);
|
||||||
const double first_layer_height = print.config().first_layer_height.value;
|
const double first_layer_height = print.config().first_layer_height.value;
|
||||||
for (size_t region_id = 0; region_id < print.num_print_regions(); ++ region_id) {
|
#if ENABLE_BINARIZED_GCODE
|
||||||
const PrintRegion ®ion = print.get_print_region(region_id);
|
if (!export_to_binary_gcode) {
|
||||||
file.write_format("; external perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frExternalPerimeter, layer_height).width());
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
file.write_format("; perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, layer_height).width());
|
for (size_t region_id = 0; region_id < print.num_print_regions(); ++ region_id) {
|
||||||
file.write_format("; infill extrusion width = %.2fmm\n", region.flow(*first_object, frInfill, layer_height).width());
|
const PrintRegion ®ion = print.get_print_region(region_id);
|
||||||
file.write_format("; solid infill extrusion width = %.2fmm\n", region.flow(*first_object, frSolidInfill, layer_height).width());
|
file.write_format("; external perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frExternalPerimeter, layer_height).width());
|
||||||
file.write_format("; top infill extrusion width = %.2fmm\n", region.flow(*first_object, frTopSolidInfill, layer_height).width());
|
file.write_format("; perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, layer_height).width());
|
||||||
if (print.has_support_material())
|
file.write_format("; infill extrusion width = %.2fmm\n", region.flow(*first_object, frInfill, layer_height).width());
|
||||||
file.write_format("; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width());
|
file.write_format("; solid infill extrusion width = %.2fmm\n", region.flow(*first_object, frSolidInfill, layer_height).width());
|
||||||
if (print.config().first_layer_extrusion_width.value > 0)
|
file.write_format("; top infill extrusion width = %.2fmm\n", region.flow(*first_object, frTopSolidInfill, layer_height).width());
|
||||||
file.write_format("; first layer extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, first_layer_height, true).width());
|
if (print.has_support_material())
|
||||||
file.write_format("\n");
|
file.write_format("; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width());
|
||||||
|
if (print.config().first_layer_extrusion_width.value > 0)
|
||||||
|
file.write_format("; first layer extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, first_layer_height, true).width());
|
||||||
|
file.write_format("\n");
|
||||||
|
}
|
||||||
|
print.throw_if_canceled();
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
}
|
}
|
||||||
print.throw_if_canceled();
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
// adds tags for time estimators
|
// adds tags for time estimators
|
||||||
if (print.config().remaining_times.value)
|
if (print.config().remaining_times.value)
|
||||||
@ -1267,31 +1386,72 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
|||||||
print.throw_if_canceled();
|
print.throw_if_canceled();
|
||||||
|
|
||||||
// Get filament stats.
|
// Get filament stats.
|
||||||
file.write(DoExport::update_print_stats_and_format_filament_stats(
|
#if ENABLE_BINARIZED_GCODE
|
||||||
// Const inputs
|
const std::string filament_stats_string_out = DoExport::update_print_stats_and_format_filament_stats(
|
||||||
|
// Const inputs
|
||||||
has_wipe_tower, print.wipe_tower_data(),
|
has_wipe_tower, print.wipe_tower_data(),
|
||||||
this->config(),
|
this->config(),
|
||||||
m_writer.extruders(),
|
m_writer.extruders(),
|
||||||
initial_extruder_id,
|
initial_extruder_id,
|
||||||
// Modifies
|
// Modifies
|
||||||
print.m_print_statistics));
|
print.m_print_statistics,
|
||||||
file.write("\n");
|
export_to_binary_gcode,
|
||||||
file.write_format("; total filament used [g] = %.2lf\n", print.m_print_statistics.total_weight);
|
m_processor.get_binary_data()
|
||||||
file.write_format("; total filament cost = %.2lf\n", print.m_print_statistics.total_cost);
|
);
|
||||||
if (print.m_print_statistics.total_toolchanges > 0)
|
|
||||||
file.write_format("; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
|
|
||||||
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
|
|
||||||
|
|
||||||
// Append full config, delimited by two 'phony' configuration keys prusaslicer_config = begin and prusaslicer_config = end.
|
if (!export_to_binary_gcode)
|
||||||
// The delimiters are structured as configuration key / value pairs to be parsable by older versions of PrusaSlicer G-code viewer.
|
file.write(filament_stats_string_out);
|
||||||
{
|
|
||||||
file.write("\n; prusaslicer_config = begin\n");
|
if (export_to_binary_gcode) {
|
||||||
std::string full_config;
|
bgcode::binarize::BinaryData& binary_data = m_processor.get_binary_data();
|
||||||
append_full_config(print, full_config);
|
if (print.m_print_statistics.total_toolchanges > 0)
|
||||||
if (!full_config.empty())
|
binary_data.print_metadata.raw_data.emplace_back("total toolchanges", std::to_string(print.m_print_statistics.total_toolchanges));
|
||||||
file.write(full_config);
|
char buf[1024];
|
||||||
file.write("; prusaslicer_config = end\n");
|
sprintf(buf, "%.2lf", m_max_layer_z);
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back("max_layer_z", buf);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
#else
|
||||||
|
file.write(DoExport::update_print_stats_and_format_filament_stats(
|
||||||
|
// Const inputs
|
||||||
|
has_wipe_tower, print.wipe_tower_data(),
|
||||||
|
this->config(),
|
||||||
|
m_writer.extruders(),
|
||||||
|
initial_extruder_id,
|
||||||
|
// Modifies
|
||||||
|
print.m_print_statistics));
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
// if exporting gcode in ascii format, statistics export is done here
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
file.write("\n");
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
file.write_format(PrintStatistics::TotalFilamentUsedGValueMask.c_str(), print.m_print_statistics.total_weight);
|
||||||
|
file.write_format(PrintStatistics::TotalFilamentCostValueMask.c_str(), print.m_print_statistics.total_cost);
|
||||||
|
#else
|
||||||
|
file.write_format("; total filament used [g] = %.2lf\n", print.m_print_statistics.total_weight);
|
||||||
|
file.write_format("; total filament cost = %.2lf\n", print.m_print_statistics.total_cost);
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
if (print.m_print_statistics.total_toolchanges > 0)
|
||||||
|
file.write_format("; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
|
||||||
|
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
// if exporting gcode in ascii format, config export is done here
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
// Append full config, delimited by two 'phony' configuration keys prusaslicer_config = begin and prusaslicer_config = end.
|
||||||
|
// The delimiters are structured as configuration key / value pairs to be parsable by older versions of PrusaSlicer G-code viewer.
|
||||||
|
{
|
||||||
|
file.write("\n; prusaslicer_config = begin\n");
|
||||||
|
std::string full_config;
|
||||||
|
append_full_config(print, full_config);
|
||||||
|
if (!full_config.empty())
|
||||||
|
file.write(full_config);
|
||||||
|
file.write("; prusaslicer_config = end\n");
|
||||||
|
}
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
print.throw_if_canceled();
|
print.throw_if_canceled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2400,6 +2560,13 @@ void GCodeGenerator::apply_print_config(const PrintConfig &print_config)
|
|||||||
|
|
||||||
void GCodeGenerator::append_full_config(const Print &print, std::string &str)
|
void GCodeGenerator::append_full_config(const Print &print, std::string &str)
|
||||||
{
|
{
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
std::vector<std::pair<std::string, std::string>> config;
|
||||||
|
encode_full_config(print, config);
|
||||||
|
for (const auto& [key, value] : config) {
|
||||||
|
str += "; " + key + " = " + value + "\n";
|
||||||
|
}
|
||||||
|
#else
|
||||||
const DynamicPrintConfig &cfg = print.full_print_config();
|
const DynamicPrintConfig &cfg = print.full_print_config();
|
||||||
// Sorted list of config keys, which shall not be stored into the G-code. Initializer list.
|
// Sorted list of config keys, which shall not be stored into the G-code. Initializer list.
|
||||||
static constexpr auto banned_keys = {
|
static constexpr auto banned_keys = {
|
||||||
@ -2417,8 +2584,35 @@ void GCodeGenerator::append_full_config(const Print &print, std::string &str)
|
|||||||
for (const std::string &key : cfg.keys())
|
for (const std::string &key : cfg.keys())
|
||||||
if (! is_banned(key) && ! cfg.option(key)->is_nil())
|
if (! is_banned(key) && ! cfg.option(key)->is_nil())
|
||||||
str += "; " + key + " = " + cfg.opt_serialize(key) + "\n";
|
str += "; " + key + " = " + cfg.opt_serialize(key) + "\n";
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
void GCodeGenerator::encode_full_config(const Print& print, std::vector<std::pair<std::string, std::string>>& config)
|
||||||
|
{
|
||||||
|
const DynamicPrintConfig& cfg = print.full_print_config();
|
||||||
|
// Sorted list of config keys, which shall not be stored into the G-code. Initializer list.
|
||||||
|
static constexpr auto banned_keys = {
|
||||||
|
"compatible_printers"sv,
|
||||||
|
"compatible_prints"sv,
|
||||||
|
//FIXME The print host keys should not be exported to full_print_config anymore. The following keys may likely be removed.
|
||||||
|
"print_host"sv,
|
||||||
|
"printhost_apikey"sv,
|
||||||
|
"printhost_cafile"sv
|
||||||
|
};
|
||||||
|
assert(std::is_sorted(banned_keys.begin(), banned_keys.end()));
|
||||||
|
auto is_banned = [](const std::string& key) {
|
||||||
|
return std::binary_search(banned_keys.begin(), banned_keys.end(), key);
|
||||||
|
};
|
||||||
|
config.reserve(config.size() + cfg.keys().size());
|
||||||
|
for (const std::string& key : cfg.keys()) {
|
||||||
|
if (!is_banned(key) && !cfg.option(key)->is_nil())
|
||||||
|
config.emplace_back(key, cfg.opt_serialize(key));
|
||||||
|
}
|
||||||
|
config.shrink_to_fit();
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
void GCodeGenerator::set_extruders(const std::vector<unsigned int> &extruder_ids)
|
void GCodeGenerator::set_extruders(const std::vector<unsigned int> &extruder_ids)
|
||||||
{
|
{
|
||||||
m_writer.set_extruders(extruder_ids);
|
m_writer.set_extruders(extruder_ids);
|
||||||
|
@ -30,6 +30,12 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
//#include "GCode/PressureEqualizer.hpp"
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
#include <LibBGCode/binarize/binarize.hpp>
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
// Forward declarations.
|
// Forward declarations.
|
||||||
@ -148,6 +154,10 @@ public:
|
|||||||
|
|
||||||
// append full config to the given string
|
// append full config to the given string
|
||||||
static void append_full_config(const Print& print, std::string& str);
|
static void append_full_config(const Print& print, std::string& str);
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
// translate full config into a list of <key, value> items
|
||||||
|
static void encode_full_config(const Print& print, std::vector<std::pair<std::string, std::string>>& config);
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
// Object and support extrusions of the same PrintObject at the same print_z.
|
// Object and support extrusions of the same PrintObject at the same print_z.
|
||||||
// public, so that it could be accessed by free helper functions from GCode.cpp
|
// public, so that it could be accessed by free helper functions from GCode.cpp
|
||||||
|
@ -26,6 +26,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#if ENABLE_BINARIZED_GCODE_WIN_DEBUG
|
||||||
|
#include <windows.h>
|
||||||
|
#include <debugapi.h>
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE_WIN_DEBUG
|
||||||
|
|
||||||
static const float DEFAULT_TOOLPATH_WIDTH = 0.4f;
|
static const float DEFAULT_TOOLPATH_WIDTH = 0.4f;
|
||||||
static const float DEFAULT_TOOLPATH_HEIGHT = 0.2f;
|
static const float DEFAULT_TOOLPATH_HEIGHT = 0.2f;
|
||||||
@ -64,6 +68,21 @@ const std::vector<std::string> GCodeProcessor::Reserved_Tags = {
|
|||||||
const float GCodeProcessor::Wipe_Width = 0.05f;
|
const float GCodeProcessor::Wipe_Width = 0.05f;
|
||||||
const float GCodeProcessor::Wipe_Height = 0.05f;
|
const float GCodeProcessor::Wipe_Height = 0.05f;
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
bgcode::binarize::BinarizerConfig GCodeProcessor::s_binarizer_config{
|
||||||
|
{
|
||||||
|
bgcode::core::ECompressionType::None, // file metadata
|
||||||
|
bgcode::core::ECompressionType::None, // printer metadata
|
||||||
|
bgcode::core::ECompressionType::Deflate, // print metadata
|
||||||
|
bgcode::core::ECompressionType::Deflate, // slicer metadata
|
||||||
|
bgcode::core::ECompressionType::Heatshrink_12_4, // gcode
|
||||||
|
},
|
||||||
|
bgcode::core::EGCodeEncodingType::MeatPackComments,
|
||||||
|
bgcode::core::EMetadataEncodingType::INI,
|
||||||
|
bgcode::core::EChecksumType::CRC32
|
||||||
|
};
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||||
const std::string GCodeProcessor::Mm3_Per_Mm_Tag = "MM3_PER_MM:";
|
const std::string GCodeProcessor::Mm3_Per_Mm_Tag = "MM3_PER_MM:";
|
||||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||||
@ -455,6 +474,9 @@ void GCodeProcessorResult::reset() {
|
|||||||
#else
|
#else
|
||||||
void GCodeProcessorResult::reset() {
|
void GCodeProcessorResult::reset() {
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
is_binary_file = false;
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
moves.clear();
|
moves.clear();
|
||||||
lines_ends.clear();
|
lines_ends.clear();
|
||||||
bed_shape = Pointfs();
|
bed_shape = Pointfs();
|
||||||
@ -553,6 +575,11 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
|||||||
{
|
{
|
||||||
m_parser.apply_config(config);
|
m_parser.apply_config(config);
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
m_binarizer.set_enabled(config.gcode_binary);
|
||||||
|
m_result.is_binary_file = config.gcode_binary;
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
m_producer = EProducer::PrusaSlicer;
|
m_producer = EProducer::PrusaSlicer;
|
||||||
m_flavor = config.gcode_flavor;
|
m_flavor = config.gcode_flavor;
|
||||||
|
|
||||||
@ -1022,6 +1049,25 @@ static inline const char* remove_eols(const char *begin, const char *end) {
|
|||||||
// Load a G-code into a stand-alone G-code viewer.
|
// Load a G-code into a stand-alone G-code viewer.
|
||||||
// throws CanceledException through print->throw_if_canceled() (sent by the caller as callback).
|
// throws CanceledException through print->throw_if_canceled() (sent by the caller as callback).
|
||||||
void GCodeProcessor::process_file(const std::string& filename, std::function<void()> cancel_callback)
|
void GCodeProcessor::process_file(const std::string& filename, std::function<void()> cancel_callback)
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
{
|
||||||
|
FILE* file = boost::nowide::fopen(filename.c_str(), "rb");
|
||||||
|
if (file == nullptr)
|
||||||
|
throw Slic3r::RuntimeError("Error opening the file: " + filename + "\n");
|
||||||
|
|
||||||
|
using namespace bgcode::core;
|
||||||
|
std::vector<uint8_t> cs_buffer(65536);
|
||||||
|
const bool is_binary = is_valid_binary_gcode(*file, true, cs_buffer.data(), cs_buffer.size()) == EResult::Success;
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
if (is_binary)
|
||||||
|
process_binary_file(filename, cancel_callback);
|
||||||
|
else
|
||||||
|
process_ascii_file(filename, cancel_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCodeProcessor::process_ascii_file(const std::string& filename, std::function<void()> cancel_callback)
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
{
|
{
|
||||||
CNumericLocalesSetter locales_setter;
|
CNumericLocalesSetter locales_setter;
|
||||||
|
|
||||||
@ -1072,6 +1118,9 @@ void GCodeProcessor::process_file(const std::string& filename, std::function<voi
|
|||||||
|
|
||||||
// process gcode
|
// process gcode
|
||||||
m_result.filename = filename;
|
m_result.filename = filename;
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
m_result.is_binary_file = false;
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
m_result.id = ++s_result_id;
|
m_result.id = ++s_result_id;
|
||||||
initialize_result_moves();
|
initialize_result_moves();
|
||||||
size_t parse_line_callback_cntr = 10000;
|
size_t parse_line_callback_cntr = 10000;
|
||||||
@ -1089,6 +1138,203 @@ void GCodeProcessor::process_file(const std::string& filename, std::function<voi
|
|||||||
this->finalize(false);
|
this->finalize(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
static void update_lines_ends_and_out_file_pos(const std::string& out_string, std::vector<size_t>& lines_ends, size_t* out_file_pos)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < out_string.size(); ++i) {
|
||||||
|
if (out_string[i] == '\n')
|
||||||
|
lines_ends.emplace_back((out_file_pos != nullptr) ? *out_file_pos + i + 1 : i + 1);
|
||||||
|
}
|
||||||
|
if (out_file_pos != nullptr)
|
||||||
|
*out_file_pos += out_string.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCodeProcessor::process_binary_file(const std::string& filename, std::function<void()> cancel_callback)
|
||||||
|
{
|
||||||
|
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
|
m_start_time = std::chrono::high_resolution_clock::now();
|
||||||
|
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
|
|
||||||
|
FilePtr file{ boost::nowide::fopen(filename.c_str(), "rb") };
|
||||||
|
if (file.f == nullptr)
|
||||||
|
throw Slic3r::RuntimeError("Unable to open file: " + filename + "\n");
|
||||||
|
|
||||||
|
fseek(file.f, 0, SEEK_END);
|
||||||
|
const long file_size = ftell(file.f);
|
||||||
|
rewind(file.f);
|
||||||
|
|
||||||
|
// read file header
|
||||||
|
using namespace bgcode::core;
|
||||||
|
using namespace bgcode::binarize;
|
||||||
|
FileHeader file_header;
|
||||||
|
EResult res = read_header(*file.f, file_header, nullptr);
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("File: " + filename + "does not contain a valid binary gcode\n Error: " +
|
||||||
|
std::string(translate_result(res)) + "\n");
|
||||||
|
|
||||||
|
// read file metadata block
|
||||||
|
BlockHeader block_header;
|
||||||
|
std::vector<uint8_t> cs_buffer(65536);
|
||||||
|
res = read_next_block_header(*file.f, file_header, block_header, cs_buffer.data(), cs_buffer.size());
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("Error while reading file '" + filename + "': " + std::string(translate_result(res)) + "\n");
|
||||||
|
if ((EBlockType)block_header.type != EBlockType::FileMetadata)
|
||||||
|
throw Slic3r::RuntimeError("Unable to find file metadata block in file: " + filename + "\n");
|
||||||
|
FileMetadataBlock file_metadata_block;
|
||||||
|
res = file_metadata_block.read_data(*file.f, file_header, block_header);
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("Error while reading file '" + filename + "': " + std::string(translate_result(res)) + "\n");
|
||||||
|
auto producer_it = std::find_if(file_metadata_block.raw_data.begin(), file_metadata_block.raw_data.end(),
|
||||||
|
[](const std::pair<std::string, std::string>& item) { return item.first == "Producer"; });
|
||||||
|
if (producer_it != file_metadata_block.raw_data.end() && boost::starts_with(producer_it->second, std::string(SLIC3R_APP_NAME)))
|
||||||
|
m_producer = EProducer::PrusaSlicer;
|
||||||
|
else
|
||||||
|
m_producer = EProducer::Unknown;
|
||||||
|
|
||||||
|
// read printer metadata block
|
||||||
|
res = read_next_block_header(*file.f, file_header, block_header, cs_buffer.data(), cs_buffer.size());
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("Error while reading file '" + filename + "': " + std::string(translate_result(res)) + "\n");
|
||||||
|
if ((EBlockType)block_header.type != EBlockType::PrinterMetadata)
|
||||||
|
throw Slic3r::RuntimeError("Unable to find printer metadata block in file: " + filename + "\n");
|
||||||
|
PrinterMetadataBlock printer_metadata_block;
|
||||||
|
res = printer_metadata_block.read_data(*file.f, file_header, block_header);
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("Error while reading file '" + filename + "': " + std::string(translate_result(res)) + "\n");
|
||||||
|
#if ENABLE_BINARIZED_GCODE_WIN_DEBUG
|
||||||
|
OutputDebugStringA("Printer metadata:\n");
|
||||||
|
for (const auto& [key, value] : printer_metadata_block.raw_data) {
|
||||||
|
OutputDebugStringA(key.c_str());
|
||||||
|
OutputDebugStringA("->");
|
||||||
|
OutputDebugStringA(value.c_str());
|
||||||
|
OutputDebugStringA("\n");
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE_WIN_DEBUG
|
||||||
|
|
||||||
|
// read thumbnail blocks
|
||||||
|
res = read_next_block_header(*file.f, file_header, block_header, cs_buffer.data(), cs_buffer.size());
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("Error while reading file '" + filename + "': " + std::string(translate_result(res)) + "\n");
|
||||||
|
|
||||||
|
while ((EBlockType)block_header.type == EBlockType::Thumbnail) {
|
||||||
|
ThumbnailBlock thumbnail_block;
|
||||||
|
res = thumbnail_block.read_data(*file.f, file_header, block_header);
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("Error while reading file '" + filename + "': " + std::string(translate_result(res)) + "\n");
|
||||||
|
#if ENABLE_BINARIZED_GCODE_DEBUG
|
||||||
|
if (thumbnail_block.data.size() > 0) {
|
||||||
|
auto format_filename = [](const std::string& stem, const ThumbnailBlock& block) {
|
||||||
|
std::string ret = stem + "_" + std::to_string(block.params.width) + "x" + std::to_string(block.params.height);
|
||||||
|
switch ((EThumbnailFormat)block.params.format)
|
||||||
|
{
|
||||||
|
case EThumbnailFormat::PNG: { ret += ".png"; break; }
|
||||||
|
case EThumbnailFormat::JPG: { ret += ".jpg"; break; }
|
||||||
|
case EThumbnailFormat::QOI: { ret += ".qoi"; break; }
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
const boost::filesystem::path path(filename);
|
||||||
|
const std::string out_path = path.parent_path().string();
|
||||||
|
const std::string out_filename = out_path + "\\" + format_filename(path.stem().string(), thumbnail_block);
|
||||||
|
FILE* outfile = boost::nowide::fopen(out_filename.c_str(), "wb");
|
||||||
|
if (outfile != nullptr) {
|
||||||
|
fwrite((const void*)thumbnail_block.data.data(), 1, thumbnail_block.data.size(), outfile);
|
||||||
|
fclose(outfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE_DEBUG
|
||||||
|
|
||||||
|
res = read_next_block_header(*file.f, file_header, block_header, cs_buffer.data(), cs_buffer.size());
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("Error while reading file '" + filename + "': " + std::string(translate_result(res)) + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// read print metadata block
|
||||||
|
if ((EBlockType)block_header.type != EBlockType::PrintMetadata)
|
||||||
|
throw Slic3r::RuntimeError("Unable to find print metadata block in file: " + filename + "\n");
|
||||||
|
PrintMetadataBlock print_metadata_block;
|
||||||
|
res = print_metadata_block.read_data(*file.f, file_header, block_header);
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("Error while reading file '" + filename + "': " + std::string(translate_result(res)) + "\n");
|
||||||
|
#if ENABLE_BINARIZED_GCODE_WIN_DEBUG
|
||||||
|
OutputDebugStringA("Print metadata:\n");
|
||||||
|
for (const auto& [key, value] : print_metadata_block.raw_data) {
|
||||||
|
OutputDebugStringA(key.c_str());
|
||||||
|
OutputDebugStringA("->");
|
||||||
|
OutputDebugStringA(value.c_str());
|
||||||
|
OutputDebugStringA("\n");
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE_WIN_DEBUG
|
||||||
|
|
||||||
|
// read slicer metadata block
|
||||||
|
res = read_next_block_header(*file.f, file_header, block_header, cs_buffer.data(), cs_buffer.size());
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("Error while reading file '" + filename + "': " + std::string(translate_result(res)) + "\n");
|
||||||
|
if ((EBlockType)block_header.type != EBlockType::SlicerMetadata)
|
||||||
|
throw Slic3r::RuntimeError("Unable to find slicer metadata block in file: " + filename + "\n");
|
||||||
|
SlicerMetadataBlock slicer_metadata_block;
|
||||||
|
res = slicer_metadata_block.read_data(*file.f, file_header, block_header);
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("Error while reading file '" + filename + "': " + std::string(translate_result(res)) + "\n");
|
||||||
|
#if ENABLE_BINARIZED_GCODE_WIN_DEBUG
|
||||||
|
OutputDebugStringA("Slicer metadata:\n");
|
||||||
|
for (const auto& [key, value] : slicer_metadata_block.raw_data) {
|
||||||
|
OutputDebugStringA(key.c_str());
|
||||||
|
OutputDebugStringA("->");
|
||||||
|
OutputDebugStringA(value.c_str());
|
||||||
|
OutputDebugStringA("\n");
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE_WIN_DEBUG
|
||||||
|
DynamicPrintConfig config;
|
||||||
|
config.apply(FullPrintConfig::defaults());
|
||||||
|
std::string str;
|
||||||
|
for (const auto& [key, value] : slicer_metadata_block.raw_data) {
|
||||||
|
str += key + " = " + value + "\n";
|
||||||
|
}
|
||||||
|
// Silently substitute unknown values by new ones for loading configurations from PrusaSlicer's own G-code.
|
||||||
|
// Showing substitution log or errors may make sense, but we are not really reading many values from the G-code config,
|
||||||
|
// thus a probability of incorrect substitution is low and the G-code viewer is a consumer-only anyways.
|
||||||
|
config.load_from_ini_string(str, ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||||
|
apply_config(config);
|
||||||
|
|
||||||
|
m_result.filename = filename;
|
||||||
|
m_result.is_binary_file = true;
|
||||||
|
m_result.id = ++s_result_id;
|
||||||
|
initialize_result_moves();
|
||||||
|
|
||||||
|
// read gcodes block
|
||||||
|
res = read_next_block_header(*file.f, file_header, block_header, cs_buffer.data(), cs_buffer.size());
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("Error while reading file '" + filename + "': " + std::string(translate_result(res)) + "\n");
|
||||||
|
if ((EBlockType)block_header.type != EBlockType::GCode)
|
||||||
|
throw Slic3r::RuntimeError("Unable to find gcode block in file: " + filename + "\n");
|
||||||
|
while ((EBlockType)block_header.type == EBlockType::GCode) {
|
||||||
|
GCodeBlock block;
|
||||||
|
res = block.read_data(*file.f, file_header, block_header);
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("Error while reading file '" + filename + "': " + std::string(translate_result(res)) + "\n");
|
||||||
|
|
||||||
|
std::vector<size_t>& lines_ends = m_result.lines_ends.emplace_back(std::vector<size_t>());
|
||||||
|
update_lines_ends_and_out_file_pos(block.raw_data, lines_ends, nullptr);
|
||||||
|
|
||||||
|
m_parser.parse_buffer(block.raw_data, [this](GCodeReader& reader, const GCodeReader::GCodeLine& line) {
|
||||||
|
this->process_gcode_line(line, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ftell(file.f) == file_size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
res = read_next_block_header(*file.f, file_header, block_header, cs_buffer.data(), cs_buffer.size());
|
||||||
|
if (res != EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError("Error while reading file '" + filename + "': " + std::string(translate_result(res)) + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't post-process the G-code to update time stamps.
|
||||||
|
this->finalize(false);
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
void GCodeProcessor::initialize(const std::string& filename)
|
void GCodeProcessor::initialize(const std::string& filename)
|
||||||
{
|
{
|
||||||
assert(is_decimal_separator_point());
|
assert(is_decimal_separator_point());
|
||||||
@ -1131,7 +1377,7 @@ void GCodeProcessor::finalize(bool perform_post_process)
|
|||||||
|
|
||||||
m_used_filaments.process_caches(this);
|
m_used_filaments.process_caches(this);
|
||||||
|
|
||||||
update_estimated_times_stats();
|
update_estimated_statistics();
|
||||||
|
|
||||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
@ -3457,10 +3703,72 @@ void GCodeProcessor::post_process()
|
|||||||
// temporary file to contain modified gcode
|
// temporary file to contain modified gcode
|
||||||
std::string out_path = m_result.filename + ".postprocess";
|
std::string out_path = m_result.filename + ".postprocess";
|
||||||
FilePtr out{ boost::nowide::fopen(out_path.c_str(), "wb") };
|
FilePtr out{ boost::nowide::fopen(out_path.c_str(), "wb") };
|
||||||
if (out.f == nullptr) {
|
if (out.f == nullptr)
|
||||||
throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nCannot open file for writing.\n"));
|
throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nCannot open file for writing.\n"));
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
std::vector<double> filament_mm(m_result.extruders_count, 0.0);
|
||||||
|
std::vector<double> filament_cm3(m_result.extruders_count, 0.0);
|
||||||
|
std::vector<double> filament_g(m_result.extruders_count, 0.0);
|
||||||
|
std::vector<double> filament_cost(m_result.extruders_count, 0.0);
|
||||||
|
|
||||||
|
double filament_total_g = 0.0;
|
||||||
|
double filament_total_cost = 0.0;
|
||||||
|
|
||||||
|
for (const auto& [id, volume] : m_result.print_statistics.volumes_per_extruder) {
|
||||||
|
filament_mm[id] = volume / (static_cast<double>(M_PI) * sqr(0.5 * m_result.filament_diameters[id]));
|
||||||
|
filament_cm3[id] = volume * 0.001;
|
||||||
|
filament_g[id] = filament_cm3[id] * double(m_result.filament_densities[id]);
|
||||||
|
filament_cost[id] = filament_g[id] * double(m_result.filament_cost[id]) * 0.001;
|
||||||
|
filament_total_g += filament_g[id];
|
||||||
|
filament_total_cost += filament_cost[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_binarizer.is_enabled()) {
|
||||||
|
// update print metadata
|
||||||
|
auto stringify = [](const std::vector<double>& values) {
|
||||||
|
std::string ret;
|
||||||
|
char buf[1024];
|
||||||
|
for (size_t i = 0; i < values.size(); ++i) {
|
||||||
|
sprintf(buf, i < values.size() - 1 ? "%.2lf, " : "%.2lf", values[i]);
|
||||||
|
ret += buf;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
// update binary data
|
||||||
|
bgcode::binarize::BinaryData& binary_data = m_binarizer.get_binary_data();
|
||||||
|
binary_data.print_metadata.raw_data.emplace_back(PrintStatistics::FilamentUsedMm, stringify(filament_mm));
|
||||||
|
binary_data.print_metadata.raw_data.emplace_back(PrintStatistics::FilamentUsedCm3, stringify(filament_cm3));
|
||||||
|
binary_data.print_metadata.raw_data.emplace_back(PrintStatistics::FilamentUsedG, stringify(filament_g));
|
||||||
|
binary_data.print_metadata.raw_data.emplace_back(PrintStatistics::FilamentCost, stringify(filament_cost));
|
||||||
|
binary_data.print_metadata.raw_data.emplace_back(PrintStatistics::TotalFilamentUsedG, stringify({ filament_total_g }));
|
||||||
|
binary_data.print_metadata.raw_data.emplace_back(PrintStatistics::TotalFilamentCost, stringify({ filament_total_cost }));
|
||||||
|
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back(PrintStatistics::FilamentUsedMm, stringify(filament_mm)); // duplicated into print metadata
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back(PrintStatistics::FilamentUsedG, stringify(filament_g)); // duplicated into print metadata
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back(PrintStatistics::FilamentCost, stringify(filament_cost)); // duplicated into print metadata
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back(PrintStatistics::FilamentUsedCm3, stringify(filament_cm3)); // duplicated into print metadata
|
||||||
|
|
||||||
|
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||||
|
const TimeMachine& machine = m_time_processor.machines[i];
|
||||||
|
PrintEstimatedStatistics::ETimeMode mode = static_cast<PrintEstimatedStatistics::ETimeMode>(i);
|
||||||
|
if (mode == PrintEstimatedStatistics::ETimeMode::Normal || machine.enabled) {
|
||||||
|
char buf[128];
|
||||||
|
sprintf(buf, "(%s mode)", (mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent");
|
||||||
|
binary_data.print_metadata.raw_data.emplace_back("estimated printing time " + std::string(buf), get_time_dhms(machine.time));
|
||||||
|
binary_data.print_metadata.raw_data.emplace_back("estimated first layer printing time " + std::string(buf), get_time_dhms(machine.layers_time.empty() ? 0.f : machine.layers_time.front()));
|
||||||
|
|
||||||
|
binary_data.printer_metadata.raw_data.emplace_back("estimated printing time " + std::string(buf), get_time_dhms(machine.time));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bgcode::core::EResult res = m_binarizer.initialize(*out.f, s_binarizer_config);
|
||||||
|
if (res != bgcode::core::EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError(std::string("Unable to initialize the gcode binarizer.\n"));
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
auto time_in_minutes = [](float time_in_seconds) {
|
auto time_in_minutes = [](float time_in_seconds) {
|
||||||
assert(time_in_seconds >= 0.f);
|
assert(time_in_seconds >= 0.f);
|
||||||
return int((time_in_seconds + 0.5f) / 60.0f);
|
return int((time_in_seconds + 0.5f) / 60.0f);
|
||||||
@ -3577,13 +3885,26 @@ void GCodeProcessor::post_process()
|
|||||||
size_t m_curr_g1_id{ 0 };
|
size_t m_curr_g1_id{ 0 };
|
||||||
size_t m_out_file_pos{ 0 };
|
size_t m_out_file_pos{ 0 };
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
bgcode::binarize::Binarizer& m_binarizer;
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
ExportLines(bgcode::binarize::Binarizer& binarizer, EWriteType type, TimeMachine& machine)
|
||||||
|
#ifndef NDEBUG
|
||||||
|
: m_statistics(*this), m_binarizer(binarizer), m_write_type(type), m_machine(machine) {}
|
||||||
|
#else
|
||||||
|
: m_binarizer(binarizer), m_write_type(type), m_machine(machine) {}
|
||||||
|
#endif // NDEBUG
|
||||||
|
#else
|
||||||
ExportLines(EWriteType type, TimeMachine& machine)
|
ExportLines(EWriteType type, TimeMachine& machine)
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
: m_statistics(*this), m_write_type(type), m_machine(machine) {}
|
: m_statistics(*this), m_write_type(type), m_machine(machine) {}
|
||||||
#else
|
#else
|
||||||
: m_write_type(type), m_machine(machine) {}
|
: m_write_type(type), m_machine(machine) {}
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
void update(size_t lines_counter, size_t g1_lines_counter) {
|
void update(size_t lines_counter, size_t g1_lines_counter) {
|
||||||
m_gcode_lines_map.push_back({ lines_counter, 0 });
|
m_gcode_lines_map.push_back({ lines_counter, 0 });
|
||||||
@ -3694,7 +4015,18 @@ void GCodeProcessor::post_process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
if (m_binarizer.is_enabled()) {
|
||||||
|
if (m_binarizer.append_gcode(out_string) != bgcode::core::EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError(std::string("Error while sending gcode to the binarizer.\n"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
write_to_file(out, out_string, result, out_path);
|
||||||
|
update_lines_ends_and_out_file_pos(out_string, result.lines_ends.front(), &m_out_file_pos);
|
||||||
|
}
|
||||||
|
#else
|
||||||
write_to_file(out, out_string, result, out_path);
|
write_to_file(out, out_string, result, out_path);
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
}
|
}
|
||||||
|
|
||||||
// flush the current content of the cache to file
|
// flush the current content of the cache to file
|
||||||
@ -3710,7 +4042,18 @@ void GCodeProcessor::post_process()
|
|||||||
m_statistics.remove_all_lines();
|
m_statistics.remove_all_lines();
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
if (m_binarizer.is_enabled()) {
|
||||||
|
if (m_binarizer.append_gcode(out_string) != bgcode::core::EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError(std::string("Error while sending gcode to the binarizer.\n"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
write_to_file(out, out_string, result, out_path);
|
||||||
|
update_lines_ends_and_out_file_pos(out_string, result.lines_ends.front(), &m_out_file_pos);
|
||||||
|
}
|
||||||
|
#else
|
||||||
write_to_file(out, out_string, result, out_path);
|
write_to_file(out, out_string, result, out_path);
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
}
|
}
|
||||||
|
|
||||||
void synchronize_moves(GCodeProcessorResult& result) const {
|
void synchronize_moves(GCodeProcessorResult& result) const {
|
||||||
@ -3729,22 +4072,33 @@ void GCodeProcessor::post_process()
|
|||||||
private:
|
private:
|
||||||
void write_to_file(FilePtr& out, const std::string& out_string, GCodeProcessorResult& result, const std::string& out_path) {
|
void write_to_file(FilePtr& out, const std::string& out_string, GCodeProcessorResult& result, const std::string& out_path) {
|
||||||
if (!out_string.empty()) {
|
if (!out_string.empty()) {
|
||||||
fwrite((const void*)out_string.c_str(), 1, out_string.length(), out.f);
|
#if ENABLE_BINARIZED_GCODE
|
||||||
if (ferror(out.f)) {
|
if (!m_binarizer.is_enabled()) {
|
||||||
out.close();
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
boost::nowide::remove(out_path.c_str());
|
fwrite((const void*)out_string.c_str(), 1, out_string.length(), out.f);
|
||||||
throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nIs the disk full?\n"));
|
if (ferror(out.f)) {
|
||||||
|
out.close();
|
||||||
|
boost::nowide::remove(out_path.c_str());
|
||||||
|
throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nIs the disk full?\n"));
|
||||||
|
}
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
for (size_t i = 0; i < out_string.size(); ++i) {
|
for (size_t i = 0; i < out_string.size(); ++i) {
|
||||||
if (out_string[i] == '\n')
|
if (out_string[i] == '\n')
|
||||||
result.lines_ends.emplace_back(m_out_file_pos + i + 1);
|
result.lines_ends.emplace_back(m_out_file_pos + i + 1);
|
||||||
}
|
}
|
||||||
m_out_file_pos += out_string.size();
|
m_out_file_pos += out_string.size();
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
ExportLines export_lines(m_binarizer, m_result.backtrace_enabled ? ExportLines::EWriteType::ByTime : ExportLines::EWriteType::BySize, m_time_processor.machines[0]);
|
||||||
|
#else
|
||||||
ExportLines export_lines(m_result.backtrace_enabled ? ExportLines::EWriteType::ByTime : ExportLines::EWriteType::BySize, m_time_processor.machines[0]);
|
ExportLines export_lines(m_result.backtrace_enabled ? ExportLines::EWriteType::ByTime : ExportLines::EWriteType::BySize, m_time_processor.machines[0]);
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
// replace placeholder lines with the proper final value
|
// replace placeholder lines with the proper final value
|
||||||
// gcode_line is in/out parameter, to reduce expensive memory allocation
|
// gcode_line is in/out parameter, to reduce expensive memory allocation
|
||||||
@ -3807,6 +4161,7 @@ void GCodeProcessor::post_process()
|
|||||||
return processed;
|
return processed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if !ENABLE_BINARIZED_GCODE
|
||||||
std::vector<double> filament_mm(m_result.extruders_count, 0.0);
|
std::vector<double> filament_mm(m_result.extruders_count, 0.0);
|
||||||
std::vector<double> filament_cm3(m_result.extruders_count, 0.0);
|
std::vector<double> filament_cm3(m_result.extruders_count, 0.0);
|
||||||
std::vector<double> filament_g(m_result.extruders_count, 0.0);
|
std::vector<double> filament_g(m_result.extruders_count, 0.0);
|
||||||
@ -3823,6 +4178,7 @@ void GCodeProcessor::post_process()
|
|||||||
filament_total_g += filament_g[id];
|
filament_total_g += filament_g[id];
|
||||||
filament_total_cost += filament_cost[id];
|
filament_total_cost += filament_cost[id];
|
||||||
}
|
}
|
||||||
|
#endif // !ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
auto process_used_filament = [&](std::string& gcode_line) {
|
auto process_used_filament = [&](std::string& gcode_line) {
|
||||||
// Prefilter for parsing speed.
|
// Prefilter for parsing speed.
|
||||||
@ -3844,12 +4200,21 @@ void GCodeProcessor::post_process()
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
ret |= process_tag(gcode_line, PrintStatistics::FilamentUsedMmMask, filament_mm);
|
||||||
|
ret |= process_tag(gcode_line, PrintStatistics::FilamentUsedGMask, filament_g);
|
||||||
|
ret |= process_tag(gcode_line, PrintStatistics::TotalFilamentUsedGMask, { filament_total_g });
|
||||||
|
ret |= process_tag(gcode_line, PrintStatistics::FilamentUsedCm3Mask, filament_cm3);
|
||||||
|
ret |= process_tag(gcode_line, PrintStatistics::FilamentCostMask, filament_cost);
|
||||||
|
ret |= process_tag(gcode_line, PrintStatistics::TotalFilamentCostMask, { filament_total_cost });
|
||||||
|
#else
|
||||||
ret |= process_tag(gcode_line, "; filament used [mm] =", filament_mm);
|
ret |= process_tag(gcode_line, "; filament used [mm] =", filament_mm);
|
||||||
ret |= process_tag(gcode_line, "; filament used [g] =", filament_g);
|
ret |= process_tag(gcode_line, "; filament used [g] =", filament_g);
|
||||||
ret |= process_tag(gcode_line, "; total filament used [g] =", { filament_total_g });
|
ret |= process_tag(gcode_line, "; total filament used [g] =", { filament_total_g });
|
||||||
ret |= process_tag(gcode_line, "; filament used [cm3] =", filament_cm3);
|
ret |= process_tag(gcode_line, "; filament used [cm3] =", filament_cm3);
|
||||||
ret |= process_tag(gcode_line, "; filament cost =", filament_cost);
|
ret |= process_tag(gcode_line, "; filament cost =", filament_cost);
|
||||||
ret |= process_tag(gcode_line, "; total filament cost =", { filament_total_cost });
|
ret |= process_tag(gcode_line, "; total filament cost =", { filament_total_cost });
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3988,6 +4353,9 @@ void GCodeProcessor::post_process()
|
|||||||
};
|
};
|
||||||
|
|
||||||
m_result.lines_ends.clear();
|
m_result.lines_ends.clear();
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
m_result.lines_ends.emplace_back(std::vector<size_t>());
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
unsigned int line_id = 0;
|
unsigned int line_id = 0;
|
||||||
// Backtrace data for Tx gcode lines
|
// Backtrace data for Tx gcode lines
|
||||||
@ -4057,9 +4425,70 @@ void GCodeProcessor::post_process()
|
|||||||
|
|
||||||
export_lines.flush(out, m_result, out_path);
|
export_lines.flush(out, m_result, out_path);
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
if (m_binarizer.is_enabled()) {
|
||||||
|
if (m_binarizer.finalize() != bgcode::core::EResult::Success)
|
||||||
|
throw Slic3r::RuntimeError(std::string("Error while finalizing the gcode binarizer.\n"));
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
out.close();
|
out.close();
|
||||||
in.close();
|
in.close();
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
if (m_binarizer.is_enabled()) {
|
||||||
|
// updates m_result.lines_ends from binarized gcode file
|
||||||
|
m_result.lines_ends.clear();
|
||||||
|
|
||||||
|
FilePtr file(boost::nowide::fopen(out_path.c_str(), "rb"));
|
||||||
|
if (file.f != nullptr) {
|
||||||
|
fseek(file.f, 0, SEEK_END);
|
||||||
|
const long file_size = ftell(file.f);
|
||||||
|
rewind(file.f);
|
||||||
|
|
||||||
|
// read file header
|
||||||
|
using namespace bgcode::core;
|
||||||
|
using namespace bgcode::binarize;
|
||||||
|
FileHeader file_header;
|
||||||
|
EResult res = read_header(*file.f, file_header, nullptr);
|
||||||
|
if (res == EResult::Success) {
|
||||||
|
// search first GCode block
|
||||||
|
BlockHeader block_header;
|
||||||
|
res = read_next_block_header(*file.f, file_header, block_header, EBlockType::GCode, nullptr, 0);
|
||||||
|
while (res == EResult::Success) {
|
||||||
|
GCodeBlock block;
|
||||||
|
res = block.read_data(*file.f, file_header, block_header);
|
||||||
|
if (res != EResult::Success)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// extract lines ends from block
|
||||||
|
std::vector<size_t>& lines_ends = m_result.lines_ends.emplace_back(std::vector<size_t>());
|
||||||
|
for (size_t i = 0; i < block.raw_data.size(); ++i) {
|
||||||
|
if (block.raw_data[i] == '\n')
|
||||||
|
lines_ends.emplace_back(i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftell(file.f) == file_size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// read next block header
|
||||||
|
res = read_next_block_header(*file.f, file_header, block_header, nullptr, 0);
|
||||||
|
if (res != EResult::Success)
|
||||||
|
break;
|
||||||
|
if (block_header.type != (uint16_t)EBlockType::GCode) {
|
||||||
|
res = EResult::InvalidBlockType;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res != EResult::Success && !m_result.lines_ends.empty() && !m_result.lines_ends.front().empty())
|
||||||
|
// some error occourred, clear lines ends
|
||||||
|
m_result.lines_ends = { std::vector<size_t>() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
export_lines.synchronize_moves(m_result);
|
export_lines.synchronize_moves(m_result);
|
||||||
|
|
||||||
if (rename_file(out_path, m_result.filename))
|
if (rename_file(out_path, m_result.filename))
|
||||||
@ -4264,7 +4693,7 @@ void GCodeProcessor::simulate_st_synchronize(float additional_time)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeProcessor::update_estimated_times_stats()
|
void GCodeProcessor::update_estimated_statistics()
|
||||||
{
|
{
|
||||||
auto update_mode = [this](PrintEstimatedStatistics::ETimeMode mode) {
|
auto update_mode = [this](PrintEstimatedStatistics::ETimeMode mode) {
|
||||||
PrintEstimatedStatistics::Mode& data = m_result.print_statistics.modes[static_cast<size_t>(mode)];
|
PrintEstimatedStatistics::Mode& data = m_result.print_statistics.modes[static_cast<size_t>(mode)];
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
#include "libslic3r/PrintConfig.hpp"
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
#include "libslic3r/CustomGCode.hpp"
|
#include "libslic3r/CustomGCode.hpp"
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
#include <LibBGCode/binarize/binarize.hpp>
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -66,10 +70,10 @@ namespace Slic3r {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<double> volumes_per_color_change;
|
std::vector<double> volumes_per_color_change;
|
||||||
std::map<size_t, double> volumes_per_extruder;
|
std::map<size_t, double> volumes_per_extruder;
|
||||||
std::map<GCodeExtrusionRole, std::pair<double, double>> used_filaments_per_role;
|
std::map<GCodeExtrusionRole, std::pair<double, double>> used_filaments_per_role;
|
||||||
std::map<size_t, double> cost_per_extruder;
|
std::map<size_t, double> cost_per_extruder;
|
||||||
|
|
||||||
std::array<Mode, static_cast<size_t>(ETimeMode::Count)> modes;
|
std::array<Mode, static_cast<size_t>(ETimeMode::Count)> modes;
|
||||||
|
|
||||||
@ -140,10 +144,17 @@ namespace Slic3r {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::string filename;
|
std::string filename;
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
bool is_binary_file;
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
std::vector<MoveVertex> moves;
|
std::vector<MoveVertex> moves;
|
||||||
// Positions of ends of lines of the final G-code this->filename after TimeProcessor::post_process() finalizes the G-code.
|
// Positions of ends of lines of the final G-code this->filename after TimeProcessor::post_process() finalizes the G-code.
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
std::vector<std::vector<size_t>> lines_ends;
|
||||||
|
#else
|
||||||
std::vector<size_t> lines_ends;
|
std::vector<size_t> lines_ends;
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
Pointfs bed_shape;
|
Pointfs bed_shape;
|
||||||
float max_print_height;
|
float max_print_height;
|
||||||
SettingsIds settings_ids;
|
SettingsIds settings_ids;
|
||||||
@ -528,8 +539,16 @@ namespace Slic3r {
|
|||||||
};
|
};
|
||||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE_DEBUG_WINDOW
|
||||||
|
static bgcode::binarize::BinarizerConfig& get_binarizer_config() { return s_binarizer_config; }
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE_DEBUG_WINDOW
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GCodeReader m_parser;
|
GCodeReader m_parser;
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
bgcode::binarize::Binarizer m_binarizer;
|
||||||
|
static bgcode::binarize::BinarizerConfig s_binarizer_config;
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
EUnits m_units;
|
EUnits m_units;
|
||||||
EPositioningType m_global_positioning_type;
|
EPositioningType m_global_positioning_type;
|
||||||
@ -627,6 +646,10 @@ namespace Slic3r {
|
|||||||
|
|
||||||
void apply_config(const PrintConfig& config);
|
void apply_config(const PrintConfig& config);
|
||||||
void set_print(Print* print) { m_print = print; }
|
void set_print(Print* print) { m_print = print; }
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
bgcode::binarize::BinaryData& get_binary_data() { return m_binarizer.get_binary_data(); }
|
||||||
|
const bgcode::binarize::BinaryData& get_binary_data() const { return m_binarizer.get_binary_data(); }
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
void enable_stealth_time_estimator(bool enabled);
|
void enable_stealth_time_estimator(bool enabled);
|
||||||
bool is_stealth_time_estimator_enabled() const {
|
bool is_stealth_time_estimator_enabled() const {
|
||||||
@ -669,6 +692,11 @@ namespace Slic3r {
|
|||||||
void apply_config_kissslicer(const std::string& filename);
|
void apply_config_kissslicer(const std::string& filename);
|
||||||
void process_gcode_line(const GCodeReader::GCodeLine& line, bool producers_enabled);
|
void process_gcode_line(const GCodeReader::GCodeLine& line, bool producers_enabled);
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
void process_ascii_file(const std::string& filename, std::function<void()> cancel_callback = nullptr);
|
||||||
|
void process_binary_file(const std::string& filename, std::function<void()> cancel_callback = nullptr);
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
// Process tags embedded into comments
|
// Process tags embedded into comments
|
||||||
void process_tags(const std::string_view comment, bool producers_enabled);
|
void process_tags(const std::string_view comment, bool producers_enabled);
|
||||||
bool process_producers_tags(const std::string_view comment);
|
bool process_producers_tags(const std::string_view comment);
|
||||||
@ -824,7 +852,7 @@ namespace Slic3r {
|
|||||||
// Simulates firmware st_synchronize() call
|
// Simulates firmware st_synchronize() call
|
||||||
void simulate_st_synchronize(float additional_time = 0.0f);
|
void simulate_st_synchronize(float additional_time = 0.0f);
|
||||||
|
|
||||||
void update_estimated_times_stats();
|
void update_estimated_statistics();
|
||||||
|
|
||||||
double extract_absolute_position_on_axis(Axis axis, const GCodeReader::GCodeLine& line, double area_filament_cross_section);
|
double extract_absolute_position_on_axis(Axis axis, const GCodeReader::GCodeLine& line, double area_filament_cross_section);
|
||||||
};
|
};
|
||||||
|
@ -116,4 +116,38 @@ std::unique_ptr<CompressedImageBuffer> compress_thumbnail(const ThumbnailData &d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<GCodeThumbnailsFormat, Vec2d>> make_thumbnail_list(const DynamicPrintConfig &config)
|
||||||
|
{
|
||||||
|
// ??? Unit tests or command line slicing may not define "thumbnails" or "thumbnails_format".
|
||||||
|
// ??? If "thumbnails_format" is not defined, export to PNG.
|
||||||
|
|
||||||
|
// generate thumbnails data to process it
|
||||||
|
|
||||||
|
std::vector<std::pair<GCodeThumbnailsFormat, Vec2d>> thumbnails_list;
|
||||||
|
if (const auto thumbnails_value = config.option<ConfigOptionString>("thumbnails")) {
|
||||||
|
std::string str = thumbnails_value->value;
|
||||||
|
std::istringstream is(str);
|
||||||
|
std::string point_str;
|
||||||
|
while (std::getline(is, point_str, ',')) {
|
||||||
|
Vec2d point(Vec2d::Zero());
|
||||||
|
GCodeThumbnailsFormat format;
|
||||||
|
std::istringstream iss(point_str);
|
||||||
|
std::string coord_str;
|
||||||
|
if (std::getline(iss, coord_str, 'x')) {
|
||||||
|
std::istringstream(coord_str) >> point(0);
|
||||||
|
if (std::getline(iss, coord_str, '/')) {
|
||||||
|
std::istringstream(coord_str) >> point(1);
|
||||||
|
std::string ext_str;
|
||||||
|
if (std::getline(iss, ext_str, '/'))
|
||||||
|
format = ext_str == "JPG" ? GCodeThumbnailsFormat::JPG :
|
||||||
|
ext_str == "QOI" ? GCodeThumbnailsFormat::QOI :GCodeThumbnailsFormat::PNG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thumbnails_list.emplace_back(std::make_pair(format, point));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return thumbnails_list;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Slic3r::GCodeThumbnails
|
} // namespace Slic3r::GCodeThumbnails
|
||||||
|
@ -9,6 +9,10 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
#include <LibBGCode/binarize/binarize.hpp>
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
#include <boost/beast/core/detail/base64.hpp>
|
#include <boost/beast/core/detail/base64.hpp>
|
||||||
|
|
||||||
namespace Slic3r::GCodeThumbnails {
|
namespace Slic3r::GCodeThumbnails {
|
||||||
@ -23,6 +27,8 @@ struct CompressedImageBuffer
|
|||||||
|
|
||||||
std::unique_ptr<CompressedImageBuffer> compress_thumbnail(const ThumbnailData &data, GCodeThumbnailsFormat format);
|
std::unique_ptr<CompressedImageBuffer> compress_thumbnail(const ThumbnailData &data, GCodeThumbnailsFormat format);
|
||||||
|
|
||||||
|
std::vector<std::pair<GCodeThumbnailsFormat, Vec2d>> make_thumbnail_list(const DynamicPrintConfig &config);
|
||||||
|
|
||||||
template<typename WriteToOutput, typename ThrowIfCanceledCallback>
|
template<typename WriteToOutput, typename ThrowIfCanceledCallback>
|
||||||
inline void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, const std::vector<std::pair<GCodeThumbnailsFormat, Vec2d>>& thumbnails_list, WriteToOutput output, ThrowIfCanceledCallback throw_if_canceled)
|
inline void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, const std::vector<std::pair<GCodeThumbnailsFormat, Vec2d>>& thumbnails_list, WriteToOutput output, ThrowIfCanceledCallback throw_if_canceled)
|
||||||
{
|
{
|
||||||
@ -57,6 +63,39 @@ inline void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
template<typename ThrowIfCanceledCallback>
|
||||||
|
inline void generate_binary_thumbnails(ThumbnailsGeneratorCallback& thumbnail_cb, std::vector<bgcode::binarize::ThumbnailBlock>& out_thumbnails,
|
||||||
|
const std::vector<std::pair<GCodeThumbnailsFormat, Vec2d>> &thumbnails_list, ThrowIfCanceledCallback throw_if_canceled)
|
||||||
|
{
|
||||||
|
using namespace bgcode::core;
|
||||||
|
using namespace bgcode::binarize;
|
||||||
|
out_thumbnails.clear();
|
||||||
|
assert(thumbnail_cb != nullptr);
|
||||||
|
if (thumbnail_cb != nullptr) {
|
||||||
|
for (const auto& [format, size] : thumbnails_list) {
|
||||||
|
ThumbnailsList thumbnails = thumbnail_cb(ThumbnailsParams{ {size}, true, true, true, true });
|
||||||
|
for (const ThumbnailData &data : thumbnails)
|
||||||
|
if (data.is_valid()) {
|
||||||
|
auto compressed = compress_thumbnail(data, format);
|
||||||
|
if (compressed->data != nullptr && compressed->size > 0) {
|
||||||
|
ThumbnailBlock& block = out_thumbnails.emplace_back(ThumbnailBlock());
|
||||||
|
block.params.width = (uint16_t)data.width;
|
||||||
|
block.params.height = (uint16_t)data.height;
|
||||||
|
switch (format) {
|
||||||
|
case GCodeThumbnailsFormat::PNG: { block.params.format = (uint16_t)EThumbnailFormat::PNG; break; }
|
||||||
|
case GCodeThumbnailsFormat::JPG: { block.params.format = (uint16_t)EThumbnailFormat::JPG; break; }
|
||||||
|
case GCodeThumbnailsFormat::QOI: { block.params.format = (uint16_t)EThumbnailFormat::QOI; break; }
|
||||||
|
}
|
||||||
|
block.data.resize(compressed->size);
|
||||||
|
memcpy(block.data.data(), compressed->data, compressed->size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
} // namespace Slic3r::GCodeThumbnails
|
} // namespace Slic3r::GCodeThumbnails
|
||||||
|
|
||||||
#endif // slic3r_GCodeThumbnails_hpp_
|
#endif // slic3r_GCodeThumbnails_hpp_
|
||||||
|
@ -195,11 +195,20 @@ bool GCodeReader::parse_file(const std::string &file, callback_t callback)
|
|||||||
return this->parse_file_internal(file, callback, [](size_t){});
|
return this->parse_file_internal(file, callback, [](size_t){});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
bool GCodeReader::parse_file(const std::string& file, callback_t callback, std::vector<std::vector<size_t>>& lines_ends)
|
||||||
|
{
|
||||||
|
lines_ends.clear();
|
||||||
|
lines_ends.push_back(std::vector<size_t>());
|
||||||
|
return this->parse_file_internal(file, callback, [&lines_ends](size_t file_pos) { lines_ends.front().emplace_back(file_pos); });
|
||||||
|
}
|
||||||
|
#else
|
||||||
bool GCodeReader::parse_file(const std::string &file, callback_t callback, std::vector<size_t> &lines_ends)
|
bool GCodeReader::parse_file(const std::string &file, callback_t callback, std::vector<size_t> &lines_ends)
|
||||||
{
|
{
|
||||||
lines_ends.clear();
|
lines_ends.clear();
|
||||||
return this->parse_file_internal(file, callback, [&lines_ends](size_t file_pos){ lines_ends.emplace_back(file_pos); });
|
return this->parse_file_internal(file, callback, [&lines_ends](size_t file_pos){ lines_ends.emplace_back(file_pos); });
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
bool GCodeReader::parse_file_raw(const std::string &filename, raw_line_callback_t line_callback)
|
bool GCodeReader::parse_file_raw(const std::string &filename, raw_line_callback_t line_callback)
|
||||||
{
|
{
|
||||||
|
@ -131,7 +131,11 @@ public:
|
|||||||
bool parse_file(const std::string &file, callback_t callback);
|
bool parse_file(const std::string &file, callback_t callback);
|
||||||
// Collect positions of line ends in the binary G-code to be used by the G-code viewer when memory mapping and displaying section of G-code
|
// Collect positions of line ends in the binary G-code to be used by the G-code viewer when memory mapping and displaying section of G-code
|
||||||
// as an overlay in the 3D scene.
|
// as an overlay in the 3D scene.
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
bool parse_file(const std::string& file, callback_t callback, std::vector<std::vector<size_t>>& lines_ends);
|
||||||
|
#else
|
||||||
bool parse_file(const std::string &file, callback_t callback, std::vector<size_t> &lines_ends);
|
bool parse_file(const std::string &file, callback_t callback, std::vector<size_t> &lines_ends);
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
// Just read the G-code file line by line, calls callback (const char *begin, const char *end). Returns false if reading the file failed.
|
// Just read the G-code file line by line, calls callback (const char *begin, const char *end). Returns false if reading the file failed.
|
||||||
bool parse_file_raw(const std::string &file, raw_line_callback_t callback);
|
bool parse_file_raw(const std::string &file, raw_line_callback_t callback);
|
||||||
|
|
||||||
|
@ -451,7 +451,11 @@ static std::vector<std::string> s_Preset_print_options {
|
|||||||
"support_tree_angle", "support_tree_angle_slow", "support_tree_branch_diameter", "support_tree_branch_diameter_angle", "support_tree_branch_diameter_double_wall",
|
"support_tree_angle", "support_tree_angle_slow", "support_tree_branch_diameter", "support_tree_branch_diameter_angle", "support_tree_branch_diameter_double_wall",
|
||||||
"support_tree_top_rate", "support_tree_branch_distance", "support_tree_tip_diameter",
|
"support_tree_top_rate", "support_tree_branch_distance", "support_tree_tip_diameter",
|
||||||
"dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius",
|
"dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius",
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
"extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "gcode_substitutions", "gcode_binary", "perimeter_extruder",
|
||||||
|
#else
|
||||||
"extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "gcode_substitutions", "perimeter_extruder",
|
"extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "gcode_substitutions", "perimeter_extruder",
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
"infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",
|
"infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",
|
||||||
"ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
|
"ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
|
||||||
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
|
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
#include <boost/locale.hpp>
|
#include <boost/locale.hpp>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
#include <LibBGCode/core/core.hpp>
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
// Store the print/filament/printer presets into a "presets" subdirectory of the Slic3rPE config dir.
|
// Store the print/filament/printer presets into a "presets" subdirectory of the Slic3rPE config dir.
|
||||||
// This breaks compatibility with the upstream Slic3r if the --datadir is used to switch between the two versions.
|
// This breaks compatibility with the upstream Slic3r if the --datadir is used to switch between the two versions.
|
||||||
@ -877,14 +880,33 @@ DynamicPrintConfig PresetBundle::full_sla_config() const
|
|||||||
// If the file is loaded successfully, its print / filament / printer profiles will be activated.
|
// If the file is loaded successfully, its print / filament / printer profiles will be activated.
|
||||||
ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule)
|
ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule)
|
||||||
{
|
{
|
||||||
if (is_gcode_file(path)) {
|
#if ENABLE_BINARIZED_GCODE
|
||||||
DynamicPrintConfig config;
|
if (is_gcode_file(path)) {
|
||||||
config.apply(FullPrintConfig::defaults());
|
FILE* file = boost::nowide::fopen(path.c_str(), "rb");
|
||||||
|
if (file == nullptr)
|
||||||
|
throw Slic3r::RuntimeError("Error opening the file: " + path + "\n");
|
||||||
|
std::vector<uint8_t> cs_buffer(65536);
|
||||||
|
const bool is_binary = bgcode::core::is_valid_binary_gcode(*file, true, cs_buffer.data(), cs_buffer.size()) == bgcode::core::EResult::Success;
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
DynamicPrintConfig config;
|
||||||
|
config.apply(FullPrintConfig::defaults());
|
||||||
|
ConfigSubstitutions config_substitutions = is_binary ? config.load_from_binary_gcode_file(path, compatibility_rule) :
|
||||||
|
config.load_from_gcode_file(path, compatibility_rule);
|
||||||
|
Preset::normalize(config);
|
||||||
|
load_config_file_config(path, true, std::move(config));
|
||||||
|
return config_substitutions;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (is_gcode_file(path)) {
|
||||||
|
DynamicPrintConfig config;
|
||||||
|
config.apply(FullPrintConfig::defaults());
|
||||||
ConfigSubstitutions config_substitutions = config.load_from_gcode_file(path, compatibility_rule);
|
ConfigSubstitutions config_substitutions = config.load_from_gcode_file(path, compatibility_rule);
|
||||||
Preset::normalize(config);
|
Preset::normalize(config);
|
||||||
load_config_file_config(path, true, std::move(config));
|
load_config_file_config(path, true, std::move(config));
|
||||||
return config_substitutions;
|
return config_substitutions;
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
// 1) Try to load the config file into a boost property tree.
|
// 1) Try to load the config file into a boost property tree.
|
||||||
boost::property_tree::ptree tree;
|
boost::property_tree::ptree tree;
|
||||||
|
@ -117,6 +117,9 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
|||||||
"perimeter_acceleration",
|
"perimeter_acceleration",
|
||||||
"post_process",
|
"post_process",
|
||||||
"gcode_substitutions",
|
"gcode_substitutions",
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
"gcode_binary",
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
"printer_notes",
|
"printer_notes",
|
||||||
"retract_before_travel",
|
"retract_before_travel",
|
||||||
"retract_before_wipe",
|
"retract_before_wipe",
|
||||||
@ -1601,6 +1604,28 @@ std::string Print::output_filename(const std::string &filename_base) const
|
|||||||
return this->PrintBase::output_filename(m_config.output_filename_format.value, ".gcode", filename_base, &config);
|
return this->PrintBase::output_filename(m_config.output_filename_format.value, ".gcode", filename_base, &config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
const std::string PrintStatistics::FilamentUsedG = "filament used [g]";
|
||||||
|
const std::string PrintStatistics::FilamentUsedGMask = "; " + PrintStatistics::FilamentUsedG + " =";
|
||||||
|
|
||||||
|
const std::string PrintStatistics::TotalFilamentUsedG = "total " + PrintStatistics::FilamentUsedG;
|
||||||
|
const std::string PrintStatistics::TotalFilamentUsedGMask = "; " + PrintStatistics::TotalFilamentUsedG + " =";
|
||||||
|
const std::string PrintStatistics::TotalFilamentUsedGValueMask = TotalFilamentUsedGMask + " %.2lf\n";
|
||||||
|
|
||||||
|
const std::string PrintStatistics::FilamentUsedCm3 = "filament used [cm3]";
|
||||||
|
const std::string PrintStatistics::FilamentUsedCm3Mask = "; " + PrintStatistics::FilamentUsedCm3 + " =";
|
||||||
|
|
||||||
|
const std::string PrintStatistics::FilamentUsedMm = "filament used [mm]";
|
||||||
|
const std::string PrintStatistics::FilamentUsedMmMask = "; " + PrintStatistics::FilamentUsedMm + " =";
|
||||||
|
|
||||||
|
const std::string PrintStatistics::FilamentCost = "filament cost";
|
||||||
|
const std::string PrintStatistics::FilamentCostMask = "; " + PrintStatistics::FilamentCost + " =";
|
||||||
|
|
||||||
|
const std::string PrintStatistics::TotalFilamentCost = "total " + PrintStatistics::FilamentCost;
|
||||||
|
const std::string PrintStatistics::TotalFilamentCostMask = "; " + PrintStatistics::TotalFilamentCost + " =";
|
||||||
|
const std::string PrintStatistics::TotalFilamentCostValueMask = PrintStatistics::TotalFilamentCostMask + " %.2lf\n";
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
DynamicConfig PrintStatistics::config() const
|
DynamicConfig PrintStatistics::config() const
|
||||||
{
|
{
|
||||||
DynamicConfig config;
|
DynamicConfig config;
|
||||||
|
@ -529,6 +529,23 @@ struct PrintStatistics
|
|||||||
filament_stats.clear();
|
filament_stats.clear();
|
||||||
printing_extruders.clear();
|
printing_extruders.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
static const std::string FilamentUsedG;
|
||||||
|
static const std::string FilamentUsedGMask;
|
||||||
|
static const std::string TotalFilamentUsedG;
|
||||||
|
static const std::string TotalFilamentUsedGMask;
|
||||||
|
static const std::string TotalFilamentUsedGValueMask;
|
||||||
|
static const std::string FilamentUsedCm3;
|
||||||
|
static const std::string FilamentUsedCm3Mask;
|
||||||
|
static const std::string FilamentUsedMm;
|
||||||
|
static const std::string FilamentUsedMmMask;
|
||||||
|
static const std::string FilamentCost;
|
||||||
|
static const std::string FilamentCostMask;
|
||||||
|
static const std::string TotalFilamentCost;
|
||||||
|
static const std::string TotalFilamentCostMask;
|
||||||
|
static const std::string TotalFilamentCostValueMask;
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
};
|
};
|
||||||
|
|
||||||
using PrintObjectPtrs = std::vector<PrintObject*>;
|
using PrintObjectPtrs = std::vector<PrintObject*>;
|
||||||
|
@ -1483,6 +1483,14 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->mode = comExpert;
|
def->mode = comExpert;
|
||||||
def->set_default_value(new ConfigOptionStrings());
|
def->set_default_value(new ConfigOptionStrings());
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
def = this->add("gcode_binary", coBool);
|
||||||
|
def->label = L("Export as binary G-code");
|
||||||
|
def->tooltip = L("Exports the G-code in binary format.");
|
||||||
|
def->mode = comExpert;
|
||||||
|
def->set_default_value(new ConfigOptionBool(0));
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
def = this->add("high_current_on_filament_swap", coBool);
|
def = this->add("high_current_on_filament_swap", coBool);
|
||||||
def->label = L("High extruder current on filament swap");
|
def->label = L("High extruder current on filament swap");
|
||||||
def->tooltip = L("It may be beneficial to increase the extruder motor current during the filament exchange"
|
def->tooltip = L("It may be beneficial to increase the extruder motor current during the filament exchange"
|
||||||
|
@ -719,6 +719,9 @@ PRINT_CONFIG_CLASS_DEFINE(
|
|||||||
// i - case insensitive
|
// i - case insensitive
|
||||||
// w - whole word
|
// w - whole word
|
||||||
((ConfigOptionStrings, gcode_substitutions))
|
((ConfigOptionStrings, gcode_substitutions))
|
||||||
|
//#if ENABLE_BINARIZED_GCODE
|
||||||
|
((ConfigOptionBool, gcode_binary))
|
||||||
|
//#endif // ENABLE_BINARIZED_GCODE
|
||||||
((ConfigOptionString, layer_gcode))
|
((ConfigOptionString, layer_gcode))
|
||||||
((ConfigOptionFloat, max_print_speed))
|
((ConfigOptionFloat, max_print_speed))
|
||||||
((ConfigOptionFloat, max_volumetric_speed))
|
((ConfigOptionFloat, max_volumetric_speed))
|
||||||
|
@ -62,4 +62,18 @@
|
|||||||
#define ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR (1 && ENABLE_2_6_0_ALPHA1)
|
#define ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR (1 && ENABLE_2_6_0_ALPHA1)
|
||||||
|
|
||||||
|
|
||||||
|
//====================
|
||||||
|
// 2.6.2.alpha1 techs
|
||||||
|
//====================
|
||||||
|
#define ENABLE_2_6_2_ALPHA1 1
|
||||||
|
|
||||||
|
// Enable export of binarized gcode
|
||||||
|
#define ENABLE_BINARIZED_GCODE (1 && ENABLE_2_6_2_ALPHA1)
|
||||||
|
#define ENABLE_BINARIZED_GCODE_DEBUG (0 && ENABLE_BINARIZED_GCODE)
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define ENABLE_BINARIZED_GCODE_WIN_DEBUG (1 && ENABLE_BINARIZED_GCODE_DEBUG)
|
||||||
|
#endif // _WIN32
|
||||||
|
#define ENABLE_BINARIZED_GCODE_DEBUG_WINDOW (1 && ENABLE_BINARIZED_GCODE)
|
||||||
|
|
||||||
|
|
||||||
#endif // _prusaslicer_technologies_h_
|
#endif // _prusaslicer_technologies_h_
|
||||||
|
@ -38,6 +38,11 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE_WIN_DEBUG
|
||||||
|
#include <windows.h>
|
||||||
|
#include <debugapi.h>
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE_WIN_DEBUG
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
@ -362,15 +367,22 @@ void GCodeViewer::SequentialView::Marker::render()
|
|||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
void GCodeViewer::SequentialView::GCodeWindow::load_gcode(const GCodeProcessorResult& gcode_result)
|
||||||
|
{
|
||||||
|
m_filename = gcode_result.filename;
|
||||||
|
m_is_binary_file = gcode_result.is_binary_file;
|
||||||
|
m_lines_ends = gcode_result.lines_ends;
|
||||||
|
}
|
||||||
|
#else
|
||||||
void GCodeViewer::SequentialView::GCodeWindow::load_gcode(const std::string& filename, const std::vector<size_t>& lines_ends)
|
void GCodeViewer::SequentialView::GCodeWindow::load_gcode(const std::string& filename, const std::vector<size_t>& lines_ends)
|
||||||
{
|
{
|
||||||
assert(! m_file.is_open());
|
assert(!m_file.is_open());
|
||||||
if (m_file.is_open())
|
if (m_file.is_open())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_filename = filename;
|
m_filename = filename;
|
||||||
m_lines_ends = lines_ends;
|
m_lines_ends = lines_ends;
|
||||||
|
|
||||||
m_selected_line_id = 0;
|
m_selected_line_id = 0;
|
||||||
m_last_lines_size = 0;
|
m_last_lines_size = 0;
|
||||||
|
|
||||||
@ -384,41 +396,325 @@ void GCodeViewer::SequentialView::GCodeWindow::load_gcode(const std::string& fil
|
|||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
void GCodeViewer::SequentialView::GCodeWindow::add_gcode_line_to_lines_cache(const std::string& src)
|
||||||
|
{
|
||||||
|
std::string command;
|
||||||
|
std::string parameters;
|
||||||
|
std::string comment;
|
||||||
|
|
||||||
|
// extract comment
|
||||||
|
std::vector<std::string> tokens;
|
||||||
|
boost::split(tokens, src, boost::is_any_of(";"), boost::token_compress_on);
|
||||||
|
command = tokens.front();
|
||||||
|
if (tokens.size() > 1)
|
||||||
|
comment = ";" + tokens.back();
|
||||||
|
|
||||||
|
// extract gcode command and parameters
|
||||||
|
if (!command.empty()) {
|
||||||
|
boost::split(tokens, command, boost::is_any_of(" "), boost::token_compress_on);
|
||||||
|
command = tokens.front();
|
||||||
|
if (tokens.size() > 1) {
|
||||||
|
for (size_t i = 1; i < tokens.size(); ++i) {
|
||||||
|
parameters += " " + tokens[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lines_cache.push_back({ command, parameters, comment });
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, size_t curr_line_id)
|
||||||
|
{
|
||||||
|
auto update_lines_ascii = [this]() {
|
||||||
|
m_lines_cache.clear();
|
||||||
|
m_lines_cache.reserve(m_cache_range.size());
|
||||||
|
const std::vector<size_t>& lines_ends = m_lines_ends.front();
|
||||||
|
FILE* file = boost::nowide::fopen(m_filename.c_str(), "rb");
|
||||||
|
if (file != nullptr) {
|
||||||
|
for (size_t id = *m_cache_range.min; id <= *m_cache_range.max; ++id) {
|
||||||
|
assert(id > 0);
|
||||||
|
// read line from file
|
||||||
|
const size_t begin = id == 1 ? 0 : lines_ends[id - 2];
|
||||||
|
const size_t len = lines_ends[id - 1] - begin;
|
||||||
|
std::string gline(len, '\0');
|
||||||
|
fseek(file, begin, SEEK_SET);
|
||||||
|
const size_t rsize = fread((void*)gline.data(), 1, len, file);
|
||||||
|
if (ferror(file) || rsize != len) {
|
||||||
|
m_lines_cache.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_gcode_line_to_lines_cache(gline);
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto update_lines_binary = [this]() {
|
||||||
|
m_lines_cache.clear();
|
||||||
|
m_lines_cache.reserve(m_cache_range.size());
|
||||||
|
|
||||||
|
size_t cumulative_lines_count = 0;
|
||||||
|
std::vector<size_t> cumulative_lines_counts;
|
||||||
|
cumulative_lines_counts.reserve(m_lines_ends.size());
|
||||||
|
for (size_t i = 0; i < m_lines_ends.size(); ++i) {
|
||||||
|
cumulative_lines_count += m_lines_ends[i].size();
|
||||||
|
cumulative_lines_counts.emplace_back(cumulative_lines_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t first_block_id = 0;
|
||||||
|
for (size_t i = 0; i < cumulative_lines_counts.size(); ++i) {
|
||||||
|
if (*m_cache_range.min <= cumulative_lines_counts[i]) {
|
||||||
|
first_block_id = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size_t last_block_id = 0;
|
||||||
|
for (size_t i = 0; i < cumulative_lines_counts.size(); ++i) {
|
||||||
|
if (*m_cache_range.max <= cumulative_lines_counts[i]) {
|
||||||
|
last_block_id = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(last_block_id >= first_block_id);
|
||||||
|
|
||||||
|
FilePtr file(boost::nowide::fopen(m_filename.c_str(), "rb"));
|
||||||
|
if (file.f != nullptr) {
|
||||||
|
fseek(file.f, 0, SEEK_END);
|
||||||
|
const long file_size = ftell(file.f);
|
||||||
|
rewind(file.f);
|
||||||
|
|
||||||
|
// read file header
|
||||||
|
using namespace bgcode::core;
|
||||||
|
using namespace bgcode::binarize;
|
||||||
|
FileHeader file_header;
|
||||||
|
EResult res = read_header(*file.f, file_header, nullptr);
|
||||||
|
if (res == EResult::Success) {
|
||||||
|
// search first GCode block
|
||||||
|
BlockHeader block_header;
|
||||||
|
res = read_next_block_header(*file.f, file_header, block_header, EBlockType::GCode, nullptr, 0);
|
||||||
|
if (res == EResult::Success) {
|
||||||
|
for (size_t i = 0; i < first_block_id; ++i) {
|
||||||
|
skip_block(*file.f, file_header, block_header);
|
||||||
|
res = read_next_block_header(*file.f, file_header, block_header, nullptr, 0);
|
||||||
|
if (res != EResult::Success || block_header.type != (uint16_t)EBlockType::GCode) {
|
||||||
|
m_lines_cache.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = first_block_id; i <= last_block_id; ++i) {
|
||||||
|
GCodeBlock block;
|
||||||
|
res = block.read_data(*file.f, file_header, block_header);
|
||||||
|
if (res != EResult::Success) {
|
||||||
|
m_lines_cache.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t ref_id = (i == 0) ? 0 : i - 1;
|
||||||
|
const size_t first_line_id = (i == 0) ? *m_cache_range.min :
|
||||||
|
(*m_cache_range.min - 1 >= cumulative_lines_counts[ref_id]) ? *m_cache_range.min - cumulative_lines_counts[ref_id] : 1;
|
||||||
|
const size_t last_line_id = (*m_cache_range.max - 1 <= cumulative_lines_counts[i]) ?
|
||||||
|
(i == 0) ? *m_cache_range.max : *m_cache_range.max - cumulative_lines_counts[ref_id] : m_lines_ends[i].size() - 1;
|
||||||
|
|
||||||
|
for (size_t j = first_line_id; j <= last_line_id; ++j) {
|
||||||
|
const size_t begin = (j == 1) ? 0 : m_lines_ends[i][j - 2];
|
||||||
|
const size_t end = m_lines_ends[i][j - 1];
|
||||||
|
std::string gline;
|
||||||
|
gline.insert(gline.end(), block.raw_data.begin() + begin, block.raw_data.begin() + end);
|
||||||
|
add_gcode_line_to_lines_cache(gline);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftell(file.f) == file_size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
res = read_next_block_header(*file.f, file_header, block_header, nullptr, 0);
|
||||||
|
if (res != EResult::Success || block_header.type != (uint16_t)EBlockType::GCode) {
|
||||||
|
m_lines_cache.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ImVec4 LINE_NUMBER_COLOR = ImGuiWrapper::COL_ORANGE_LIGHT;
|
||||||
|
static const ImVec4 SELECTION_RECT_COLOR = ImGuiWrapper::COL_ORANGE_DARK;
|
||||||
|
static const ImVec4 COMMAND_COLOR = { 0.8f, 0.8f, 0.0f, 1.0f };
|
||||||
|
static const ImVec4 PARAMETERS_COLOR = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
|
static const ImVec4 COMMENT_COLOR = { 0.7f, 0.7f, 0.7f, 1.0f };
|
||||||
|
static const ImVec4 ELLIPSIS_COLOR = { 0.0f, 0.7f, 0.0f, 1.0f };
|
||||||
|
|
||||||
|
if (!m_visible || m_filename.empty() || m_lines_ends.empty() || curr_line_id == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// window height
|
||||||
|
const float wnd_height = bottom - top;
|
||||||
|
|
||||||
|
// number of visible lines
|
||||||
|
const float text_height = ImGui::CalcTextSize("0").y;
|
||||||
|
const ImGuiStyle& style = ImGui::GetStyle();
|
||||||
|
const size_t visible_lines_count = static_cast<size_t>((wnd_height - 2.0f * style.WindowPadding.y + style.ItemSpacing.y) / (text_height + style.ItemSpacing.y));
|
||||||
|
|
||||||
|
if (visible_lines_count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_lines_ends.empty() || m_lines_ends.front().empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto resize_range = [&](Range& range, size_t lines_count) {
|
||||||
|
const size_t half_lines_count = lines_count / 2;
|
||||||
|
range.min = (curr_line_id >= half_lines_count) ? curr_line_id - half_lines_count : 1;
|
||||||
|
range.max = *range.min + lines_count - 1;
|
||||||
|
size_t lines_ends_count = 0;
|
||||||
|
for (const auto& le : m_lines_ends) {
|
||||||
|
lines_ends_count += le.size();
|
||||||
|
}
|
||||||
|
if (*range.max >= lines_ends_count) {
|
||||||
|
range.max = lines_ends_count - 1;
|
||||||
|
range.min = *range.max - lines_count + 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// visible range
|
||||||
|
Range visible_range;
|
||||||
|
resize_range(visible_range, visible_lines_count);
|
||||||
|
|
||||||
|
// update cache if needed
|
||||||
|
if (m_cache_range.empty() || !m_cache_range.contains(visible_range)) {
|
||||||
|
resize_range(m_cache_range, 4 * visible_range.size());
|
||||||
|
if (m_is_binary_file)
|
||||||
|
update_lines_binary();
|
||||||
|
else
|
||||||
|
update_lines_ascii();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_lines_cache.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// line number's column width
|
||||||
|
const float id_width = ImGui::CalcTextSize(std::to_string(*visible_range.max).c_str()).x;
|
||||||
|
|
||||||
|
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||||
|
|
||||||
|
auto add_item_to_line = [&imgui](const std::string& txt, const ImVec4& color, float spacing, size_t& current_length) {
|
||||||
|
static const size_t LENGTH_THRESHOLD = 60;
|
||||||
|
|
||||||
|
if (txt.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string out_text = txt;
|
||||||
|
bool reduced = false;
|
||||||
|
if (current_length + out_text.length() > LENGTH_THRESHOLD) {
|
||||||
|
out_text = out_text.substr(0, LENGTH_THRESHOLD - current_length);
|
||||||
|
reduced = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_length += out_text.length();
|
||||||
|
|
||||||
|
ImGui::SameLine(0.0f, spacing);
|
||||||
|
imgui.text_colored(color, out_text);
|
||||||
|
if (reduced) {
|
||||||
|
ImGui::SameLine(0.0f, 0.0f);
|
||||||
|
imgui.text_colored(ELLIPSIS_COLOR, "...");
|
||||||
|
}
|
||||||
|
|
||||||
|
return reduced;
|
||||||
|
};
|
||||||
|
|
||||||
|
imgui.set_next_window_pos(0.0f, top, ImGuiCond_Always, 0.0f, 0.0f);
|
||||||
|
imgui.set_next_window_size(0.0f, wnd_height, ImGuiCond_Always);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||||
|
ImGui::SetNextWindowBgAlpha(0.6f);
|
||||||
|
imgui.begin(std::string("G-code"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove);
|
||||||
|
|
||||||
|
// center the text in the window by pushing down the first line
|
||||||
|
const float f_lines_count = static_cast<float>(visible_lines_count);
|
||||||
|
ImGui::SetCursorPosY(0.5f * (wnd_height - f_lines_count * text_height - (f_lines_count - 1.0f) * style.ItemSpacing.y));
|
||||||
|
|
||||||
|
// render text lines
|
||||||
|
size_t max_line_length = 0;
|
||||||
|
for (size_t id = *visible_range.min; id <= *visible_range.max; ++id) {
|
||||||
|
const Line& line = m_lines_cache[id - *m_cache_range.min];
|
||||||
|
|
||||||
|
// rect around the current selected line
|
||||||
|
if (id == curr_line_id) {
|
||||||
|
const float pos_y = ImGui::GetCursorScreenPos().y;
|
||||||
|
const float half_ItemSpacing_y = 0.5f * style.ItemSpacing.y;
|
||||||
|
const float half_padding_x = 0.5f * style.WindowPadding.x;
|
||||||
|
ImGui::GetWindowDrawList()->AddRect({ half_padding_x, pos_y - half_ItemSpacing_y },
|
||||||
|
{ ImGui::GetCurrentWindow()->Size.x - half_padding_x, pos_y + text_height + half_ItemSpacing_y },
|
||||||
|
ImGui::GetColorU32(SELECTION_RECT_COLOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string id_str = std::to_string(id);
|
||||||
|
// spacer to right align text
|
||||||
|
ImGui::Dummy({ id_width - ImGui::CalcTextSize(id_str.c_str()).x, text_height });
|
||||||
|
|
||||||
|
size_t line_length = 0;
|
||||||
|
// render line number
|
||||||
|
bool stop_adding = add_item_to_line(id_str, LINE_NUMBER_COLOR, 0.0f, line_length);
|
||||||
|
if (!stop_adding && !line.command.empty())
|
||||||
|
// render command
|
||||||
|
stop_adding = add_item_to_line(line.command, COMMAND_COLOR, -1.0f, line_length);
|
||||||
|
if (!stop_adding && !line.parameters.empty())
|
||||||
|
// render parameters
|
||||||
|
stop_adding = add_item_to_line(line.parameters, PARAMETERS_COLOR, 0.0f, line_length);
|
||||||
|
if (!stop_adding && !line.comment.empty())
|
||||||
|
// render comment
|
||||||
|
stop_adding = add_item_to_line(line.comment, COMMENT_COLOR, line.command.empty() ? -1.0f : 0.0f, line_length);
|
||||||
|
|
||||||
|
max_line_length = std::max(max_line_length, line_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
imgui.end();
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
// request an extra frame if window's width changed
|
||||||
|
if (m_max_line_length != max_line_length) {
|
||||||
|
m_max_line_length = max_line_length;
|
||||||
|
imgui.set_requires_extra_frame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, uint64_t curr_line_id) const
|
void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, uint64_t curr_line_id) const
|
||||||
{
|
{
|
||||||
auto update_lines = [this](uint64_t start_id, uint64_t end_id) {
|
auto update_lines = [this](uint64_t start_id, uint64_t end_id) {
|
||||||
std::vector<Line> ret;
|
std::vector<Line> ret;
|
||||||
ret.reserve(end_id - start_id + 1);
|
ret.reserve(end_id - start_id + 1);
|
||||||
for (uint64_t id = start_id; id <= end_id; ++id) {
|
for (uint64_t id = start_id; id <= end_id; ++id) {
|
||||||
// read line from file
|
// read line from file
|
||||||
const size_t start = id == 1 ? 0 : m_lines_ends[id - 2];
|
const size_t start = id == 1 ? 0 : m_lines_ends[id - 2];
|
||||||
const size_t len = m_lines_ends[id - 1] - start;
|
const size_t len = m_lines_ends[id - 1] - start;
|
||||||
std::string gline(m_file.data() + start, len);
|
std::string gline(m_file.data() + start, len);
|
||||||
|
|
||||||
std::string command;
|
std::string command;
|
||||||
std::string parameters;
|
std::string parameters;
|
||||||
std::string comment;
|
std::string comment;
|
||||||
|
|
||||||
// extract comment
|
// extract comment
|
||||||
std::vector<std::string> tokens;
|
std::vector<std::string> tokens;
|
||||||
boost::split(tokens, gline, boost::is_any_of(";"), boost::token_compress_on);
|
boost::split(tokens, gline, boost::is_any_of(";"), boost::token_compress_on);
|
||||||
command = tokens.front();
|
|
||||||
if (tokens.size() > 1)
|
|
||||||
comment = ";" + tokens.back();
|
|
||||||
|
|
||||||
// extract gcode command and parameters
|
|
||||||
if (!command.empty()) {
|
|
||||||
boost::split(tokens, command, boost::is_any_of(" "), boost::token_compress_on);
|
|
||||||
command = tokens.front();
|
command = tokens.front();
|
||||||
if (tokens.size() > 1) {
|
if (tokens.size() > 1)
|
||||||
for (size_t i = 1; i < tokens.size(); ++i) {
|
comment = ";" + tokens.back();
|
||||||
parameters += " " + tokens[i];
|
|
||||||
|
// extract gcode command and parameters
|
||||||
|
if (!command.empty()) {
|
||||||
|
boost::split(tokens, command, boost::is_any_of(" "), boost::token_compress_on);
|
||||||
|
command = tokens.front();
|
||||||
|
if (tokens.size() > 1) {
|
||||||
|
for (size_t i = 1; i < tokens.size(); ++i) {
|
||||||
|
parameters += " " + tokens[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ret.push_back({ command, parameters, comment });
|
||||||
}
|
}
|
||||||
ret.push_back({ command, parameters, comment });
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -552,6 +848,7 @@ void GCodeViewer::SequentialView::GCodeWindow::stop_mapping_file()
|
|||||||
if (m_file.is_open())
|
if (m_file.is_open())
|
||||||
m_file.close();
|
m_file.close();
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
void GCodeViewer::SequentialView::render(float legend_height)
|
void GCodeViewer::SequentialView::render(float legend_height)
|
||||||
{
|
{
|
||||||
@ -731,7 +1028,11 @@ void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& pr
|
|||||||
// release gpu memory, if used
|
// release gpu memory, if used
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
m_sequential_view.gcode_window.load_gcode(gcode_result);
|
||||||
|
#else
|
||||||
m_sequential_view.gcode_window.load_gcode(gcode_result.filename, gcode_result.lines_ends);
|
m_sequential_view.gcode_window.load_gcode(gcode_result.filename, gcode_result.lines_ends);
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
if (wxGetApp().is_gcode_viewer())
|
if (wxGetApp().is_gcode_viewer())
|
||||||
m_custom_gcode_per_print_z = gcode_result.custom_gcode_per_print_z;
|
m_custom_gcode_per_print_z = gcode_result.custom_gcode_per_print_z;
|
||||||
@ -2354,20 +2655,26 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
|
|||||||
case EViewType::Temperature: { color = m_extrusions.ranges.temperature.get_color_at(path.temperature); break; }
|
case EViewType::Temperature: { color = m_extrusions.ranges.temperature.get_color_at(path.temperature); break; }
|
||||||
case EViewType::LayerTimeLinear:
|
case EViewType::LayerTimeLinear:
|
||||||
case EViewType::LayerTimeLogarithmic: {
|
case EViewType::LayerTimeLogarithmic: {
|
||||||
const Path::Sub_Path& sub_path = path.sub_paths.front();
|
#if ENABLE_BINARIZED_GCODE
|
||||||
double z = static_cast<double>(sub_path.first.position.z());
|
if (!m_layers_times.empty() && m_layers.size() == m_layers_times.front().size()) {
|
||||||
const std::vector<double>& zs = m_layers.get_zs();
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
const std::vector<Layers::Range>& ranges = m_layers.get_ranges();
|
const Path::Sub_Path& sub_path = path.sub_paths.front();
|
||||||
size_t time_mode_id = static_cast<size_t>(m_time_estimate_mode);
|
double z = static_cast<double>(sub_path.first.position.z());
|
||||||
for (size_t i = 0; i < zs.size(); ++i) {
|
const std::vector<double>& zs = m_layers.get_zs();
|
||||||
if (std::abs(zs[i] - z) < EPSILON) {
|
const std::vector<Layers::Range>& ranges = m_layers.get_ranges();
|
||||||
if (ranges[i].contains(sub_path.first.s_id)) {
|
size_t time_mode_id = static_cast<size_t>(m_time_estimate_mode);
|
||||||
color = m_extrusions.ranges.layer_time[time_mode_id].get_color_at(m_layers_times[time_mode_id][i],
|
for (size_t i = 0; i < zs.size(); ++i) {
|
||||||
(m_view_type == EViewType::LayerTimeLinear) ? Extrusions::Range::EType::Linear : Extrusions::Range::EType::Logarithmic);
|
if (std::abs(zs[i] - z) < EPSILON) {
|
||||||
break;
|
if (ranges[i].contains(sub_path.first.s_id)) {
|
||||||
|
color = m_extrusions.ranges.layer_time[time_mode_id].get_color_at(m_layers_times[time_mode_id][i],
|
||||||
|
(m_view_type == EViewType::LayerTimeLinear) ? Extrusions::Range::EType::Linear : Extrusions::Range::EType::Logarithmic);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EViewType::VolumetricRate: { color = m_extrusions.ranges.volumetric_rate.get_color_at(path.volumetric_rate); break; }
|
case EViewType::VolumetricRate: { color = m_extrusions.ranges.volumetric_rate.get_color_at(path.volumetric_rate); break; }
|
||||||
@ -3637,6 +3944,27 @@ void GCodeViewer::render_legend(float& legend_height)
|
|||||||
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, { 0.1f, 0.1f, 0.1f, 0.8f });
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, { 0.1f, 0.1f, 0.1f, 0.8f });
|
||||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, { 0.2f, 0.2f, 0.2f, 0.8f });
|
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, { 0.2f, 0.2f, 0.2f, 0.8f });
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
std::vector<std::string> view_options;
|
||||||
|
std::vector<int> view_options_id;
|
||||||
|
if (!m_layers_times.empty() && m_layers.size() == m_layers_times.front().size()) {
|
||||||
|
view_options = { _u8L("Feature type"), _u8L("Height (mm)"), _u8L("Width (mm)"), _u8L("Speed (mm/s)"), _u8L("Fan speed (%)"),
|
||||||
|
_u8L("Temperature (°C)"), _u8L("Volumetric flow rate (mm³/s)"), _u8L("Layer time (linear)"), _u8L("Layer time (logarithmic)"),
|
||||||
|
_u8L("Tool"), _u8L("Color Print") };
|
||||||
|
view_options_id = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
view_options = { _u8L("Feature type"), _u8L("Height (mm)"), _u8L("Width (mm)"), _u8L("Speed (mm/s)"), _u8L("Fan speed (%)"),
|
||||||
|
_u8L("Temperature (°C)"), _u8L("Volumetric flow rate (mm³/s)"), _u8L("Tool"), _u8L("Color Print") };
|
||||||
|
view_options_id = { 0, 1, 2, 3, 4, 5, 6, 9, 10 };
|
||||||
|
if (view_type == 7 || view_type == 8)
|
||||||
|
view_type = 0;
|
||||||
|
}
|
||||||
|
auto view_type_it = std::find(view_options_id.begin(), view_options_id.end(), view_type);
|
||||||
|
int view_type_id = (view_type_it == view_options_id.end()) ? 0 : std::distance(view_options_id.begin(), view_type_it);
|
||||||
|
if (imgui.combo(std::string(), view_options, view_type_id, ImGuiComboFlags_HeightLargest, 0.0f, -1.0f))
|
||||||
|
view_type = view_options_id[view_type_id];
|
||||||
|
#else
|
||||||
imgui.combo(std::string(), { _u8L("Feature type"),
|
imgui.combo(std::string(), { _u8L("Feature type"),
|
||||||
_u8L("Height (mm)"),
|
_u8L("Height (mm)"),
|
||||||
_u8L("Width (mm)"),
|
_u8L("Width (mm)"),
|
||||||
@ -3648,6 +3976,7 @@ void GCodeViewer::render_legend(float& legend_height)
|
|||||||
_u8L("Layer time (logarithmic)"),
|
_u8L("Layer time (logarithmic)"),
|
||||||
_u8L("Tool"),
|
_u8L("Tool"),
|
||||||
_u8L("Color Print") }, view_type, ImGuiComboFlags_HeightLargest, 0.0f, -1.0f);
|
_u8L("Color Print") }, view_type, ImGuiComboFlags_HeightLargest, 0.0f, -1.0f);
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
ImGui::PopStyleColor(2);
|
ImGui::PopStyleColor(2);
|
||||||
|
|
||||||
if (old_view_type != view_type) {
|
if (old_view_type != view_type) {
|
||||||
|
@ -6,7 +6,9 @@
|
|||||||
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
||||||
#include "GLModel.hpp"
|
#include "GLModel.hpp"
|
||||||
|
|
||||||
|
#if !ENABLE_BINARIZED_GCODE
|
||||||
#include <boost/iostreams/device/mapped_file.hpp>
|
#include <boost/iostreams/device/mapped_file.hpp>
|
||||||
|
#endif // !ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
@ -673,6 +675,54 @@ public:
|
|||||||
void render();
|
void render();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
class GCodeWindow
|
||||||
|
{
|
||||||
|
struct Line
|
||||||
|
{
|
||||||
|
std::string command;
|
||||||
|
std::string parameters;
|
||||||
|
std::string comment;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Range
|
||||||
|
{
|
||||||
|
std::optional<size_t> min;
|
||||||
|
std::optional<size_t> max;
|
||||||
|
bool empty() const {
|
||||||
|
return !min.has_value() || !max.has_value();
|
||||||
|
}
|
||||||
|
bool contains(const Range& other) const {
|
||||||
|
return !this->empty() && !other.empty() && *this->min <= *other.min && *this->max >= other.max;
|
||||||
|
}
|
||||||
|
size_t size() const {
|
||||||
|
return empty() ? 0 : *this->max - *this->min + 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool m_visible{ true };
|
||||||
|
std::string m_filename;
|
||||||
|
bool m_is_binary_file{ false };
|
||||||
|
// map for accessing data in file by line number
|
||||||
|
std::vector<std::vector<size_t>> m_lines_ends;
|
||||||
|
std::vector<Line> m_lines_cache;
|
||||||
|
Range m_cache_range;
|
||||||
|
size_t m_max_line_length{ 0 };
|
||||||
|
|
||||||
|
public:
|
||||||
|
void load_gcode(const GCodeProcessorResult& gcode_result);
|
||||||
|
void reset() {
|
||||||
|
m_lines_ends.clear();
|
||||||
|
m_lines_cache.clear();
|
||||||
|
m_filename.clear();
|
||||||
|
}
|
||||||
|
void toggle_visibility() { m_visible = !m_visible; }
|
||||||
|
void render(float top, float bottom, size_t curr_line_id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void add_gcode_line_to_lines_cache(const std::string& src);
|
||||||
|
};
|
||||||
|
#else
|
||||||
class GCodeWindow
|
class GCodeWindow
|
||||||
{
|
{
|
||||||
struct Line
|
struct Line
|
||||||
@ -692,7 +742,7 @@ public:
|
|||||||
std::vector<Line> m_lines;
|
std::vector<Line> m_lines;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GCodeWindow() = default;
|
GCodeWindow() = default;
|
||||||
~GCodeWindow() { stop_mapping_file(); }
|
~GCodeWindow() { stop_mapping_file(); }
|
||||||
void load_gcode(const std::string& filename, const std::vector<size_t>& lines_ends);
|
void load_gcode(const std::string& filename, const std::vector<size_t>& lines_ends);
|
||||||
void reset() {
|
void reset() {
|
||||||
@ -708,6 +758,7 @@ public:
|
|||||||
|
|
||||||
void stop_mapping_file();
|
void stop_mapping_file();
|
||||||
};
|
};
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
struct Endpoints
|
struct Endpoints
|
||||||
{
|
{
|
||||||
|
@ -1998,6 +1998,11 @@ void GLCanvas3D::render()
|
|||||||
#endif // ENABLE_SLA_VIEW_DEBUG_WINDOW
|
#endif // ENABLE_SLA_VIEW_DEBUG_WINDOW
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE_DEBUG_WINDOW
|
||||||
|
if (wxGetApp().plater()->is_view3D_shown() && current_printer_technology() != ptSLA && fff_print()->config().gcode_binary)
|
||||||
|
show_binary_gcode_debug_window();
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE_DEBUG_WINDOW
|
||||||
|
|
||||||
std::string tooltip;
|
std::string tooltip;
|
||||||
|
|
||||||
// Negative coordinate means out of the window, likely because the window was deactivated.
|
// Negative coordinate means out of the window, likely because the window was deactivated.
|
||||||
@ -7762,6 +7767,96 @@ void GLCanvas3D::GizmoHighlighter::blink()
|
|||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE_DEBUG_WINDOW
|
||||||
|
void GLCanvas3D::show_binary_gcode_debug_window()
|
||||||
|
{
|
||||||
|
bgcode::binarize::BinarizerConfig& binarizer_config = GCodeProcessor::get_binarizer_config();
|
||||||
|
|
||||||
|
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||||
|
imgui.begin(std::string("Binary GCode"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||||
|
|
||||||
|
using namespace bgcode::core;
|
||||||
|
if (ImGui::BeginTable("BinaryGCodeConfig", 2)) {
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "File metadata compression");
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
std::vector<std::string> options = { "None", "Deflate", "heatshrink 11,4", "heatshrink 12,4" };
|
||||||
|
int option_id = (int)binarizer_config.compression.file_metadata;
|
||||||
|
if (imgui.combo(std::string("##file_metadata_compression"), options, option_id, ImGuiComboFlags_HeightLargest, 0.0f, 175.0f))
|
||||||
|
binarizer_config.compression.file_metadata = (ECompressionType)option_id;
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Printer metadata compression");
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
option_id = (int)binarizer_config.compression.printer_metadata;
|
||||||
|
if (imgui.combo(std::string("##printer_metadata_compression"), options, option_id, ImGuiComboFlags_HeightLargest, 0.0f, 175.0f))
|
||||||
|
binarizer_config.compression.printer_metadata = (ECompressionType)option_id;
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Print metadata compression");
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
option_id = (int)binarizer_config.compression.print_metadata;
|
||||||
|
if (imgui.combo(std::string("##print_metadata_compression"), options, option_id, ImGuiComboFlags_HeightLargest, 0.0f, 175.0f))
|
||||||
|
binarizer_config.compression.print_metadata = (ECompressionType)option_id;
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Slicer metadata compression");
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
option_id = (int)binarizer_config.compression.slicer_metadata;
|
||||||
|
if (imgui.combo(std::string("##slicer_metadata_compression"), options, option_id, ImGuiComboFlags_HeightLargest, 0.0f, 175.0f))
|
||||||
|
binarizer_config.compression.slicer_metadata = (ECompressionType)option_id;
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "GCode compression");
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
option_id = (int)binarizer_config.compression.gcode;
|
||||||
|
if (imgui.combo(std::string("##gcode_compression"), options, option_id, ImGuiComboFlags_HeightLargest, 0.0f, 175.0f))
|
||||||
|
binarizer_config.compression.gcode = (ECompressionType)option_id;
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "GCode encoding");
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
options = { "None", "MeatPack", "MeatPack Comments" };
|
||||||
|
option_id = (int)binarizer_config.gcode_encoding;
|
||||||
|
if (imgui.combo(std::string("##gcode_encoding"), options, option_id, ImGuiComboFlags_HeightLargest, 0.0f, 175.0f))
|
||||||
|
binarizer_config.gcode_encoding = (EGCodeEncodingType)option_id;
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Metadata encoding");
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
options = { "INI" };
|
||||||
|
option_id = (int)binarizer_config.metadata_encoding;
|
||||||
|
if (imgui.combo(std::string("##metadata_encoding"), options, option_id, ImGuiComboFlags_HeightLargest, 0.0f, 175.0f))
|
||||||
|
binarizer_config.metadata_encoding = (EMetadataEncodingType)option_id;
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Checksum type");
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
options = { "None", "CRC32" };
|
||||||
|
option_id = (int)binarizer_config.checksum;
|
||||||
|
if (imgui.combo(std::string("##4"), options, option_id, ImGuiComboFlags_HeightLargest, 0.0f, 175.0f))
|
||||||
|
binarizer_config.checksum = (EChecksumType)option_id;
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
imgui.text("!!! WARNING !!!");
|
||||||
|
imgui.text("Changing values does NOT invalidate the current slice");
|
||||||
|
}
|
||||||
|
|
||||||
|
imgui.end();
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE_DEBUG_WINDOW
|
||||||
|
|
||||||
const ModelVolume *get_model_volume(const GLVolume &v, const Model &model)
|
const ModelVolume *get_model_volume(const GLVolume &v, const Model &model)
|
||||||
{
|
{
|
||||||
const ModelVolume * ret = nullptr;
|
const ModelVolume * ret = nullptr;
|
||||||
|
@ -1097,6 +1097,10 @@ private:
|
|||||||
bool _deactivate_arrange_menu();
|
bool _deactivate_arrange_menu();
|
||||||
|
|
||||||
float get_overlay_window_width() { return LayersEditing::get_overlay_window_width(); }
|
float get_overlay_window_width() { return LayersEditing::get_overlay_window_width(); }
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE_DEBUG_WINDOW
|
||||||
|
void show_binary_gcode_debug_window();
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE_DEBUG_WINDOW
|
||||||
};
|
};
|
||||||
|
|
||||||
const ModelVolume *get_model_volume(const GLVolume &v, const Model &model);
|
const ModelVolume *get_model_volume(const GLVolume &v, const Model &model);
|
||||||
|
@ -785,7 +785,8 @@ bool ImGuiWrapper::combo(const wxString& label, const std::vector<std::string>&
|
|||||||
bool ImGuiWrapper::combo(const std::string& label, const std::vector<std::string>& options, int& selection, ImGuiComboFlags flags/* = 0*/, float label_width/* = 0.0f*/, float item_width/* = 0.0f*/)
|
bool ImGuiWrapper::combo(const std::string& label, const std::vector<std::string>& options, int& selection, ImGuiComboFlags flags/* = 0*/, float label_width/* = 0.0f*/, float item_width/* = 0.0f*/)
|
||||||
{
|
{
|
||||||
// this is to force the label to the left of the widget:
|
// this is to force the label to the left of the widget:
|
||||||
if (!label.empty()) {
|
const bool hidden_label = boost::starts_with(label, "##");
|
||||||
|
if (!label.empty() && !hidden_label) {
|
||||||
text(label);
|
text(label);
|
||||||
ImGui::SameLine(label_width);
|
ImGui::SameLine(label_width);
|
||||||
}
|
}
|
||||||
@ -795,7 +796,7 @@ bool ImGuiWrapper::combo(const std::string& label, const std::vector<std::string
|
|||||||
bool res = false;
|
bool res = false;
|
||||||
|
|
||||||
const char *selection_str = selection < int(options.size()) && selection >= 0 ? options[selection].c_str() : "";
|
const char *selection_str = selection < int(options.size()) && selection >= 0 ? options[selection].c_str() : "";
|
||||||
if (ImGui::BeginCombo(("##" + label).c_str(), selection_str, flags)) {
|
if (ImGui::BeginCombo(hidden_label ? label.c_str() : ("##" + label).c_str(), selection_str, flags)) {
|
||||||
for (int i = 0; i < (int)options.size(); i++) {
|
for (int i = 0; i < (int)options.size(); i++) {
|
||||||
if (ImGui::Selectable(options[i].c_str(), i == selection)) {
|
if (ImGui::Selectable(options[i].c_str(), i == selection)) {
|
||||||
selection_out = i;
|
selection_out = i;
|
||||||
|
@ -1349,6 +1349,17 @@ void MainFrame::init_menubar_as_editor()
|
|||||||
[]() {return true; }, this);
|
[]() {return true; }, this);
|
||||||
append_submenu(fileMenu, export_menu, wxID_ANY, _L("&Export"), "");
|
append_submenu(fileMenu, export_menu, wxID_ANY, _L("&Export"), "");
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
wxMenu* convert_menu = new wxMenu();
|
||||||
|
append_menu_item(convert_menu, wxID_ANY, _L("Convert ascii G-code to &binary") + dots, _L("Convert a G-code file from ascii to binary format"),
|
||||||
|
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->convert_gcode_to_binary(); }, "convert_file", nullptr,
|
||||||
|
[this]() { return true; }, this);
|
||||||
|
append_menu_item(convert_menu, wxID_ANY, _L("Convert binary G-code to &ascii") + dots, _L("Convert a G-code file from binary to ascii format"),
|
||||||
|
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->convert_gcode_to_ascii(); }, "convert_file", nullptr,
|
||||||
|
[this]() { return true; }, this);
|
||||||
|
append_submenu(fileMenu, convert_menu, wxID_ANY, _L("&Convert"), "");
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
append_menu_item(fileMenu, wxID_ANY, _L("Ejec&t SD Card / Flash Drive") + dots + "\tCtrl+T", _L("Eject SD card / Flash drive after the G-code was exported to it."),
|
append_menu_item(fileMenu, wxID_ANY, _L("Ejec&t SD Card / Flash Drive") + dots + "\tCtrl+T", _L("Eject SD card / Flash drive after the G-code was exported to it."),
|
||||||
[this](wxCommandEvent&) { if (m_plater) m_plater->eject_drive(); }, "eject_sd", nullptr,
|
[this](wxCommandEvent&) { if (m_plater) m_plater->eject_drive(); }, "eject_sd", nullptr,
|
||||||
[this]() {return can_eject(); }, this);
|
[this]() {return can_eject(); }, this);
|
||||||
@ -1621,13 +1632,22 @@ void MainFrame::init_menubar_as_gcodeviewer()
|
|||||||
_L("Reload the plater from disk"), [this](wxCommandEvent&) { m_plater->reload_gcode_from_disk(); },
|
_L("Reload the plater from disk"), [this](wxCommandEvent&) { m_plater->reload_gcode_from_disk(); },
|
||||||
"", nullptr, [this]() { return !m_plater->get_last_loaded_gcode().empty(); }, this);
|
"", nullptr, [this]() { return !m_plater->get_last_loaded_gcode().empty(); }, this);
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
fileMenu->AppendSeparator();
|
||||||
|
append_menu_item(fileMenu, wxID_ANY, _L("Convert ascii G-code to &binary") + dots, _L("Convert a G-code file from ascii to binary format"),
|
||||||
|
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->convert_gcode_to_binary(); }, "convert_file", nullptr,
|
||||||
|
[this]() { return true; }, this);
|
||||||
|
append_menu_item(fileMenu, wxID_ANY, _L("Convert binary G-code to &ascii") + dots, _L("Convert a G-code file from binary to ascii format"),
|
||||||
|
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->convert_gcode_to_ascii(); }, "convert_file", nullptr,
|
||||||
|
[this]() { return true; }, this);
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
fileMenu->AppendSeparator();
|
fileMenu->AppendSeparator();
|
||||||
append_menu_item(fileMenu, wxID_ANY, _L("Export &Toolpaths as OBJ") + dots, _L("Export toolpaths as OBJ"),
|
append_menu_item(fileMenu, wxID_ANY, _L("Export &Toolpaths as OBJ") + dots, _L("Export toolpaths as OBJ"),
|
||||||
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->export_toolpaths_to_obj(); }, "export_plater", nullptr,
|
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->export_toolpaths_to_obj(); }, "export_plater", nullptr,
|
||||||
[this]() {return can_export_toolpaths(); }, this);
|
[this]() {return can_export_toolpaths(); }, this);
|
||||||
append_menu_item(fileMenu, wxID_ANY, _L("Open &PrusaSlicer") + dots, _L("Open PrusaSlicer"),
|
append_menu_item(fileMenu, wxID_ANY, _L("Open &PrusaSlicer") + dots, _L("Open PrusaSlicer"),
|
||||||
[](wxCommandEvent&) { start_new_slicer(); }, "", nullptr,
|
[](wxCommandEvent&) { start_new_slicer(); }, "", nullptr,
|
||||||
[]() {return true; }, this);
|
[]() { return true; }, this);
|
||||||
fileMenu->AppendSeparator();
|
fileMenu->AppendSeparator();
|
||||||
append_menu_item(fileMenu, wxID_EXIT, _L("&Quit"), wxString::Format(_L("Quit %s"), SLIC3R_APP_NAME),
|
append_menu_item(fileMenu, wxID_EXIT, _L("&Quit"), wxString::Format(_L("Quit %s"), SLIC3R_APP_NAME),
|
||||||
[this](wxCommandEvent&) { Close(false); });
|
[this](wxCommandEvent&) { Close(false); });
|
||||||
|
@ -36,6 +36,10 @@
|
|||||||
#include <wx/popupwin.h>
|
#include <wx/popupwin.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
#include <LibBGCode/convert/convert.hpp>
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
#include "libslic3r/Format/STL.hpp"
|
#include "libslic3r/Format/STL.hpp"
|
||||||
#include "libslic3r/Format/AMF.hpp"
|
#include "libslic3r/Format/AMF.hpp"
|
||||||
@ -5440,6 +5444,101 @@ void Plater::reload_gcode_from_disk()
|
|||||||
load_gcode(filename);
|
load_gcode(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
void Plater::convert_gcode_to_ascii()
|
||||||
|
{
|
||||||
|
// Ask user for a gcode file name.
|
||||||
|
wxString input_file;
|
||||||
|
wxGetApp().load_gcode(this, input_file);
|
||||||
|
if (input_file.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Open source file
|
||||||
|
FilePtr in_file{ boost::nowide::fopen(into_u8(input_file).c_str(), "rb") };
|
||||||
|
if (in_file.f == nullptr) {
|
||||||
|
MessageDialog msg_dlg(this, _L("Unable to open the selected file."), _L("Error"), wxICON_ERROR | wxOK);
|
||||||
|
msg_dlg.ShowModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set out filename
|
||||||
|
boost::filesystem::path path(into_u8(input_file));
|
||||||
|
const std::string output_file = path.parent_path().string() + "/" + path.stem().string() + "_ascii" + path.extension().string();
|
||||||
|
|
||||||
|
// Open destination file
|
||||||
|
FilePtr out_file{ boost::nowide::fopen(output_file.c_str(), "wb") };
|
||||||
|
if (out_file.f == nullptr) {
|
||||||
|
MessageDialog msg_dlg(this, _L("Unable to open output file."), _L("Error"), wxICON_ERROR | wxOK);
|
||||||
|
msg_dlg.ShowModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform conversion
|
||||||
|
{
|
||||||
|
wxBusyCursor busy;
|
||||||
|
using namespace bgcode::core;
|
||||||
|
EResult res = bgcode::convert::from_binary_to_ascii(*in_file.f, *out_file.f, true);
|
||||||
|
if (res != EResult::Success) {
|
||||||
|
MessageDialog msg_dlg(this, _L(std::string(translate_result(res))), _L("Error converting gcode file"), wxICON_INFORMATION | wxOK);
|
||||||
|
msg_dlg.ShowModal();
|
||||||
|
out_file.close();
|
||||||
|
boost::nowide::remove(output_file.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageDialog msg_dlg(this, _L("Succesfully created gcode ascii file:\n") + output_file, _L("Convert gcode file to ascii format"), wxICON_ERROR | wxOK);
|
||||||
|
msg_dlg.ShowModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plater::convert_gcode_to_binary()
|
||||||
|
{
|
||||||
|
// Ask user for a gcode file name.
|
||||||
|
wxString input_file;
|
||||||
|
wxGetApp().load_gcode(this, input_file);
|
||||||
|
if (input_file.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Open source file
|
||||||
|
FilePtr in_file{ boost::nowide::fopen(into_u8(input_file).c_str(), "rb") };
|
||||||
|
if (in_file.f == nullptr) {
|
||||||
|
MessageDialog msg_dlg(this, _L("Unable to open the selected file."), _L("Error"), wxICON_ERROR | wxOK);
|
||||||
|
msg_dlg.ShowModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set out filename
|
||||||
|
boost::filesystem::path path(into_u8(input_file));
|
||||||
|
const std::string output_file = path.parent_path().string() + "/" + path.stem().string() + "_binary" + path.extension().string();
|
||||||
|
|
||||||
|
// Open destination file
|
||||||
|
FilePtr out_file{ boost::nowide::fopen(output_file.c_str(), "wb") };
|
||||||
|
if (out_file.f == nullptr) {
|
||||||
|
MessageDialog msg_dlg(this, _L("Unable to open output file."), _L("Error"), wxICON_ERROR | wxOK);
|
||||||
|
msg_dlg.ShowModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform conversion
|
||||||
|
{
|
||||||
|
wxBusyCursor busy;
|
||||||
|
using namespace bgcode::core;
|
||||||
|
const bgcode::binarize::BinarizerConfig& binarizer_config = GCodeProcessor::get_binarizer_config();
|
||||||
|
EResult res = bgcode::convert::from_ascii_to_binary(*in_file.f, *out_file.f, binarizer_config);
|
||||||
|
if (res != EResult::Success) {
|
||||||
|
MessageDialog msg_dlg(this, _L(std::string(translate_result(res))), _L("Error converting gcode file"), wxICON_INFORMATION | wxOK);
|
||||||
|
msg_dlg.ShowModal();
|
||||||
|
out_file.close();
|
||||||
|
boost::nowide::remove(output_file.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageDialog msg_dlg(this, _L("Succesfully created gcode binary file:\n") + output_file, _L("Convert gcode file to binary format"), wxICON_ERROR | wxOK);
|
||||||
|
msg_dlg.ShowModal();
|
||||||
|
}
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
void Plater::refresh_print()
|
void Plater::refresh_print()
|
||||||
{
|
{
|
||||||
p->preview->refresh_print();
|
p->preview->refresh_print();
|
||||||
|
@ -172,6 +172,10 @@ public:
|
|||||||
void load_gcode();
|
void load_gcode();
|
||||||
void load_gcode(const wxString& filename);
|
void load_gcode(const wxString& filename);
|
||||||
void reload_gcode_from_disk();
|
void reload_gcode_from_disk();
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
void convert_gcode_to_ascii();
|
||||||
|
void convert_gcode_to_binary();
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
void refresh_print();
|
void refresh_print();
|
||||||
|
|
||||||
std::vector<size_t> load_files(const std::vector<boost::filesystem::path>& input_files, bool load_model = true, bool load_config = true, bool imperial_units = false);
|
std::vector<size_t> load_files(const std::vector<boost::filesystem::path>& input_files, bool load_model = true, bool load_config = true, bool imperial_units = false);
|
||||||
|
@ -1698,6 +1698,9 @@ void TabPrint::build()
|
|||||||
Option option = optgroup->get_option("output_filename_format");
|
Option option = optgroup->get_option("output_filename_format");
|
||||||
option.opt.full_width = true;
|
option.opt.full_width = true;
|
||||||
optgroup->append_single_option_line(option);
|
optgroup->append_single_option_line(option);
|
||||||
|
#if ENABLE_BINARIZED_GCODE
|
||||||
|
optgroup->append_single_option_line("gcode_binary");
|
||||||
|
#endif // ENABLE_BINARIZED_GCODE
|
||||||
|
|
||||||
optgroup = page->new_optgroup(L("Other"));
|
optgroup = page->new_optgroup(L("Other"));
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ use Slic3r::Test qw(_eq);
|
|||||||
{
|
{
|
||||||
my $config = Slic3r::Config->new;
|
my $config = Slic3r::Config->new;
|
||||||
$config->set('fill_density', 0); # just for making the test faster
|
$config->set('fill_density', 0); # just for making the test faster
|
||||||
|
$config->set('gcode_binary', 0);
|
||||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config, scale => 2);
|
my $print = Slic3r::Test::init_print('20mm_cube', config => $config, scale => 2);
|
||||||
|
|
||||||
my @z = ();
|
my @z = ();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user