Merge branch 'master' into lm_tm_hollowing
@ -72,6 +72,9 @@ if (MSVC)
|
||||
# error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater
|
||||
# Generate symbols at every build target, even for the release.
|
||||
add_compile_options(-bigobj -Zm520 /Zi)
|
||||
# Disable STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17.
|
||||
#FIXME Remove this line after eigen library adapts to the new C++17 adaptor rules.
|
||||
add_compile_options(-D_SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING)
|
||||
endif ()
|
||||
|
||||
if (MINGW)
|
||||
|
2
deps/MPFR/MPFR.cmake
vendored
@ -21,7 +21,7 @@ else ()
|
||||
ExternalProject_Add(dep_MPFR
|
||||
URL http://ftp.vim.org/ftp/gnu/mpfr/mpfr-3.1.6.tar.bz2 https://www.mpfr.org/mpfr-3.1.6/mpfr-3.1.6.tar.bz2 # mirrors are allowed
|
||||
BUILD_IN_SOURCE ON
|
||||
CONFIGURE_COMMAND ./configure --prefix=${DESTDIR}/usr/local --with-gmp=${DESTDIR}/usr/local --with-pic
|
||||
CONFIGURE_COMMAND ./configure --prefix=${DESTDIR}/usr/local --enable-shared=no --enable-static=yes --with-gmp=${DESTDIR}/usr/local --with-pic
|
||||
BUILD_COMMAND make -j
|
||||
INSTALL_COMMAND make install
|
||||
DEPENDS dep_GMP
|
||||
|
12
resources/icons/error_tick.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
|
||||
<g id="error_tick">
|
||||
<path fill="#808080" d="M8,1.85l5.29,3.53V7v3.62L8,14.15l-5.29-3.53V7V5.38L8,1.85 M8,1L2,5v2v4l6,4l6-4V7V5L8,1L8,1z"/>
|
||||
|
||||
<path fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-width="2" d="M8 4 L8 9" />
|
||||
|
||||
<circle fill="#ED6B21" cx="8" cy="12" r="1"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 640 B |
@ -3622,8 +3622,7 @@ msgstr ""
|
||||
|
||||
#: src/slic3r/GUI/Plater.cpp:2315
|
||||
msgid ""
|
||||
"You can't load SLA project if there is at least one multi-part object on the "
|
||||
"bed"
|
||||
"You cannot load SLA project with a multi-part object on the bed"
|
||||
msgstr ""
|
||||
|
||||
#: src/slic3r/GUI/Plater.cpp:2316 src/slic3r/GUI/Tab.cpp:2915
|
||||
|
@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-09-09 16:39+0200\n"
|
||||
"PO-Revision-Date: 2019-11-18 16:39-0300\n"
|
||||
"PO-Revision-Date: 2019-12-21 19:55-0300\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -1432,7 +1432,7 @@ msgid ""
|
||||
"You will lose content of the plater."
|
||||
msgstr ""
|
||||
"Alterar a linguagem fará com que o aplicativo reinicie.\n"
|
||||
"Você irá perder conteúdo no prato."
|
||||
"Você irá perder conteúdo na bandeja."
|
||||
|
||||
#: src/slic3r/GUI/GUI_App.cpp:877
|
||||
msgid "Do you want to proceed?"
|
||||
@ -2302,7 +2302,7 @@ msgstr "(Re)fatiar"
|
||||
|
||||
#: src/slic3r/GUI/KBShortcutsDialog.cpp:116
|
||||
msgid "Select Plater Tab"
|
||||
msgstr "Selecione a guia de prato"
|
||||
msgstr "Selecione a guia de bandeja"
|
||||
|
||||
#: src/slic3r/GUI/KBShortcutsDialog.cpp:118
|
||||
msgid "Select Print Settings Tab"
|
||||
@ -2466,7 +2466,7 @@ msgstr "Desmarcar Gizmo/limpar seleção"
|
||||
|
||||
#: src/slic3r/GUI/KBShortcutsDialog.cpp:166
|
||||
msgid "Plater Shortcuts"
|
||||
msgstr "Atalhos do prato"
|
||||
msgstr "Atalhos da bandeja"
|
||||
|
||||
#: src/slic3r/GUI/KBShortcutsDialog.cpp:181
|
||||
#: src/slic3r/GUI/KBShortcutsDialog.cpp:193
|
||||
@ -2546,7 +2546,7 @@ msgstr "baseado no Slic3r"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:189
|
||||
msgid "Plater"
|
||||
msgstr "Prato"
|
||||
msgstr "Bandeja"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:400
|
||||
msgid "&New Project"
|
||||
@ -2635,7 +2635,7 @@ msgstr "Exportar &G-code"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:469
|
||||
msgid "Export current plate as G-code"
|
||||
msgstr "Exporte o prato atual como o G-code"
|
||||
msgstr "Exporte a bandeja atual como o G-code"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:473 src/slic3r/GUI/MainFrame.cpp:720
|
||||
msgid "S&end G-code"
|
||||
@ -2643,31 +2643,31 @@ msgstr "E&nviar G-code"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:473
|
||||
msgid "Send to print current plate as G-code"
|
||||
msgstr "Enviar para imprimir prato atual como G-code"
|
||||
msgstr "Enviar para imprimir a bandeja atual como G-code"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:478
|
||||
msgid "Export plate as &STL"
|
||||
msgstr "Exportar prato como &STL"
|
||||
msgstr "Exportar bandeja como &STL"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:478
|
||||
msgid "Export current plate as STL"
|
||||
msgstr "Exporte o prato atual como STL"
|
||||
msgstr "Exporte a bandeja atual como STL"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:481
|
||||
msgid "Export plate as STL &including supports"
|
||||
msgstr "Exportar prato como STL &incluindo suportes"
|
||||
msgstr "Exportar bandeja como STL &incluindo suportes"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:481
|
||||
msgid "Export current plate as STL including supports"
|
||||
msgstr "Exporte o prato atual como o STL que inclui suportes"
|
||||
msgstr "Exporte a bandeja atual como o STL que inclui suportes"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:484
|
||||
msgid "Export plate as &AMF"
|
||||
msgstr "Exportar prato como &AMF"
|
||||
msgstr "Exportar bandeja como &AMF"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:484
|
||||
msgid "Export current plate as AMF"
|
||||
msgstr "Exporte o prato atual como o AMF"
|
||||
msgstr "Exporte a bandeja atual como o AMF"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:488
|
||||
msgid "Export &toolpaths as OBJ"
|
||||
@ -2804,11 +2804,11 @@ msgstr "Colar área de transferência"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:590
|
||||
msgid "&Plater Tab"
|
||||
msgstr "&Prato"
|
||||
msgstr "&Bandeja"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:590
|
||||
msgid "Show the plater"
|
||||
msgstr "Mostrar o prato"
|
||||
msgstr "Mostrar a bandeja"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:597
|
||||
msgid "P&rint Settings Tab"
|
||||
@ -6198,7 +6198,7 @@ msgstr "Distância entre cópias"
|
||||
|
||||
#: src/libslic3r/PrintConfig.cpp:352
|
||||
msgid "Distance used for the auto-arrange feature of the plater."
|
||||
msgstr "Distância usada para o recurso de organizar automaticamente o prato."
|
||||
msgstr "Distância usada para o recurso de organizar automaticamente a bandeja."
|
||||
|
||||
#: src/libslic3r/PrintConfig.cpp:359
|
||||
msgid "Elephant foot compensation"
|
||||
@ -6395,8 +6395,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Defina isso para o raio de folga em torno de sua extrusora. Se a extrusora "
|
||||
"não estiver centralizada, escolha o maior valor para a segurança. Essa "
|
||||
"config. é usada para verificar colisões e exibir a visualização gráfica no "
|
||||
"prato."
|
||||
"config. é usada para verificar colisões e exibir a visualização gráfica na "
|
||||
"bandeja."
|
||||
|
||||
#: src/libslic3r/PrintConfig.cpp:505
|
||||
msgid "Extruder Color"
|
||||
|
@ -18,6 +18,9 @@ config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/Prusa
|
||||
name = Creality Ender-3
|
||||
variants = 0.4
|
||||
technology = FFF
|
||||
bed_model = ender3_bed.stl
|
||||
bed_texture = ender3.svg
|
||||
default_materials = Creality PLA @ENDER3; Prusament PLA @ENDER3
|
||||
|
||||
# All presets starting with asterisk, for example *common*, are intermediate and they will
|
||||
# not make it into the user interface.
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
@ -22,72 +22,108 @@ name = Original Prusa MINI
|
||||
variants = 0.4; 0.25; 0.6
|
||||
technology = FFF
|
||||
family = MINI
|
||||
bed_model = mini_bed.stl
|
||||
bed_texture = mini.svg
|
||||
default_materials = Prusament PLA; Prusament PETG @MINI
|
||||
|
||||
[printer_model:MK3S]
|
||||
name = Original Prusa i3 MK3S
|
||||
variants = 0.4; 0.25; 0.6
|
||||
technology = FFF
|
||||
family = MK3
|
||||
bed_model = mk3_bed.stl
|
||||
bed_texture = mk3.svg
|
||||
default_materials = Prusament PLA; Prusament PETG
|
||||
|
||||
[printer_model:MK3]
|
||||
name = Original Prusa i3 MK3
|
||||
variants = 0.4; 0.25; 0.6
|
||||
technology = FFF
|
||||
family = MK3
|
||||
bed_model = mk3_bed.stl
|
||||
bed_texture = mk3.svg
|
||||
default_materials = Prusament PLA; Prusament PETG
|
||||
|
||||
[printer_model:MK3SMMU2S]
|
||||
name = Original Prusa i3 MK3S MMU2S
|
||||
variants = 0.4; 0.25; 0.6
|
||||
technology = FFF
|
||||
family = MK3
|
||||
bed_model = mk3_bed.stl
|
||||
bed_texture = mk3.svg
|
||||
default_materials = Prusament PLA @MMU2; Prusament PETG @MMU2
|
||||
|
||||
[printer_model:MK3MMU2]
|
||||
name = Original Prusa i3 MK3 MMU2
|
||||
variants = 0.4; 0.25; 0.6
|
||||
technology = FFF
|
||||
family = MK3
|
||||
bed_model = mk3_bed.stl
|
||||
bed_texture = mk3.svg
|
||||
default_materials = Prusament PLA @MMU2; Prusament PETG @MMU2
|
||||
|
||||
[printer_model:MK2.5S]
|
||||
name = Original Prusa i3 MK2.5S
|
||||
variants = 0.4; 0.25; 0.6
|
||||
technology = FFF
|
||||
family = MK2.5
|
||||
bed_model = mk3_bed.stl
|
||||
bed_texture = mk3.svg
|
||||
default_materials = Prusament PLA; Prusament PETG
|
||||
|
||||
[printer_model:MK2.5]
|
||||
name = Original Prusa i3 MK2.5
|
||||
variants = 0.4; 0.25; 0.6
|
||||
technology = FFF
|
||||
family = MK2.5
|
||||
bed_model = mk3_bed.stl
|
||||
bed_texture = mk3.svg
|
||||
default_materials = Prusament PLA; Prusament PETG
|
||||
|
||||
[printer_model:MK2.5SMMU2S]
|
||||
name = Original Prusa i3 MK2.5S MMU2S
|
||||
variants = 0.4; 0.25; 0.6
|
||||
technology = FFF
|
||||
family = MK2.5
|
||||
bed_model = mk3_bed.stl
|
||||
bed_texture = mk3.svg
|
||||
default_materials = Prusament PLA @MMU2; Prusament PETG @MMU2
|
||||
|
||||
[printer_model:MK2.5MMU2]
|
||||
name = Original Prusa i3 MK2.5 MMU2
|
||||
variants = 0.4; 0.25; 0.6
|
||||
technology = FFF
|
||||
family = MK2.5
|
||||
bed_model = mk3_bed.stl
|
||||
bed_texture = mk3.svg
|
||||
default_materials = Prusament PLA @MMU2; Prusament PETG @MMU2
|
||||
|
||||
[printer_model:MK2S]
|
||||
name = Original Prusa i3 MK2S
|
||||
variants = 0.4; 0.25; 0.6
|
||||
technology = FFF
|
||||
family = MK2
|
||||
bed_model = mk2_bed.stl
|
||||
bed_texture = mk2.svg
|
||||
default_materials = Prusament PLA; Prusament PETG
|
||||
|
||||
[printer_model:MK2SMM]
|
||||
name = Original Prusa i3 MK2S MMU1
|
||||
variants = 0.4; 0.6
|
||||
technology = FFF
|
||||
family = MK2
|
||||
bed_model = mk2_bed.stl
|
||||
bed_texture = mk2.svg
|
||||
default_materials = Prusament PLA; Prusament PETG @MMU1
|
||||
|
||||
[printer_model:SL1]
|
||||
name = Original Prusa SL1
|
||||
variants = default
|
||||
technology = SLA
|
||||
family = SL1
|
||||
bed_model = sl1_bed.stl
|
||||
bed_texture = sl1.svg
|
||||
default_materials = Prusa Transparent Tough @0.05
|
||||
|
||||
# All presets starting with asterisk, for example *common*, are intermediate and they will
|
||||
# not make it into the user interface.
|
||||
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.2 KiB |
@ -641,10 +641,18 @@ bool CLI::export_models(IO::ExportFormat format)
|
||||
const std::string path = this->output_filepath(model, format);
|
||||
bool success = false;
|
||||
switch (format) {
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
case IO::AMF: success = Slic3r::store_amf(path.c_str(), &model, nullptr, false); break;
|
||||
#else
|
||||
case IO::AMF: success = Slic3r::store_amf(path.c_str(), &model, nullptr); break;
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
case IO::OBJ: success = Slic3r::store_obj(path.c_str(), &model); break;
|
||||
case IO::STL: success = Slic3r::store_stl(path.c_str(), &model, true); break;
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
case IO::TMF: success = Slic3r::store_3mf(path.c_str(), &model, nullptr, false); break;
|
||||
#else
|
||||
case IO::TMF: success = Slic3r::store_3mf(path.c_str(), &model, nullptr); break;
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
default: assert(false); break;
|
||||
}
|
||||
if (success)
|
||||
|
@ -24,7 +24,7 @@ set(LIBNEST2D_SRCFILES
|
||||
src/libnest2d.cpp
|
||||
)
|
||||
|
||||
add_library(libnest2d ${LIBNEST2D_SRCFILES})
|
||||
add_library(libnest2d STATIC ${LIBNEST2D_SRCFILES})
|
||||
|
||||
target_include_directories(libnest2d PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
target_link_libraries(libnest2d PUBLIC clipper NLopt::nlopt TBB::tbb Boost::boost)
|
||||
|
@ -1116,12 +1116,8 @@ private:
|
||||
for(Item& item : items_) item.translate(d);
|
||||
}
|
||||
|
||||
void setInitialPosition(Item& item) {
|
||||
auto sh = item.rawShape();
|
||||
sl::translate(sh, item.translation());
|
||||
sl::rotate(sh, item.rotation());
|
||||
|
||||
Box bb = sl::boundingBox(sh);
|
||||
void setInitialPosition(Item& item) {
|
||||
Box bb = item.boundingBox();
|
||||
|
||||
Vertex ci, cb;
|
||||
auto bbin = sl::boundingBox(bin_);
|
||||
|
@ -289,13 +289,13 @@ public:
|
||||
throw std::runtime_error("ConfigOptionVector::set_at(): Assigning an incompatible type");
|
||||
}
|
||||
|
||||
T& get_at(size_t i)
|
||||
const T& get_at(size_t i) const
|
||||
{
|
||||
assert(! this->values.empty());
|
||||
return (i < this->values.size()) ? this->values[i] : this->values.front();
|
||||
}
|
||||
|
||||
const T& get_at(size_t i) const { return const_cast<ConfigOptionVector<T>*>(this)->get_at(i); }
|
||||
T& get_at(size_t i) { return const_cast<T&>(std::as_const(*this).get_at(i)); }
|
||||
|
||||
// Resize this vector by duplicating the /*last*/first value.
|
||||
// If the current vector is empty, the default value is used instead.
|
||||
@ -500,7 +500,7 @@ public:
|
||||
if (NULLABLE)
|
||||
this->values.push_back(nil_value());
|
||||
else
|
||||
std::runtime_error("Deserializing nil into a non-nullable object");
|
||||
throw std::runtime_error("Deserializing nil into a non-nullable object");
|
||||
} else {
|
||||
std::istringstream iss(item_str);
|
||||
double value;
|
||||
@ -525,9 +525,9 @@ protected:
|
||||
if (NULLABLE)
|
||||
ss << "nil";
|
||||
else
|
||||
std::runtime_error("Serializing NaN");
|
||||
throw std::runtime_error("Serializing NaN");
|
||||
} else
|
||||
std::runtime_error("Serializing invalid number");
|
||||
throw std::runtime_error("Serializing invalid number");
|
||||
}
|
||||
static bool vectors_equal(const std::vector<double> &v1, const std::vector<double> &v2) {
|
||||
if (NULLABLE) {
|
||||
@ -646,7 +646,7 @@ public:
|
||||
if (NULLABLE)
|
||||
this->values.push_back(nil_value());
|
||||
else
|
||||
std::runtime_error("Deserializing nil into a non-nullable object");
|
||||
throw std::runtime_error("Deserializing nil into a non-nullable object");
|
||||
} else {
|
||||
std::istringstream iss(item_str);
|
||||
int value;
|
||||
@ -663,7 +663,7 @@ private:
|
||||
if (NULLABLE)
|
||||
ss << "nil";
|
||||
else
|
||||
std::runtime_error("Serializing NaN");
|
||||
throw std::runtime_error("Serializing NaN");
|
||||
} else
|
||||
ss << v;
|
||||
}
|
||||
@ -1126,7 +1126,7 @@ public:
|
||||
if (NULLABLE)
|
||||
this->values.push_back(nil_value());
|
||||
else
|
||||
std::runtime_error("Deserializing nil into a non-nullable object");
|
||||
throw std::runtime_error("Deserializing nil into a non-nullable object");
|
||||
} else
|
||||
this->values.push_back(item_str.compare("1") == 0);
|
||||
}
|
||||
@ -1139,7 +1139,7 @@ protected:
|
||||
if (NULLABLE)
|
||||
ss << "nil";
|
||||
else
|
||||
std::runtime_error("Serializing NaN");
|
||||
throw std::runtime_error("Serializing NaN");
|
||||
} else
|
||||
ss << (v ? "1" : "0");
|
||||
}
|
||||
@ -1638,7 +1638,7 @@ class DynamicConfig : public virtual ConfigBase
|
||||
public:
|
||||
DynamicConfig() {}
|
||||
DynamicConfig(const DynamicConfig &rhs) { *this = rhs; }
|
||||
DynamicConfig(DynamicConfig &&rhs) : options(std::move(rhs.options)) { rhs.options.clear(); }
|
||||
DynamicConfig(DynamicConfig &&rhs) noexcept : options(std::move(rhs.options)) { rhs.options.clear(); }
|
||||
explicit DynamicConfig(const ConfigBase &rhs, const t_config_option_keys &keys);
|
||||
explicit DynamicConfig(const ConfigBase& rhs) : DynamicConfig(rhs, rhs.keys()) {}
|
||||
virtual ~DynamicConfig() override { clear(); }
|
||||
@ -1656,7 +1656,7 @@ public:
|
||||
|
||||
// Move a content of one DynamicConfig to another DynamicConfig.
|
||||
// If rhs.def() is not null, then it has to be equal to this->def().
|
||||
DynamicConfig& operator=(DynamicConfig &&rhs)
|
||||
DynamicConfig& operator=(DynamicConfig &&rhs) noexcept
|
||||
{
|
||||
assert(this->def() == nullptr || this->def() == rhs.def());
|
||||
this->clear();
|
||||
|
@ -19,7 +19,7 @@ class ExPolygon
|
||||
public:
|
||||
ExPolygon() {}
|
||||
ExPolygon(const ExPolygon &other) : contour(other.contour), holes(other.holes) {}
|
||||
ExPolygon(ExPolygon &&other) : contour(std::move(other.contour)), holes(std::move(other.holes)) {}
|
||||
ExPolygon(ExPolygon &&other) noexcept : contour(std::move(other.contour)), holes(std::move(other.holes)) {}
|
||||
explicit ExPolygon(const Polygon &contour) : contour(contour) {}
|
||||
explicit ExPolygon(Polygon &&contour) : contour(std::move(contour)) {}
|
||||
explicit ExPolygon(const Points &contour) : contour(contour) {}
|
||||
@ -32,7 +32,7 @@ public:
|
||||
ExPolygon(std::initializer_list<Point> contour, std::initializer_list<Point> hole) : contour(contour), holes({ hole }) {}
|
||||
|
||||
ExPolygon& operator=(const ExPolygon &other) { contour = other.contour; holes = other.holes; return *this; }
|
||||
ExPolygon& operator=(ExPolygon &&other) { contour = std::move(other.contour); holes = std::move(other.holes); return *this; }
|
||||
ExPolygon& operator=(ExPolygon &&other) noexcept { contour = std::move(other.contour); holes = std::move(other.holes); return *this; }
|
||||
|
||||
Polygon contour;
|
||||
Polygons holes;
|
||||
|
@ -48,9 +48,6 @@ public:
|
||||
double retract_length_toolchange() const;
|
||||
double retract_restart_extra_toolchange() const;
|
||||
|
||||
// Constructor for a key object, to be used by the stdlib search functions.
|
||||
static Extruder key(unsigned int id) { return Extruder(id); }
|
||||
|
||||
private:
|
||||
// Private constructor to create a key for a search in std::set.
|
||||
Extruder(unsigned int id) : m_id(id) {}
|
||||
|
@ -6,6 +6,26 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
void filter_by_extrusion_role_in_place(ExtrusionEntitiesPtr &extrusion_entities, ExtrusionRole role)
|
||||
{
|
||||
if (role != erMixed) {
|
||||
auto first = extrusion_entities.begin();
|
||||
auto last = extrusion_entities.end();
|
||||
auto result = first;
|
||||
while (first != last) {
|
||||
// The caller wants only paths with a specific extrusion role.
|
||||
auto role2 = (*first)->role();
|
||||
if (role != role2) {
|
||||
// This extrusion entity does not match the role asked.
|
||||
assert(role2 != erMixed);
|
||||
*result = *first;
|
||||
++ result;
|
||||
}
|
||||
++ first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExtrusionEntityCollection::ExtrusionEntityCollection(const ExtrusionPaths &paths)
|
||||
: no_sort(false)
|
||||
{
|
||||
@ -74,31 +94,16 @@ void ExtrusionEntityCollection::remove(size_t i)
|
||||
this->entities.erase(this->entities.begin() + i);
|
||||
}
|
||||
|
||||
ExtrusionEntityCollection ExtrusionEntityCollection::chained_path_from(const Point &start_near, ExtrusionRole role) const
|
||||
ExtrusionEntityCollection ExtrusionEntityCollection::chained_path_from(const ExtrusionEntitiesPtr& extrusion_entities, const Point &start_near, ExtrusionRole role)
|
||||
{
|
||||
ExtrusionEntityCollection out;
|
||||
if (this->no_sort) {
|
||||
out = *this;
|
||||
} else {
|
||||
if (role == erMixed)
|
||||
out = *this;
|
||||
else {
|
||||
for (const ExtrusionEntity *ee : this->entities) {
|
||||
if (role != erMixed) {
|
||||
// The caller wants only paths with a specific extrusion role.
|
||||
auto role2 = ee->role();
|
||||
if (role != role2) {
|
||||
// This extrusion entity does not match the role asked.
|
||||
assert(role2 != erMixed);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
out.entities.emplace_back(ee->clone());
|
||||
}
|
||||
}
|
||||
chain_and_reorder_extrusion_entities(out.entities, &start_near);
|
||||
}
|
||||
return out;
|
||||
// Return a filtered copy of the collection.
|
||||
ExtrusionEntityCollection out;
|
||||
out.entities = filter_by_extrusion_role(extrusion_entities, role);
|
||||
// Clone the extrusion entities.
|
||||
for (auto &ptr : out.entities)
|
||||
ptr = ptr->clone();
|
||||
chain_and_reorder_extrusion_entities(out.entities, &start_near);
|
||||
return out;
|
||||
}
|
||||
|
||||
void ExtrusionEntityCollection::polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const
|
||||
|
@ -6,6 +6,21 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Remove those items from extrusion_entities, that do not match role.
|
||||
// Do nothing if role is mixed.
|
||||
// Removed elements are NOT being deleted.
|
||||
void filter_by_extrusion_role_in_place(ExtrusionEntitiesPtr &extrusion_entities, ExtrusionRole role);
|
||||
|
||||
// Return new vector of ExtrusionEntities* with only those items from input extrusion_entities, that match role.
|
||||
// Return all extrusion entities if role is mixed.
|
||||
// Returned extrusion entities are shared with the source vector, they are NOT cloned, they are considered to be owned by extrusion_entities.
|
||||
inline ExtrusionEntitiesPtr filter_by_extrusion_role(const ExtrusionEntitiesPtr &extrusion_entities, ExtrusionRole role)
|
||||
{
|
||||
ExtrusionEntitiesPtr out { extrusion_entities };
|
||||
filter_by_extrusion_role_in_place(out, role);
|
||||
return out;
|
||||
}
|
||||
|
||||
class ExtrusionEntityCollection : public ExtrusionEntity
|
||||
{
|
||||
public:
|
||||
@ -65,7 +80,9 @@ public:
|
||||
}
|
||||
void replace(size_t i, const ExtrusionEntity &entity);
|
||||
void remove(size_t i);
|
||||
ExtrusionEntityCollection chained_path_from(const Point &start_near, ExtrusionRole role = erMixed) const;
|
||||
static ExtrusionEntityCollection chained_path_from(const ExtrusionEntitiesPtr &extrusion_entities, const Point &start_near, ExtrusionRole role = erMixed);
|
||||
ExtrusionEntityCollection chained_path_from(const Point &start_near, ExtrusionRole role = erMixed) const
|
||||
{ return this->no_sort ? *this : chained_path_from(this->entities, start_near, role); }
|
||||
void reverse();
|
||||
const Point& first_point() const { return this->entities.front()->first_point(); }
|
||||
const Point& last_point() const { return this->entities.back()->last_point(); }
|
||||
@ -105,6 +122,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif
|
||||
|
@ -107,9 +107,9 @@ double Flow::mm3_per_mm() const
|
||||
{
|
||||
float res = this->bridge ?
|
||||
// Area of a circle with dmr of this->width.
|
||||
(this->width * this->width) * 0.25 * PI :
|
||||
float((this->width * this->width) * 0.25 * PI) :
|
||||
// Rectangle with semicircles at the ends. ~ h (w - 0.215 h)
|
||||
this->height * (this->width - this->height * (1. - 0.25 * PI));
|
||||
float(this->height * (this->width - this->height * (1. - 0.25 * PI)));
|
||||
//assert(res > 0.);
|
||||
if (res <= 0.)
|
||||
throw std::runtime_error("Flow::mm3_per_mm() produced negative flow. Did you set some extrusion width too small?");
|
||||
|
@ -1187,7 +1187,7 @@ namespace Slic3r {
|
||||
return;
|
||||
pt::ptree code_tree = main_tree.front().second;
|
||||
|
||||
m_model->custom_gcode_per_print_z.clear();
|
||||
m_model->custom_gcode_per_print_z.gcodes.clear();
|
||||
|
||||
for (const auto& code : code_tree)
|
||||
{
|
||||
@ -1199,7 +1199,7 @@ namespace Slic3r {
|
||||
int extruder = tree.get<int> ("<xmlattr>.extruder" );
|
||||
std::string color = tree.get<std::string> ("<xmlattr>.color" );
|
||||
|
||||
m_model->custom_gcode_per_print_z.push_back(Model::CustomGCode{print_z, gcode, extruder, color}) ;
|
||||
m_model->custom_gcode_per_print_z.gcodes.push_back(Model::CustomGCode{print_z, gcode, extruder, color}) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1816,9 +1816,6 @@ namespace Slic3r {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
Transform3d inv_matrix = volume_matrix_to_object.inverse();
|
||||
#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
|
||||
// splits volume out of imported geometry
|
||||
TriangleMesh triangle_mesh;
|
||||
@ -1838,15 +1835,7 @@ namespace Slic3r {
|
||||
for (unsigned int v = 0; v < 3; ++v)
|
||||
{
|
||||
unsigned int tri_id = geometry.triangles[src_start_id + ii + v] * 3;
|
||||
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
facet.vertex[v] = Vec3f(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]);
|
||||
#else
|
||||
Vec3f vertex(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]);
|
||||
facet.vertex[v] = has_transform ?
|
||||
// revert the vertices to the original mesh reference system
|
||||
(inv_matrix * vertex.cast<double>()).cast<float>() :
|
||||
vertex;
|
||||
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
}
|
||||
}
|
||||
|
||||
@ -1854,15 +1843,9 @@ namespace Slic3r {
|
||||
triangle_mesh.repair();
|
||||
|
||||
ModelVolume* volume = object.add_volume(std::move(triangle_mesh));
|
||||
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
// stores the volume matrix taken from the metadata, if present
|
||||
if (has_transform)
|
||||
volume->source.transform = Slic3r::Geometry::Transformation(volume_matrix_to_object);
|
||||
#else
|
||||
// apply the volume matrix taken from the metadata, if present
|
||||
if (has_transform)
|
||||
volume->set_transformation(Slic3r::Geometry::Transformation(volume_matrix_to_object));
|
||||
#endif //ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
volume->calculate_convex_hull();
|
||||
|
||||
// apply the remaining volume's metadata
|
||||
@ -1975,12 +1958,24 @@ namespace Slic3r {
|
||||
typedef std::vector<BuildItem> BuildItemsList;
|
||||
typedef std::map<int, ObjectData> IdToObjectDataMap;
|
||||
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
bool m_fullpath_sources{ true };
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
|
||||
public:
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr);
|
||||
#else
|
||||
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#else
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data = nullptr);
|
||||
#else
|
||||
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
|
||||
private:
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
@ -2006,6 +2001,22 @@ namespace Slic3r {
|
||||
bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||
};
|
||||
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data)
|
||||
{
|
||||
clear_errors();
|
||||
m_fullpath_sources = fullpath_sources;
|
||||
return _save_model_to_file(filename, model, config, thumbnail_data);
|
||||
}
|
||||
#else
|
||||
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources)
|
||||
{
|
||||
clear_errors();
|
||||
return _save_model_to_file(filename, model, config);
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#else
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data)
|
||||
{
|
||||
@ -2019,6 +2030,7 @@ namespace Slic3r {
|
||||
return _save_model_to_file(filename, model, config);
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data)
|
||||
@ -2690,11 +2702,7 @@ namespace Slic3r {
|
||||
|
||||
// stores volume's local matrix
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MATRIX_KEY << "\" " << VALUE_ATTR << "=\"";
|
||||
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
Transform3d matrix = volume->get_matrix() * volume->source.transform.get_matrix();
|
||||
#else
|
||||
const Transform3d& matrix = volume->get_matrix();
|
||||
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
for (int r = 0; r < 4; ++r)
|
||||
{
|
||||
for (int c = 0; c < 4; ++c)
|
||||
@ -2709,7 +2717,12 @@ namespace Slic3r {
|
||||
// stores volume's source data
|
||||
if (!volume->source.input_file.empty())
|
||||
{
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
std::string input_file = xml_escape(m_fullpath_sources ? volume->source.input_file : boost::filesystem::path(volume->source.input_file).filename().string());
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_FILE_KEY << "\" " << VALUE_ATTR << "=\"" << input_file << "\"/>\n";
|
||||
#else
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_FILE_KEY << "\" " << VALUE_ATTR << "=\"" << xml_escape(volume->source.input_file) << "\"/>\n";
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OBJECT_ID_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.object_idx << "\"/>\n";
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_VOLUME_ID_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.volume_idx << "\"/>\n";
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OFFSET_X_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(0) << "\"/>\n";
|
||||
@ -2749,12 +2762,12 @@ bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archiv
|
||||
{
|
||||
std::string out = "";
|
||||
|
||||
if (!model.custom_gcode_per_print_z.empty())
|
||||
if (!model.custom_gcode_per_print_z.gcodes.empty())
|
||||
{
|
||||
pt::ptree tree;
|
||||
pt::ptree& main_tree = tree.add("custom_gcodes_per_print_z", "");
|
||||
|
||||
for (const Model::CustomGCode& code : model.custom_gcode_per_print_z)
|
||||
for (const Model::CustomGCode& code : model.custom_gcode_per_print_z.gcodes)
|
||||
{
|
||||
pt::ptree& code_tree = main_tree.add("code", "");
|
||||
// store minX and maxZ
|
||||
@ -2798,21 +2811,37 @@ bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool c
|
||||
return res;
|
||||
}
|
||||
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data)
|
||||
#else
|
||||
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources)
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#else
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data)
|
||||
#else
|
||||
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config)
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
{
|
||||
if ((path == nullptr) || (model == nullptr))
|
||||
return false;
|
||||
|
||||
_3MF_Exporter exporter;
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool res = exporter.save_model_to_file(path, *model, config, fullpath_sources, thumbnail_data);
|
||||
#else
|
||||
bool res = exporter.save_model_to_file(path, *model, config, fullpath_sources);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#else
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool res = exporter.save_model_to_file(path, *model, config, thumbnail_data);
|
||||
#else
|
||||
bool res = exporter.save_model_to_file(path, *model, config);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
|
||||
if (!res)
|
||||
exporter.log_errors();
|
||||
|
@ -35,11 +35,19 @@ namespace Slic3r {
|
||||
|
||||
// Save the given model and the config data contained in the given Print into a 3mf file.
|
||||
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr);
|
||||
#else
|
||||
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#else
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data = nullptr);
|
||||
#else
|
||||
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
|
@ -585,36 +585,20 @@ void AMFParserContext::endElement(const char * /* name */)
|
||||
stl_allocate(&stl);
|
||||
|
||||
bool has_transform = ! m_volume_transform.isApprox(Transform3d::Identity(), 1e-10);
|
||||
#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
Transform3d inv_matrix = m_volume_transform.inverse();
|
||||
#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
for (size_t i = 0; i < m_volume_facets.size();) {
|
||||
stl_facet &facet = stl.facet_start[i/3];
|
||||
for (unsigned int v = 0; v < 3; ++v)
|
||||
{
|
||||
unsigned int tri_id = m_volume_facets[i++] * 3;
|
||||
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
facet.vertex[v] = Vec3f(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]);
|
||||
#else
|
||||
Vec3f vertex(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]);
|
||||
facet.vertex[v] = has_transform ?
|
||||
// revert the vertices to the original mesh reference system
|
||||
(inv_matrix * vertex.cast<double>()).cast<float>() :
|
||||
vertex;
|
||||
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
}
|
||||
}
|
||||
stl_get_size(&stl);
|
||||
mesh.repair();
|
||||
m_volume->set_mesh(std::move(mesh));
|
||||
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
// stores the volume matrix taken from the metadata, if present
|
||||
if (has_transform)
|
||||
m_volume->source.transform = Slic3r::Geometry::Transformation(m_volume_transform);
|
||||
#else
|
||||
if (has_transform)
|
||||
m_volume->set_transformation(m_volume_transform);
|
||||
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
if (m_volume->source.input_file.empty() && (m_volume->type() == ModelVolumeType::MODEL_PART))
|
||||
{
|
||||
m_volume->source.object_idx = (int)m_model.objects.size() - 1;
|
||||
@ -653,7 +637,7 @@ void AMFParserContext::endElement(const char * /* name */)
|
||||
int extruder = atoi(m_value[2].c_str());
|
||||
const std::string& color = m_value[3];
|
||||
|
||||
m_model.custom_gcode_per_print_z.push_back(Model::CustomGCode{height, gcode, extruder, color});
|
||||
m_model.custom_gcode_per_print_z.gcodes.push_back(Model::CustomGCode{height, gcode, extruder, color});
|
||||
|
||||
for (std::string& val: m_value)
|
||||
val.clear();
|
||||
@ -1019,7 +1003,11 @@ bool load_amf(const char* path, DynamicPrintConfig* config, Model* model, bool c
|
||||
return false;
|
||||
}
|
||||
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources)
|
||||
#else
|
||||
bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
{
|
||||
if ((path == nullptr) || (model == nullptr))
|
||||
return false;
|
||||
@ -1159,11 +1147,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
||||
stream << " <metadata type=\"slic3r.modifier\">1</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.volume_type\">" << ModelVolume::type_to_string(volume->type()) << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.matrix\">";
|
||||
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
const Transform3d& matrix = volume->get_matrix() * volume->source.transform.get_matrix();
|
||||
#else
|
||||
const Transform3d& matrix = volume->get_matrix();
|
||||
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
stream << std::setprecision(std::numeric_limits<double>::max_digits10);
|
||||
for (int r = 0; r < 4; ++r)
|
||||
{
|
||||
@ -1177,7 +1161,12 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
||||
stream << "</metadata>\n";
|
||||
if (!volume->source.input_file.empty())
|
||||
{
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
std::string input_file = xml_escape(fullpath_sources ? volume->source.input_file : boost::filesystem::path(volume->source.input_file).filename().string());
|
||||
stream << " <metadata type=\"slic3r.source_file\">" << input_file << "</metadata>\n";
|
||||
#else
|
||||
stream << " <metadata type=\"slic3r.source_file\">" << xml_escape(volume->source.input_file) << "</metadata>\n";
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
stream << " <metadata type=\"slic3r.source_object_id\">" << volume->source.object_idx << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.source_volume_id\">" << volume->source.volume_idx << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.source_offset_x\">" << volume->source.mesh_offset(0) << "</metadata>\n";
|
||||
@ -1241,14 +1230,14 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
||||
stream << " </constellation>\n";
|
||||
}
|
||||
|
||||
if (!model->custom_gcode_per_print_z.empty())
|
||||
if (!model->custom_gcode_per_print_z.gcodes.empty())
|
||||
{
|
||||
std::string out = "";
|
||||
pt::ptree tree;
|
||||
|
||||
pt::ptree& main_tree = tree.add("custom_gcodes_per_height", "");
|
||||
|
||||
for (const Model::CustomGCode& code : model->custom_gcode_per_print_z)
|
||||
for (const Model::CustomGCode& code : model->custom_gcode_per_print_z.gcodes)
|
||||
{
|
||||
pt::ptree& code_tree = main_tree.add("code", "");
|
||||
// store minX and maxZ
|
||||
|
@ -11,7 +11,11 @@ extern bool load_amf(const char* path, DynamicPrintConfig* config, Model* model,
|
||||
|
||||
// Save the given model and the config data into an amf file.
|
||||
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
extern bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources);
|
||||
#else
|
||||
extern bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config);
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
|
@ -197,23 +197,25 @@ public:
|
||||
// append full config to the given string
|
||||
static void append_full_config(const Print& print, std::string& str);
|
||||
|
||||
protected:
|
||||
// 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
|
||||
struct LayerToPrint
|
||||
{
|
||||
LayerToPrint() : object_layer(nullptr), support_layer(nullptr) {}
|
||||
const Layer* object_layer;
|
||||
const SupportLayer* support_layer;
|
||||
const Layer* layer() const { return (object_layer != nullptr) ? object_layer : support_layer; }
|
||||
const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; }
|
||||
coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; }
|
||||
};
|
||||
|
||||
private:
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void _do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb);
|
||||
void _do_export(Print &print, FILE *file, ThumbnailsGeneratorCallback thumbnail_cb);
|
||||
#else
|
||||
void _do_export(Print &print, FILE *file);
|
||||
#endif //ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// Object and support extrusions of the same PrintObject at the same print_z.
|
||||
struct LayerToPrint
|
||||
{
|
||||
LayerToPrint() : object_layer(nullptr), support_layer(nullptr) {}
|
||||
const Layer *object_layer;
|
||||
const SupportLayer *support_layer;
|
||||
const Layer* layer() const { return (object_layer != nullptr) ? object_layer : support_layer; }
|
||||
const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; }
|
||||
coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; }
|
||||
};
|
||||
static std::vector<LayerToPrint> collect_layers_to_print(const PrintObject &object);
|
||||
static std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> collect_layers_to_print(const Print &print);
|
||||
void process_layer(
|
||||
@ -239,7 +241,6 @@ protected:
|
||||
std::string extrude_multi_path(ExtrusionMultiPath multipath, std::string description = "", double speed = -1.);
|
||||
std::string extrude_path(ExtrusionPath path, std::string description = "", double speed = -1.);
|
||||
|
||||
typedef std::vector<int> ExtruderPerCopy;
|
||||
// Extruding multiple objects with soluble / non-soluble / combined supports
|
||||
// on a multi-material printer, trying to minimize tool switches.
|
||||
// Following structures sort extrusions by the extruder ID, by an order of objects and object islands.
|
||||
@ -253,21 +254,29 @@ protected:
|
||||
struct Island
|
||||
{
|
||||
struct Region {
|
||||
ExtrusionEntityCollection perimeters;
|
||||
ExtrusionEntityCollection infills;
|
||||
// Non-owned references to LayerRegion::perimeters::entities
|
||||
// std::vector<const ExtrusionEntity*> would be better here, but there is no way in C++ to convert from std::vector<T*> std::vector<const T*> without copying.
|
||||
ExtrusionEntitiesPtr perimeters;
|
||||
// Non-owned references to LayerRegion::fills::entities
|
||||
ExtrusionEntitiesPtr infills;
|
||||
|
||||
std::vector<const ExtruderPerCopy*> infills_overrides;
|
||||
std::vector<const ExtruderPerCopy*> perimeters_overrides;
|
||||
std::vector<const WipingExtrusions::ExtruderPerCopy*> infills_overrides;
|
||||
std::vector<const WipingExtrusions::ExtruderPerCopy*> perimeters_overrides;
|
||||
|
||||
enum Type {
|
||||
PERIMETERS,
|
||||
INFILL,
|
||||
};
|
||||
|
||||
// Appends perimeter/infill entities and writes don't indices of those that are not to be extruder as part of perimeter/infill wiping
|
||||
void append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copy_extruders, size_t object_copies_num);
|
||||
void append(const Type type, const ExtrusionEntityCollection* eec, const WipingExtrusions::ExtruderPerCopy* copy_extruders);
|
||||
};
|
||||
|
||||
std::vector<Region> by_region; // all extrusions for this island, grouped by regions
|
||||
const std::vector<Region>& by_region_per_copy(unsigned int copy, int extruder, bool wiping_entities = false); // returns reference to subvector of by_region
|
||||
|
||||
private:
|
||||
std::vector<Region> by_region_per_copy_cache; // caches vector generated by function above to avoid copying and recalculating
|
||||
std::vector<Region> by_region; // all extrusions for this island, grouped by regions
|
||||
|
||||
// Fills in by_region_per_copy_cache and returns its reference.
|
||||
const std::vector<Region>& by_region_per_copy(std::vector<Region> &by_region_per_copy_cache, unsigned int copy, unsigned int extruder, bool wiping_entities = false) const;
|
||||
};
|
||||
std::vector<Island> islands;
|
||||
};
|
||||
@ -277,7 +286,9 @@ protected:
|
||||
InstanceToPrint(ObjectByExtruder &object_by_extruder, size_t layer_id, const PrintObject &print_object, size_t instance_id) :
|
||||
object_by_extruder(object_by_extruder), layer_id(layer_id), print_object(print_object), instance_id(instance_id) {}
|
||||
|
||||
ObjectByExtruder &object_by_extruder;
|
||||
// Repository
|
||||
ObjectByExtruder &object_by_extruder;
|
||||
// Index into std::vector<LayerToPrint>, which contains Object and Support layers for the current print_z, collected for a single object, or for possibly multiple objects with multiple instances.
|
||||
const size_t layer_id;
|
||||
const PrintObject &print_object;
|
||||
// Instance idx of the copy of a print object.
|
||||
@ -285,7 +296,8 @@ protected:
|
||||
};
|
||||
|
||||
std::vector<InstanceToPrint> sort_print_object_instances(
|
||||
std::vector<ObjectByExtruder> &objects_by_extruder,
|
||||
std::vector<ObjectByExtruder> &objects_by_extruder,
|
||||
// Object and Support layers for the current print_z, collected for a single object, or for possibly multiple objects with multiple instances.
|
||||
const std::vector<LayerToPrint> &layers,
|
||||
// Ordering must be defined for normal (non-sequential print).
|
||||
const std::vector<std::pair<size_t, size_t>> *ordering,
|
||||
@ -354,7 +366,7 @@ protected:
|
||||
#endif /* HAS_PRESSURE_EQUALIZER */
|
||||
std::unique_ptr<WipeTowerIntegration> m_wipe_tower;
|
||||
|
||||
// Heights at which the skirt has already been extruded.
|
||||
// Heights (print_z) at which the skirt has already been extruded.
|
||||
std::vector<coordf_t> m_skirt_done;
|
||||
// Has the brim been extruded already? Brim is being extruded only for the first object of a multi-object print.
|
||||
bool m_brim_done;
|
||||
@ -362,11 +374,6 @@ protected:
|
||||
bool m_second_layer_things_done;
|
||||
// Index of a last object copy extruded.
|
||||
std::pair<const PrintObject*, Point> m_last_obj_copy;
|
||||
// Extensions for colorprint - now it's not a just color_print_heights,
|
||||
// there can be some custom gcode.
|
||||
// Updated before the export and erased during the process,
|
||||
// so no toolchange occurs twice.
|
||||
std::vector<Model::CustomGCode> m_custom_gcode_per_print_z;
|
||||
|
||||
// Time estimators
|
||||
GCodeTimeEstimator m_normal_time_estimator;
|
||||
|
@ -311,24 +311,22 @@ void GCodeAnalyzer::_processG1(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
auto axis_absolute_position = [this](GCodeAnalyzer::EAxis axis, const GCodeReader::GCodeLine& lineG1) -> float
|
||||
{
|
||||
float current_absolute_position = _get_axis_position(axis);
|
||||
float current_origin = _get_axis_origin(axis);
|
||||
float lengthsScaleFactor = (_get_units() == GCodeAnalyzer::Inches) ? INCHES_TO_MM : 1.0f;
|
||||
|
||||
bool is_relative = (_get_global_positioning_type() == Relative);
|
||||
if (axis == E)
|
||||
is_relative |= (_get_e_local_positioning_type() == Relative);
|
||||
|
||||
if (lineG1.has(Slic3r::Axis(axis)))
|
||||
{
|
||||
float lengthsScaleFactor = (_get_units() == GCodeAnalyzer::Inches) ? INCHES_TO_MM : 1.0f;
|
||||
float ret = lineG1.value(Slic3r::Axis(axis)) * lengthsScaleFactor;
|
||||
return is_relative ? current_absolute_position + ret : ret + current_origin;
|
||||
return is_relative ? _get_axis_position(axis) + ret : _get_axis_origin(axis) + ret;
|
||||
}
|
||||
else
|
||||
return current_absolute_position;
|
||||
return _get_axis_position(axis);
|
||||
};
|
||||
|
||||
// updates axes positions from line
|
||||
|
||||
float new_pos[Num_Axis];
|
||||
for (unsigned char a = X; a < Num_Axis; ++a)
|
||||
{
|
||||
@ -352,7 +350,7 @@ void GCodeAnalyzer::_processG1(const GCodeReader::GCodeLine& line)
|
||||
if (delta_pos[E] < 0.0f)
|
||||
{
|
||||
if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f) || (delta_pos[Z] != 0.0f))
|
||||
type = GCodeMove::Move;
|
||||
type = GCodeMove::Move;
|
||||
else
|
||||
type = GCodeMove::Retract;
|
||||
}
|
||||
@ -440,7 +438,9 @@ void GCodeAnalyzer::_processG92(const GCodeReader::GCodeLine& line)
|
||||
|
||||
if (line.has_e())
|
||||
{
|
||||
_set_axis_origin(E, _get_axis_position(E) - line.e() * lengthsScaleFactor);
|
||||
// extruder coordinate can grow to the point where its float representation does not allow for proper addition with small increments,
|
||||
// we set the value taken from the G92 line as the new current position for it
|
||||
_set_axis_position(E, line.e() * lengthsScaleFactor);
|
||||
anyFound = true;
|
||||
}
|
||||
|
||||
@ -956,7 +956,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
||||
GCodePreviewData::Extrusion::Path &path = paths.back();
|
||||
path.polyline = polyline;
|
||||
path.extrusion_role = data.extrusion_role;
|
||||
path.mm3_per_mm = data.mm3_per_mm;
|
||||
path.mm3_per_mm = float(data.mm3_per_mm);
|
||||
path.width = data.width;
|
||||
path.height = data.height;
|
||||
path.feedrate = data.feedrate;
|
||||
@ -978,7 +978,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
||||
float volumetric_rate = FLT_MAX;
|
||||
GCodePreviewData::Range height_range;
|
||||
GCodePreviewData::Range width_range;
|
||||
GCodePreviewData::Range feedrate_range;
|
||||
GCodePreviewData::MultiRange<GCodePreviewData::FeedrateKind> feedrate_range;
|
||||
GCodePreviewData::Range volumetric_rate_range;
|
||||
GCodePreviewData::Range fan_speed_range;
|
||||
|
||||
@ -1013,7 +1013,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
||||
volumetric_rate = move.data.feedrate * (float)move.data.mm3_per_mm;
|
||||
height_range.update_from(move.data.height);
|
||||
width_range.update_from(move.data.width);
|
||||
feedrate_range.update_from(move.data.feedrate);
|
||||
feedrate_range.update_from(move.data.feedrate, GCodePreviewData::FeedrateKind::EXTRUSION);
|
||||
volumetric_rate_range.update_from(volumetric_rate);
|
||||
fan_speed_range.update_from(move.data.fan_speed);
|
||||
}
|
||||
@ -1066,7 +1066,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s
|
||||
|
||||
GCodePreviewData::Range height_range;
|
||||
GCodePreviewData::Range width_range;
|
||||
GCodePreviewData::Range feedrate_range;
|
||||
GCodePreviewData::MultiRange<GCodePreviewData::FeedrateKind> feedrate_range;
|
||||
|
||||
// to avoid to call the callback too often
|
||||
unsigned int cancel_callback_threshold = (unsigned int)std::max((int)travel_moves->second.size() / 25, 1);
|
||||
@ -1106,7 +1106,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s
|
||||
extruder_id = move.data.extruder_id;
|
||||
height_range.update_from(move.data.height);
|
||||
width_range.update_from(move.data.width);
|
||||
feedrate_range.update_from(move.data.feedrate);
|
||||
feedrate_range.update_from(move.data.feedrate, GCodePreviewData::FeedrateKind::TRAVEL);
|
||||
}
|
||||
|
||||
// store last polyline
|
||||
|
@ -303,8 +303,8 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
|
||||
unsigned int extruder_id = extruders[i].id();
|
||||
adj.extruder_id = extruder_id;
|
||||
adj.cooling_slow_down_enabled = config.cooling.get_at(extruder_id);
|
||||
adj.slowdown_below_layer_time = config.slowdown_below_layer_time.get_at(extruder_id);
|
||||
adj.min_print_speed = config.min_print_speed.get_at(extruder_id);
|
||||
adj.slowdown_below_layer_time = float(config.slowdown_below_layer_time.get_at(extruder_id));
|
||||
adj.min_print_speed = float(config.min_print_speed.get_at(extruder_id));
|
||||
map_extruder_to_per_extruder_adjustment[extruder_id] = i;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "Analyzer.hpp"
|
||||
#include "PreviewData.hpp"
|
||||
#include <float.h>
|
||||
#include <I18N.hpp>
|
||||
#include "Utils.hpp"
|
||||
|
||||
@ -11,9 +10,7 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
const GCodePreviewData::Color GCodePreviewData::Color::Dummy(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
std::vector<unsigned char> GCodePreviewData::Color::as_bytes() const
|
||||
std::vector<unsigned char> Color::as_bytes() const
|
||||
{
|
||||
std::vector<unsigned char> ret;
|
||||
for (unsigned int i = 0; i < 4; ++i)
|
||||
@ -38,20 +35,6 @@ GCodePreviewData::Travel::Polyline::Polyline(EType type, EDirection direction, f
|
||||
{
|
||||
}
|
||||
|
||||
const GCodePreviewData::Color GCodePreviewData::Range::Default_Colors[Colors_Count] =
|
||||
{
|
||||
Color(0.043f, 0.173f, 0.478f, 1.0f),
|
||||
Color(0.075f, 0.349f, 0.522f, 1.0f),
|
||||
Color(0.110f, 0.533f, 0.569f, 1.0f),
|
||||
Color(0.016f, 0.839f, 0.059f, 1.0f),
|
||||
Color(0.667f, 0.949f, 0.000f, 1.0f),
|
||||
Color(0.988f, 0.975f, 0.012f, 1.0f),
|
||||
Color(0.961f, 0.808f, 0.039f, 1.0f),
|
||||
Color(0.890f, 0.533f, 0.125f, 1.0f),
|
||||
Color(0.820f, 0.408f, 0.188f, 1.0f),
|
||||
Color(0.761f, 0.322f, 0.235f, 1.0f)
|
||||
};
|
||||
|
||||
GCodePreviewData::Range::Range()
|
||||
{
|
||||
reset();
|
||||
@ -59,69 +42,73 @@ GCodePreviewData::Range::Range()
|
||||
|
||||
void GCodePreviewData::Range::reset()
|
||||
{
|
||||
min = FLT_MAX;
|
||||
max = -FLT_MAX;
|
||||
min_val = FLT_MAX;
|
||||
max_val = -FLT_MAX;
|
||||
}
|
||||
|
||||
bool GCodePreviewData::Range::empty() const
|
||||
{
|
||||
return min == max;
|
||||
return min_val >= max_val;
|
||||
}
|
||||
|
||||
void GCodePreviewData::Range::update_from(float value)
|
||||
{
|
||||
min = std::min(min, value);
|
||||
max = std::max(max, value);
|
||||
min_val = std::min(min_val, value);
|
||||
max_val = std::max(max_val, value);
|
||||
}
|
||||
|
||||
void GCodePreviewData::Range::update_from(const Range& other)
|
||||
void GCodePreviewData::Range::update_from(const RangeBase& other)
|
||||
{
|
||||
min = std::min(min, other.min);
|
||||
max = std::max(max, other.max);
|
||||
min_val = std::min(min_val, other.min());
|
||||
max_val = std::max(max_val, other.max());
|
||||
}
|
||||
|
||||
void GCodePreviewData::Range::set_from(const Range& other)
|
||||
float GCodePreviewData::RangeBase::step_size() const
|
||||
{
|
||||
min = other.min;
|
||||
max = other.max;
|
||||
return (max() - min()) / static_cast<float>(range_rainbow_colors.size() - 1);
|
||||
}
|
||||
|
||||
float GCodePreviewData::Range::step_size() const
|
||||
Color GCodePreviewData::RangeBase::get_color_at(float value) const
|
||||
{
|
||||
return (max - min) / (float)(Colors_Count - 1);
|
||||
}
|
||||
// Input value scaled to the color range
|
||||
float step = step_size();
|
||||
const float global_t = (step != 0.0f) ? std::max(0.0f, value - min()) / step_size() : 0.0f; // lower limit of 0.0f
|
||||
|
||||
GCodePreviewData::Color GCodePreviewData::Range::get_color_at(float value) const
|
||||
{
|
||||
if (empty())
|
||||
return Color::Dummy;
|
||||
constexpr std::size_t color_max_idx = range_rainbow_colors.size() - 1;
|
||||
|
||||
float global_t = (value - min) / step_size();
|
||||
// Compute the two colors just below (low) and above (high) the input value
|
||||
const std::size_t color_low_idx = std::clamp(static_cast<std::size_t>(global_t), std::size_t{ 0 }, color_max_idx);
|
||||
const std::size_t color_high_idx = std::clamp(color_low_idx + 1, std::size_t{ 0 }, color_max_idx);
|
||||
|
||||
unsigned int low = (unsigned int)global_t;
|
||||
unsigned int high = clamp((unsigned int)0, Colors_Count - 1, low + 1);
|
||||
// Compute how far the value is between the low and high colors so that they can be interpolated
|
||||
const float local_t = std::min(global_t - static_cast<float>(color_low_idx), 1.0f); // upper limit of 1.0f
|
||||
|
||||
Color color_low = colors[low];
|
||||
Color color_high = colors[high];
|
||||
|
||||
float local_t = global_t - (float)low;
|
||||
|
||||
// interpolate in RGB space
|
||||
// Interpolate between the low and high colors in RGB space to find exactly which color the input value should get
|
||||
Color ret;
|
||||
for (unsigned int i = 0; i < 4; ++i)
|
||||
{
|
||||
ret.rgba[i] = lerp(color_low.rgba[i], color_high.rgba[i], local_t);
|
||||
ret.rgba[i] = lerp(range_rainbow_colors[color_low_idx].rgba[i], range_rainbow_colors[color_high_idx].rgba[i], local_t);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
GCodePreviewData::LegendItem::LegendItem(const std::string& text, const GCodePreviewData::Color& color)
|
||||
float GCodePreviewData::Range::min() const
|
||||
{
|
||||
return min_val;
|
||||
}
|
||||
|
||||
float GCodePreviewData::Range::max() const
|
||||
{
|
||||
return max_val;
|
||||
}
|
||||
|
||||
GCodePreviewData::LegendItem::LegendItem(const std::string& text, const Color& color)
|
||||
: text(text)
|
||||
, color(color)
|
||||
{
|
||||
}
|
||||
|
||||
const GCodePreviewData::Color GCodePreviewData::Extrusion::Default_Extrusion_Role_Colors[erCount] =
|
||||
const Color GCodePreviewData::Extrusion::Default_Extrusion_Role_Colors[erCount] =
|
||||
{
|
||||
Color(0.0f, 0.0f, 0.0f, 1.0f), // erNone
|
||||
Color(1.0f, 0.0f, 0.0f, 1.0f), // erPerimeter
|
||||
@ -180,7 +167,7 @@ size_t GCodePreviewData::Extrusion::memory_used() const
|
||||
|
||||
const float GCodePreviewData::Travel::Default_Width = 0.075f;
|
||||
const float GCodePreviewData::Travel::Default_Height = 0.075f;
|
||||
const GCodePreviewData::Color GCodePreviewData::Travel::Default_Type_Colors[Num_Types] =
|
||||
const Color GCodePreviewData::Travel::Default_Type_Colors[Num_Types] =
|
||||
{
|
||||
Color(0.0f, 0.0f, 0.75f, 1.0f), // Move
|
||||
Color(0.0f, 0.75f, 0.0f, 1.0f), // Extrude
|
||||
@ -206,7 +193,7 @@ size_t GCodePreviewData::Travel::memory_used() const
|
||||
return out;
|
||||
}
|
||||
|
||||
const GCodePreviewData::Color GCodePreviewData::Retraction::Default_Color = GCodePreviewData::Color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
const Color GCodePreviewData::Retraction::Default_Color = Color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
GCodePreviewData::Retraction::Position::Position(const Vec3crd& position, float width, float height)
|
||||
: position(position)
|
||||
@ -238,17 +225,15 @@ GCodePreviewData::GCodePreviewData()
|
||||
|
||||
void GCodePreviewData::set_default()
|
||||
{
|
||||
::memcpy((void*)ranges.height.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
||||
::memcpy((void*)ranges.width.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
||||
::memcpy((void*)ranges.feedrate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
||||
::memcpy((void*)ranges.fan_speed.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
||||
::memcpy((void*)ranges.volumetric_rate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
|
||||
|
||||
extrusion.set_default();
|
||||
travel.set_default();
|
||||
retraction.set_default();
|
||||
unretraction.set_default();
|
||||
shell.set_default();
|
||||
|
||||
// Configure the color range for feedrate to match the default for travels and to enable extrusions since they are always visible
|
||||
ranges.feedrate.set_mode(FeedrateKind::TRAVEL, travel.is_visible);
|
||||
ranges.feedrate.set_mode(FeedrateKind::EXTRUSION, true);
|
||||
}
|
||||
|
||||
void GCodePreviewData::reset()
|
||||
@ -268,32 +253,32 @@ bool GCodePreviewData::empty() const
|
||||
return extrusion.layers.empty() && travel.polylines.empty() && retraction.positions.empty() && unretraction.positions.empty();
|
||||
}
|
||||
|
||||
GCodePreviewData::Color GCodePreviewData::get_extrusion_role_color(ExtrusionRole role) const
|
||||
Color GCodePreviewData::get_extrusion_role_color(ExtrusionRole role) const
|
||||
{
|
||||
return extrusion.role_colors[role];
|
||||
}
|
||||
|
||||
GCodePreviewData::Color GCodePreviewData::get_height_color(float height) const
|
||||
Color GCodePreviewData::get_height_color(float height) const
|
||||
{
|
||||
return ranges.height.get_color_at(height);
|
||||
}
|
||||
|
||||
GCodePreviewData::Color GCodePreviewData::get_width_color(float width) const
|
||||
Color GCodePreviewData::get_width_color(float width) const
|
||||
{
|
||||
return ranges.width.get_color_at(width);
|
||||
}
|
||||
|
||||
GCodePreviewData::Color GCodePreviewData::get_feedrate_color(float feedrate) const
|
||||
Color GCodePreviewData::get_feedrate_color(float feedrate) const
|
||||
{
|
||||
return ranges.feedrate.get_color_at(feedrate);
|
||||
}
|
||||
|
||||
GCodePreviewData::Color GCodePreviewData::get_fan_speed_color(float fan_speed) const
|
||||
Color GCodePreviewData::get_fan_speed_color(float fan_speed) const
|
||||
{
|
||||
return ranges.fan_speed.get_color_at(fan_speed);
|
||||
}
|
||||
|
||||
GCodePreviewData::Color GCodePreviewData::get_volumetric_rate_color(float rate) const
|
||||
Color GCodePreviewData::get_volumetric_rate_color(float rate) const
|
||||
{
|
||||
return ranges.volumetric_rate.get_color_at(rate);
|
||||
}
|
||||
@ -384,16 +369,25 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
|
||||
{
|
||||
struct Helper
|
||||
{
|
||||
static void FillListFromRange(LegendItemsList& list, const Range& range, unsigned int decimals, float scale_factor)
|
||||
static void FillListFromRange(LegendItemsList& list, const RangeBase& range, unsigned int decimals, float scale_factor)
|
||||
{
|
||||
list.reserve(Range::Colors_Count);
|
||||
list.reserve(range_rainbow_colors.size());
|
||||
|
||||
float step = range.step_size();
|
||||
for (int i = Range::Colors_Count - 1; i >= 0; --i)
|
||||
if (step == 0.0f)
|
||||
{
|
||||
char buf[1024];
|
||||
sprintf(buf, "%.*f", decimals, scale_factor * (range.min + (float)i * step));
|
||||
list.emplace_back(buf, range.colors[i]);
|
||||
sprintf(buf, "%.*f", decimals, scale_factor * range.min());
|
||||
list.emplace_back(buf, range_rainbow_colors[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = static_cast<int>(range_rainbow_colors.size()) - 1; i >= 0; --i)
|
||||
{
|
||||
char buf[1024];
|
||||
sprintf(buf, "%.*f", decimals, scale_factor * (range.min() + (float)i * step));
|
||||
list.emplace_back(buf, range_rainbow_colors[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -446,8 +440,8 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
|
||||
items.reserve(tools_colors_count);
|
||||
for (unsigned int i = 0; i < tools_colors_count; ++i)
|
||||
{
|
||||
GCodePreviewData::Color color;
|
||||
::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
|
||||
Color color;
|
||||
::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
|
||||
items.emplace_back((boost::format(Slic3r::I18N::translate(L("Extruder %d"))) % (i + 1)).str(), color);
|
||||
}
|
||||
|
||||
@ -460,7 +454,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
|
||||
if (color_print_cnt == 1) // means "Default print color"
|
||||
{
|
||||
Color color;
|
||||
::memcpy((void*)color.rgba, (const void*)(tool_colors.data()), 4 * sizeof(float));
|
||||
::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data()), 4 * sizeof(float));
|
||||
|
||||
items.emplace_back(cp_items[0], color);
|
||||
break;
|
||||
@ -472,7 +466,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
|
||||
for (int i = 0 ; i < color_print_cnt; ++i)
|
||||
{
|
||||
Color color;
|
||||
::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
|
||||
::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
|
||||
|
||||
items.emplace_back(cp_items[i], color);
|
||||
}
|
||||
@ -502,20 +496,20 @@ const std::vector<std::string>& GCodePreviewData::ColorPrintColors()
|
||||
return color_print;
|
||||
}
|
||||
|
||||
GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2)
|
||||
Color operator + (const Color& c1, const Color& c2)
|
||||
{
|
||||
return GCodePreviewData::Color(clamp(0.0f, 1.0f, c1.rgba[0] + c2.rgba[0]),
|
||||
clamp(0.0f, 1.0f, c1.rgba[1] + c2.rgba[1]),
|
||||
clamp(0.0f, 1.0f, c1.rgba[2] + c2.rgba[2]),
|
||||
clamp(0.0f, 1.0f, c1.rgba[3] + c2.rgba[3]));
|
||||
return Color(std::clamp(c1.rgba[0] + c2.rgba[0], 0.0f, 1.0f),
|
||||
std::clamp(c1.rgba[1] + c2.rgba[1], 0.0f, 1.0f),
|
||||
std::clamp(c1.rgba[2] + c2.rgba[2], 0.0f, 1.0f),
|
||||
std::clamp(c1.rgba[3] + c2.rgba[3], 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
GCodePreviewData::Color operator * (float f, const GCodePreviewData::Color& color)
|
||||
Color operator * (float f, const Color& color)
|
||||
{
|
||||
return GCodePreviewData::Color(clamp(0.0f, 1.0f, f * color.rgba[0]),
|
||||
clamp(0.0f, 1.0f, f * color.rgba[1]),
|
||||
clamp(0.0f, 1.0f, f * color.rgba[2]),
|
||||
clamp(0.0f, 1.0f, f * color.rgba[3]));
|
||||
return Color(std::clamp(f * color.rgba[0], 0.0f, 1.0f),
|
||||
std::clamp(f * color.rgba[1], 0.0f, 1.0f),
|
||||
std::clamp(f * color.rgba[2], 0.0f, 1.0f),
|
||||
std::clamp(f * color.rgba[3], 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -5,43 +5,190 @@
|
||||
#include "../ExtrusionEntity.hpp"
|
||||
#include "../Point.hpp"
|
||||
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
#include <cstddef>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include <float.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Represents an RGBA color
|
||||
struct Color
|
||||
{
|
||||
std::array<float,4> rgba;
|
||||
|
||||
Color(const float *argba)
|
||||
{
|
||||
memcpy(this->rgba.data(), argba, sizeof(float) * 4);
|
||||
}
|
||||
constexpr Color(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f) : rgba{r,g,b,a}
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
std::vector<unsigned char> as_bytes() const;
|
||||
};
|
||||
Color operator + (const Color& c1, const Color& c2);
|
||||
Color operator * (float f, const Color& color);
|
||||
|
||||
// Default colors for Ranges
|
||||
constexpr std::array<Color, 10> range_rainbow_colors{
|
||||
Color{0.043f, 0.173f, 0.478f, 1.0f},
|
||||
Color{0.075f, 0.349f, 0.522f, 1.0f},
|
||||
Color{0.110f, 0.533f, 0.569f, 1.0f},
|
||||
Color{0.016f, 0.839f, 0.059f, 1.0f},
|
||||
Color{0.667f, 0.949f, 0.000f, 1.0f},
|
||||
Color{0.988f, 0.975f, 0.012f, 1.0f},
|
||||
Color{0.961f, 0.808f, 0.039f, 1.0f},
|
||||
Color{0.890f, 0.533f, 0.125f, 1.0f},
|
||||
Color{0.820f, 0.408f, 0.188f, 1.0f},
|
||||
Color{0.761f, 0.322f, 0.235f, 1.0f}};
|
||||
|
||||
class GCodePreviewData
|
||||
{
|
||||
public:
|
||||
struct Color
|
||||
|
||||
// Color mapping to convert a float into a smooth rainbow of 10 colors.
|
||||
class RangeBase
|
||||
{
|
||||
float rgba[4];
|
||||
public:
|
||||
|
||||
Color(const float *argba) { memcpy(this->rgba, argba, sizeof(float) * 4); }
|
||||
Color(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f) { rgba[0] = r; rgba[1] = g; rgba[2] = b; rgba[3] = a; }
|
||||
|
||||
std::vector<unsigned char> as_bytes() const;
|
||||
|
||||
static const Color Dummy;
|
||||
virtual void reset() = 0;
|
||||
virtual bool empty() const = 0;
|
||||
virtual float min() const = 0;
|
||||
virtual float max() const = 0;
|
||||
|
||||
// Gets the step size using min(), max() and colors
|
||||
float step_size() const;
|
||||
|
||||
// Gets the color at a value using colors, min(), and max()
|
||||
Color get_color_at(float value) const;
|
||||
};
|
||||
|
||||
// Color mapping from a <min, max> range into a smooth rainbow of 10 colors.
|
||||
struct Range
|
||||
|
||||
// Color mapping converting a float in a range between a min and a max into a smooth rainbow of 10 colors.
|
||||
class Range : public RangeBase
|
||||
{
|
||||
static const unsigned int Colors_Count = 10;
|
||||
static const Color Default_Colors[Colors_Count];
|
||||
|
||||
Color colors[Colors_Count];
|
||||
float min;
|
||||
float max;
|
||||
|
||||
public:
|
||||
Range();
|
||||
|
||||
void reset();
|
||||
bool empty() const;
|
||||
// RangeBase Overrides
|
||||
void reset() override;
|
||||
bool empty() const override;
|
||||
float min() const override;
|
||||
float max() const override;
|
||||
|
||||
// Range-specific methods
|
||||
void update_from(float value);
|
||||
void update_from(const Range& other);
|
||||
void set_from(const Range& other);
|
||||
float step_size() const;
|
||||
void update_from(const RangeBase& other);
|
||||
|
||||
Color get_color_at(float value) const;
|
||||
private:
|
||||
float min_val;
|
||||
float max_val;
|
||||
};
|
||||
|
||||
// Like Range, but stores multiple ranges internally that are used depending on mode.
|
||||
// Template param EnumRangeType must be an enum with values for each type of range that needs to be tracked in this MultiRange.
|
||||
// The last enum value should be num_values. The numerical values of all enum values should range from 0 to num_values.
|
||||
template <typename EnumRangeType>
|
||||
class MultiRange : public RangeBase
|
||||
{
|
||||
public:
|
||||
|
||||
void reset() override
|
||||
{
|
||||
bounds = decltype(bounds){};
|
||||
}
|
||||
|
||||
bool empty() const override
|
||||
{
|
||||
for (std::size_t i = 0; i < bounds.size(); ++i)
|
||||
{
|
||||
if (bounds[i].min != bounds[i].max)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
float min() const override
|
||||
{
|
||||
float min = FLT_MAX;
|
||||
for (std::size_t i = 0; i < bounds.size(); ++i)
|
||||
{
|
||||
// Only use bounds[i] if the current mode includes it
|
||||
if (mode.test(i))
|
||||
{
|
||||
min = std::min(min, bounds[i].min);
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
float max() const override
|
||||
{
|
||||
float max = -FLT_MAX;
|
||||
for (std::size_t i = 0; i < bounds.size(); ++i)
|
||||
{
|
||||
// Only use bounds[i] if the current mode includes it
|
||||
if (mode.test(i))
|
||||
{
|
||||
max = std::max(max, bounds[i].max);
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
void update_from(const float value, EnumRangeType range_type_value)
|
||||
{
|
||||
bounds[static_cast<std::size_t>(range_type_value)].update_from(value);
|
||||
}
|
||||
|
||||
void update_from(const MultiRange& other)
|
||||
{
|
||||
for (std::size_t i = 0; i < bounds.size(); ++i)
|
||||
{
|
||||
bounds[i].update_from(other.bounds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void set_mode(const EnumRangeType range_type_value, const bool enable)
|
||||
{
|
||||
mode.set(static_cast<std::size_t>(range_type_value), enable);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Interval bounds
|
||||
struct Bounds
|
||||
{
|
||||
float min{FLT_MAX};
|
||||
float max{-FLT_MAX};
|
||||
void update_from(const float value)
|
||||
{
|
||||
min = std::min(min, value);
|
||||
max = std::max(max, value);
|
||||
}
|
||||
void update_from(const Bounds other_bounds)
|
||||
{
|
||||
min = std::min(min, other_bounds.min);
|
||||
max = std::max(max, other_bounds.max);
|
||||
}
|
||||
};
|
||||
|
||||
std::array<Bounds, static_cast<std::size_t>(EnumRangeType::num_values)> bounds;
|
||||
std::bitset<static_cast<std::size_t>(EnumRangeType::num_values)> mode;
|
||||
};
|
||||
|
||||
// Enum distinguishing different kinds of feedrate data
|
||||
enum class FeedrateKind
|
||||
{
|
||||
EXTRUSION = 0, // values must go from 0 up to num_values
|
||||
TRAVEL,
|
||||
num_values //must be last in the list of values
|
||||
};
|
||||
|
||||
struct Ranges
|
||||
@ -51,7 +198,7 @@ public:
|
||||
// Color mapping by extrusion width.
|
||||
Range width;
|
||||
// Color mapping by feedrate.
|
||||
Range feedrate;
|
||||
MultiRange<FeedrateKind> feedrate;
|
||||
// Color mapping by fan speed.
|
||||
Range fan_speed;
|
||||
// Color mapping by volumetric extrusion rate.
|
||||
@ -245,9 +392,6 @@ public:
|
||||
static const std::vector<std::string>& ColorPrintColors();
|
||||
};
|
||||
|
||||
GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2);
|
||||
GCodePreviewData::Color operator * (float f, const GCodePreviewData::Color& color);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_GCode_PreviewData_hpp_ */
|
||||
|
@ -29,7 +29,7 @@ static inline BoundingBox extrusion_polyline_extents(const Polyline &polyline, c
|
||||
|
||||
static inline BoundingBoxf extrusionentity_extents(const ExtrusionPath &extrusion_path)
|
||||
{
|
||||
BoundingBox bbox = extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width));
|
||||
BoundingBox bbox = extrusion_polyline_extents(extrusion_path.polyline, coord_t(scale_(0.5 * extrusion_path.width)));
|
||||
BoundingBoxf bboxf;
|
||||
if (! empty(bbox)) {
|
||||
bboxf.min = unscale(bbox.min);
|
||||
@ -43,7 +43,7 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionLoop &extrusio
|
||||
{
|
||||
BoundingBox bbox;
|
||||
for (const ExtrusionPath &extrusion_path : extrusion_loop.paths)
|
||||
bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)));
|
||||
bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, coord_t(scale_(0.5 * extrusion_path.width))));
|
||||
BoundingBoxf bboxf;
|
||||
if (! empty(bbox)) {
|
||||
bboxf.min = unscale(bbox.min);
|
||||
@ -57,7 +57,7 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionMultiPath &ext
|
||||
{
|
||||
BoundingBox bbox;
|
||||
for (const ExtrusionPath &extrusion_path : extrusion_multi_path.paths)
|
||||
bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)));
|
||||
bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, coord_t(scale_(0.5 * extrusion_path.width))));
|
||||
BoundingBoxf bboxf;
|
||||
if (! empty(bbox)) {
|
||||
bboxf.min = unscale(bbox.min);
|
||||
|
@ -13,13 +13,17 @@
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
#include <libslic3r.h>
|
||||
|
||||
#include "../GCodeWriter.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
||||
// Returns true in case that extruder a comes before b (b does not have to be present). False otherwise.
|
||||
bool LayerTools::is_extruder_order(unsigned int a, unsigned int b) const
|
||||
{
|
||||
if (a==b)
|
||||
if (a == b)
|
||||
return false;
|
||||
|
||||
for (auto extruder : extruders) {
|
||||
@ -32,6 +36,39 @@ bool LayerTools::is_extruder_order(unsigned int a, unsigned int b) const
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return a zero based extruder from the region, or extruder_override if overriden.
|
||||
unsigned int LayerTools::perimeter_extruder(const PrintRegion ®ion) const
|
||||
{
|
||||
assert(region.config().perimeter_extruder.value > 0);
|
||||
return ((this->extruder_override == 0) ? region.config().perimeter_extruder.value : this->extruder_override) - 1;
|
||||
}
|
||||
|
||||
unsigned int LayerTools::infill_extruder(const PrintRegion ®ion) const
|
||||
{
|
||||
assert(region.config().infill_extruder.value > 0);
|
||||
return ((this->extruder_override == 0) ? region.config().infill_extruder.value : this->extruder_override) - 1;
|
||||
}
|
||||
|
||||
unsigned int LayerTools::solid_infill_extruder(const PrintRegion ®ion) const
|
||||
{
|
||||
assert(region.config().solid_infill_extruder.value > 0);
|
||||
return ((this->extruder_override == 0) ? region.config().solid_infill_extruder.value : this->extruder_override) - 1;
|
||||
}
|
||||
|
||||
// Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden.
|
||||
unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, const PrintRegion ®ion) const
|
||||
{
|
||||
assert(region.config().perimeter_extruder.value > 0);
|
||||
assert(region.config().infill_extruder.value > 0);
|
||||
assert(region.config().solid_infill_extruder.value > 0);
|
||||
// 1 based extruder ID.
|
||||
unsigned int extruder = ((this->extruder_override == 0) ?
|
||||
(is_infill(extrusions.role()) ?
|
||||
(is_solid_infill(extrusions.entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) :
|
||||
region.config().perimeter_extruder.value) :
|
||||
this->extruder_override);
|
||||
return (extruder == 0) ? 0 : extruder - 1;
|
||||
}
|
||||
|
||||
// For the use case when each object is printed separately
|
||||
// (print.config().complete_objects is true).
|
||||
@ -52,7 +89,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
|
||||
}
|
||||
|
||||
// Collect extruders reuqired to print the layers.
|
||||
this->collect_extruders(object);
|
||||
this->collect_extruders(object, std::vector<std::pair<double, unsigned int>>());
|
||||
|
||||
// Reorder the extruders to minimize tool switches.
|
||||
this->reorder_extruders(first_extruder);
|
||||
@ -89,9 +126,19 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
|
||||
this->initialize_layers(zs);
|
||||
}
|
||||
|
||||
// Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object.
|
||||
// Do it only if all the objects were configured to be printed with a single extruder.
|
||||
std::vector<std::pair<double, unsigned int>> per_layer_extruder_switches;
|
||||
if (auto num_extruders = unsigned(print.config().nozzle_diameter.size());
|
||||
num_extruders > 1 && print.object_extruders().size() == 1) {
|
||||
// Printing a single extruder platter on a printer with more than 1 extruder (or single-extruder multi-material).
|
||||
// There may be custom per-layer tool changes available at the model.
|
||||
per_layer_extruder_switches = custom_tool_changes(print.model(), num_extruders);
|
||||
}
|
||||
|
||||
// Collect extruders reuqired to print the layers.
|
||||
for (auto object : print.objects())
|
||||
this->collect_extruders(*object);
|
||||
this->collect_extruders(*object, per_layer_extruder_switches);
|
||||
|
||||
// Reorder the extruders to minimize tool switches.
|
||||
this->reorder_extruders(first_extruder);
|
||||
@ -111,13 +158,13 @@ void ToolOrdering::initialize_layers(std::vector<coordf_t> &zs)
|
||||
coordf_t zmax = zs[i] + EPSILON;
|
||||
for (; j < zs.size() && zs[j] <= zmax; ++ j) ;
|
||||
// Assign an average print_z to the set of layers with nearly equal print_z.
|
||||
m_layer_tools.emplace_back(LayerTools(0.5 * (zs[i] + zs[j-1]), m_print_config_ptr));
|
||||
m_layer_tools.emplace_back(LayerTools(0.5 * (zs[i] + zs[j-1])));
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect extruders reuqired to print layers.
|
||||
void ToolOrdering::collect_extruders(const PrintObject &object)
|
||||
void ToolOrdering::collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches)
|
||||
{
|
||||
// Collect the support extruders.
|
||||
for (auto support_layer : object.support_layers()) {
|
||||
@ -134,9 +181,23 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
|
||||
if (has_support || has_interface)
|
||||
layer_tools.has_support = true;
|
||||
}
|
||||
|
||||
// Extruder overrides are ordered by print_z.
|
||||
std::vector<std::pair<double, unsigned int>>::const_iterator it_per_layer_extruder_override;
|
||||
it_per_layer_extruder_override = per_layer_extruder_switches.begin();
|
||||
unsigned int extruder_override = 0;
|
||||
|
||||
// Collect the object extruders.
|
||||
for (auto layer : object.layers()) {
|
||||
LayerTools &layer_tools = this->tools_for_layer(layer->print_z);
|
||||
|
||||
// Override extruder with the next
|
||||
for (; it_per_layer_extruder_override != per_layer_extruder_switches.end() && it_per_layer_extruder_override->first < layer->print_z + EPSILON; ++ it_per_layer_extruder_override)
|
||||
extruder_override = (int)it_per_layer_extruder_override->second;
|
||||
|
||||
// Store the current extruder override (set to zero if no overriden), so that layer_tools.wiping_extrusions().is_overridable_and_mark() will use it.
|
||||
layer_tools.extruder_override = extruder_override;
|
||||
|
||||
// What extruders are required to print this object layer?
|
||||
for (size_t region_id = 0; region_id < object.region_volumes.size(); ++ region_id) {
|
||||
const LayerRegion *layerm = (region_id < layer->regions().size()) ? layer->regions()[region_id] : nullptr;
|
||||
@ -150,19 +211,18 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
|
||||
if (m_print_config_ptr) { // in this case complete_objects is false (see ToolOrdering constructors)
|
||||
something_nonoverriddable = false;
|
||||
for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities
|
||||
if (!layer_tools.wiping_extrusions().is_overriddable(dynamic_cast<const ExtrusionEntityCollection&>(*eec), *m_print_config_ptr, object, region)) {
|
||||
if (!layer_tools.wiping_extrusions().is_overriddable_and_mark(dynamic_cast<const ExtrusionEntityCollection&>(*eec), *m_print_config_ptr, object, region)) {
|
||||
something_nonoverriddable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (something_nonoverriddable)
|
||||
layer_tools.extruders.push_back(region.config().perimeter_extruder.value);
|
||||
layer_tools.extruders.emplace_back((extruder_override == 0) ? region.config().perimeter_extruder.value : extruder_override);
|
||||
|
||||
layer_tools.has_object = true;
|
||||
}
|
||||
|
||||
|
||||
bool has_infill = false;
|
||||
bool has_solid_infill = false;
|
||||
bool something_nonoverriddable = false;
|
||||
@ -176,17 +236,19 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
|
||||
has_infill = true;
|
||||
|
||||
if (m_print_config_ptr) {
|
||||
if (!something_nonoverriddable && !layer_tools.wiping_extrusions().is_overriddable(*fill, *m_print_config_ptr, object, region))
|
||||
if (!something_nonoverriddable && !layer_tools.wiping_extrusions().is_overriddable_and_mark(*fill, *m_print_config_ptr, object, region))
|
||||
something_nonoverriddable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (something_nonoverriddable || !m_print_config_ptr)
|
||||
{
|
||||
if (has_solid_infill)
|
||||
layer_tools.extruders.push_back(region.config().solid_infill_extruder);
|
||||
if (has_infill)
|
||||
layer_tools.extruders.push_back(region.config().infill_extruder);
|
||||
if (something_nonoverriddable || !m_print_config_ptr) {
|
||||
if (extruder_override == 0) {
|
||||
if (has_solid_infill)
|
||||
layer_tools.extruders.emplace_back(region.config().solid_infill_extruder);
|
||||
if (has_infill)
|
||||
layer_tools.extruders.emplace_back(region.config().infill_extruder);
|
||||
} else if (has_solid_infill || has_infill)
|
||||
layer_tools.extruders.emplace_back(extruder_override);
|
||||
}
|
||||
if (has_solid_infill || has_infill)
|
||||
layer_tools.has_object = true;
|
||||
@ -199,7 +261,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
|
||||
|
||||
// make sure that there are some tools for each object layer (e.g. tall wiping object will result in empty extruders vector)
|
||||
if (layer.extruders.empty() && layer.has_object)
|
||||
layer.extruders.push_back(0); // 0="dontcare" extruder - it will be taken care of in reorder_extruders
|
||||
layer.extruders.emplace_back(0); // 0="dontcare" extruder - it will be taken care of in reorder_extruders
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,11 +316,9 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
|
||||
for (unsigned int &extruder_id : lt.extruders) {
|
||||
assert(extruder_id > 0);
|
||||
-- extruder_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z)
|
||||
{
|
||||
if (m_layer_tools.empty())
|
||||
@ -394,17 +454,76 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material)
|
||||
}
|
||||
}
|
||||
|
||||
// Assign a pointer to a custom G-code to the respective ToolOrdering::LayerTools.
|
||||
// Ignore color changes, which are performed on a layer and for such an extruder, that the extruder will not be printing above that layer.
|
||||
// If multiple events are planned over a span of a single layer, use the last one.
|
||||
void ToolOrdering::assign_custom_gcodes(const Print &print)
|
||||
{
|
||||
// Only valid for non-sequential print.
|
||||
assert(! print.config().complete_objects.value);
|
||||
|
||||
const Model::CustomGCodeInfo &custom_gcode_per_print_z = print.model().custom_gcode_per_print_z;
|
||||
if (custom_gcode_per_print_z.gcodes.empty())
|
||||
return;
|
||||
|
||||
unsigned int num_extruders = *std::max_element(m_all_printing_extruders.begin(), m_all_printing_extruders.end()) + 1;
|
||||
std::vector<unsigned char> extruder_printing_above(num_extruders, false);
|
||||
auto custom_gcode_it = custom_gcode_per_print_z.gcodes.rbegin();
|
||||
// If printing on a single extruder machine, make the tool changes trigger color change (M600) events.
|
||||
bool tool_changes_as_color_changes = num_extruders == 1;
|
||||
// From the last layer to the first one:
|
||||
for (auto it_lt = m_layer_tools.rbegin(); it_lt != m_layer_tools.rend(); ++ it_lt) {
|
||||
LayerTools < = *it_lt;
|
||||
// Add the extruders of the current layer to the set of extruders printing at and above this print_z.
|
||||
for (unsigned int i : lt.extruders)
|
||||
extruder_printing_above[i] = true;
|
||||
// Skip all custom G-codes above this layer and skip all extruder switches.
|
||||
for (; custom_gcode_it != custom_gcode_per_print_z.gcodes.rend() && (custom_gcode_it->print_z > lt.print_z + EPSILON || custom_gcode_it->gcode == ToolChangeCode); ++ custom_gcode_it);
|
||||
if (custom_gcode_it == custom_gcode_per_print_z.gcodes.rend())
|
||||
// Custom G-codes were processed.
|
||||
break;
|
||||
// Some custom G-code is configured for this layer or a layer below.
|
||||
const Model::CustomGCode &custom_gcode = *custom_gcode_it;
|
||||
// print_z of the layer below the current layer.
|
||||
coordf_t print_z_below = 0.;
|
||||
if (auto it_lt_below = it_lt; ++ it_lt_below != m_layer_tools.rend())
|
||||
print_z_below = it_lt_below->print_z;
|
||||
if (custom_gcode.print_z > print_z_below + 0.5 * EPSILON) {
|
||||
// The custom G-code applies to the current layer.
|
||||
if ( tool_changes_as_color_changes || custom_gcode.gcode != ColorChangeCode ||
|
||||
(custom_gcode.extruder <= num_extruders && extruder_printing_above[unsigned(custom_gcode.extruder - 1)]))
|
||||
// If it is color change, it will actually be useful as the exturder above will print.
|
||||
lt.custom_gcode = &custom_gcode;
|
||||
// Consume that custom G-code event.
|
||||
++ custom_gcode_it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) const
|
||||
{
|
||||
auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), LayerTools(print_z - EPSILON));
|
||||
assert(it_layer_tools != m_layer_tools.end());
|
||||
coordf_t dist_min = std::abs(it_layer_tools->print_z - print_z);
|
||||
for (++ it_layer_tools; it_layer_tools != m_layer_tools.end(); ++ it_layer_tools) {
|
||||
coordf_t d = std::abs(it_layer_tools->print_z - print_z);
|
||||
if (d >= dist_min)
|
||||
break;
|
||||
dist_min = d;
|
||||
}
|
||||
-- it_layer_tools;
|
||||
assert(dist_min < EPSILON);
|
||||
return *it_layer_tools;
|
||||
}
|
||||
|
||||
// This function is called from Print::mark_wiping_extrusions and sets extruder this entity should be printed with (-1 .. as usual)
|
||||
void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies)
|
||||
void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, size_t copy_id, int extruder, size_t num_of_copies)
|
||||
{
|
||||
something_overridden = true;
|
||||
|
||||
auto entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector<int>()))).first; // (add and) return iterator
|
||||
auto& copies_vector = entity_map_it->second;
|
||||
if (copies_vector.size() < num_of_copies)
|
||||
copies_vector.resize(num_of_copies, -1);
|
||||
auto entity_map_it = (entity_map.emplace(entity, ExtruderPerCopy())).first; // (add and) return iterator
|
||||
ExtruderPerCopy& copies_vector = entity_map_it->second;
|
||||
copies_vector.resize(num_of_copies, -1);
|
||||
|
||||
if (copies_vector[copy_id] != -1)
|
||||
std::cout << "ERROR: Entity extruder overriden multiple times!!!\n"; // A debugging message - this must never happen.
|
||||
@ -412,7 +531,6 @@ void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsi
|
||||
copies_vector[copy_id] = extruder;
|
||||
}
|
||||
|
||||
|
||||
// Finds first non-soluble extruder on the layer
|
||||
int WipingExtrusions::first_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const
|
||||
{
|
||||
@ -435,11 +553,10 @@ int WipingExtrusions::last_nonsoluble_extruder_on_layer(const PrintConfig& print
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
// Decides whether this entity could be overridden
|
||||
bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const
|
||||
{
|
||||
if (print_config.filament_soluble.get_at(Print::get_extruder(eec, region)))
|
||||
if (print_config.filament_soluble.get_at(m_layer_tools->extruder(eec, region)))
|
||||
return false;
|
||||
|
||||
if (object.config().wipe_into_objects)
|
||||
@ -451,7 +568,6 @@ bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, con
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange
|
||||
// and returns volume that is left to be wiped on the wipe tower.
|
||||
float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe)
|
||||
@ -459,8 +575,8 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
||||
const LayerTools& lt = *m_layer_tools;
|
||||
const float min_infill_volume = 0.f; // ignore infill with smaller volume than this
|
||||
|
||||
if (print.config().filament_soluble.get_at(old_extruder) || print.config().filament_soluble.get_at(new_extruder))
|
||||
return volume_to_wipe; // Soluble filament cannot be wiped in a random infill, neither the filament after it
|
||||
if (! this->something_overridable || volume_to_wipe <= 0. || print.config().filament_soluble.get_at(old_extruder) || print.config().filament_soluble.get_at(new_extruder))
|
||||
return std::max(0.f, volume_to_wipe); // Soluble filament cannot be wiped in a random infill, neither the filament after it
|
||||
|
||||
// we will sort objects so that dedicated for wiping are at the beginning:
|
||||
PrintObjectPtrs object_list = print.objects();
|
||||
@ -483,13 +599,13 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
||||
const PrintObject* object = object_list[i];
|
||||
|
||||
// Finds this layer:
|
||||
auto this_layer_it = std::find_if(object->layers().begin(), object->layers().end(), [<](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)<EPSILON; });
|
||||
if (this_layer_it == object->layers().end())
|
||||
continue;
|
||||
const Layer* this_layer = *this_layer_it;
|
||||
const Layer* this_layer = object->get_layer_at_printz(lt.print_z, EPSILON);
|
||||
if (this_layer == nullptr)
|
||||
continue;
|
||||
size_t num_of_copies = object->copies().size();
|
||||
|
||||
for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
|
||||
// iterate through copies (aka PrintObject instances) first, so that we mark neighbouring infills to minimize travel moves
|
||||
for (unsigned int copy = 0; copy < num_of_copies; ++copy) {
|
||||
|
||||
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) {
|
||||
const auto& region = *object->print()->regions()[region_id];
|
||||
@ -497,51 +613,48 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
||||
if (!region.config().wipe_into_infill && !object->config().wipe_into_objects)
|
||||
continue;
|
||||
|
||||
|
||||
if ((!print.config().infill_first ? perimeters_done : !perimeters_done) || (!object->config().wipe_into_objects && region.config().wipe_into_infill)) {
|
||||
bool wipe_into_infill_only = ! object->config().wipe_into_objects && region.config().wipe_into_infill;
|
||||
if (print.config().infill_first != perimeters_done || wipe_into_infill_only) {
|
||||
for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->fills.entities) { // iterate through all infill Collections
|
||||
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
||||
|
||||
if (!is_overriddable(*fill, print.config(), *object, region))
|
||||
continue;
|
||||
|
||||
if (volume_to_wipe<=0)
|
||||
continue;
|
||||
|
||||
if (!object->config().wipe_into_objects && !print.config().infill_first && region.config().wipe_into_infill)
|
||||
if (wipe_into_infill_only && ! print.config().infill_first)
|
||||
// In this case we must check that the original extruder is used on this layer before the one we are overridding
|
||||
// (and the perimeters will be finished before the infill is printed):
|
||||
if (!lt.is_extruder_order(region.config().perimeter_extruder - 1, new_extruder))
|
||||
if (!lt.is_extruder_order(lt.perimeter_extruder(region), new_extruder))
|
||||
continue;
|
||||
|
||||
if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { // this infill will be used to wipe this extruder
|
||||
set_extruder_override(fill, copy, new_extruder, num_of_copies);
|
||||
volume_to_wipe -= float(fill->total_volume());
|
||||
if ((volume_to_wipe -= float(fill->total_volume())) <= 0.f)
|
||||
// More material was purged already than asked for.
|
||||
return 0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now the same for perimeters - see comments above for explanation:
|
||||
if (object->config().wipe_into_objects && (print.config().infill_first ? perimeters_done : !perimeters_done))
|
||||
if (object->config().wipe_into_objects && print.config().infill_first == perimeters_done)
|
||||
{
|
||||
for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->perimeters.entities) {
|
||||
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
||||
if (!is_overriddable(*fill, print.config(), *object, region))
|
||||
continue;
|
||||
|
||||
if (volume_to_wipe<=0)
|
||||
continue;
|
||||
|
||||
if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) {
|
||||
if (is_overriddable(*fill, print.config(), *object, region) && !is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) {
|
||||
set_extruder_override(fill, copy, new_extruder, num_of_copies);
|
||||
volume_to_wipe -= float(fill->total_volume());
|
||||
if ((volume_to_wipe -= float(fill->total_volume())) <= 0.f)
|
||||
// More material was purged already than asked for.
|
||||
return 0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::max(0.f, volume_to_wipe);
|
||||
// Some purge remains to be done on the Wipe Tower.
|
||||
assert(volume_to_wipe > 0.);
|
||||
return volume_to_wipe;
|
||||
}
|
||||
|
||||
|
||||
@ -552,16 +665,18 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
||||
// them again and make sure we override it.
|
||||
void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
|
||||
{
|
||||
if (! this->something_overridable)
|
||||
return;
|
||||
|
||||
const LayerTools& lt = *m_layer_tools;
|
||||
unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config());
|
||||
unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config());
|
||||
|
||||
for (const PrintObject* object : print.objects()) {
|
||||
// Finds this layer:
|
||||
auto this_layer_it = std::find_if(object->layers().begin(), object->layers().end(), [<](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)<EPSILON; });
|
||||
if (this_layer_it == object->layers().end())
|
||||
continue;
|
||||
const Layer* this_layer = *this_layer_it;
|
||||
const Layer* this_layer = object->get_layer_at_printz(lt.print_z, EPSILON);
|
||||
if (this_layer == nullptr)
|
||||
continue;
|
||||
size_t num_of_copies = object->copies().size();
|
||||
|
||||
for (size_t copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
|
||||
@ -584,9 +699,8 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
|
||||
// Either way, we will now force-override it with something suitable:
|
||||
if (print.config().infill_first
|
||||
|| object->config().wipe_into_objects // in this case the perimeter is overridden, so we can override by the last one safely
|
||||
|| lt.is_extruder_order(region.config().perimeter_extruder - 1, last_nonsoluble_extruder // !infill_first, but perimeter is already printed when last extruder prints
|
||||
|| std::find(lt.extruders.begin(), lt.extruders.end(), region.config().infill_extruder - 1) == lt.extruders.end()) // we have to force override - this could violate infill_first (FIXME)
|
||||
)
|
||||
|| lt.is_extruder_order(lt.perimeter_extruder(region), last_nonsoluble_extruder // !infill_first, but perimeter is already printed when last extruder prints
|
||||
|| ! lt.has_extruder(lt.infill_extruder(region)))) // we have to force override - this could violate infill_first (FIXME)
|
||||
set_extruder_override(fill, copy, (print.config().infill_first ? first_nonsoluble_extruder : last_nonsoluble_extruder), num_of_copies);
|
||||
else {
|
||||
// In this case we can (and should) leave it to be printed normally.
|
||||
@ -597,42 +711,31 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
|
||||
// Now the same for perimeters - see comments above for explanation:
|
||||
for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->perimeters.entities) { // iterate through all perimeter Collections
|
||||
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
||||
if (!is_overriddable(*fill, print.config(), *object, region)
|
||||
|| is_entity_overridden(fill, copy) )
|
||||
continue;
|
||||
|
||||
set_extruder_override(fill, copy, (print.config().infill_first ? last_nonsoluble_extruder : first_nonsoluble_extruder), num_of_copies);
|
||||
if (is_overriddable(*fill, print.config(), *object, region) && ! is_entity_overridden(fill, copy))
|
||||
set_extruder_override(fill, copy, (print.config().infill_first ? last_nonsoluble_extruder : first_nonsoluble_extruder), num_of_copies);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Following function is called from process_layer and returns pointer to vector with information about which extruders should be used for given copy of this entity.
|
||||
// It first makes sure the pointer is valid (creates the vector if it does not exist) and contains a record for each copy
|
||||
// It also modifies the vector in place and changes all -1 to correct_extruder_id (at the time the overrides were created, correct extruders were not known,
|
||||
// so -1 was used as "print as usual".
|
||||
// The resulting vector has to keep track of which extrusions are the ones that were overridden and which were not. In the extruder is used as overridden,
|
||||
// its number is saved as it is (zero-based index). Usual extrusions are saved as -number-1 (unfortunately there is no negative zero).
|
||||
const std::vector<int>* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies)
|
||||
// Following function is called from GCode::process_layer and returns pointer to vector with information about which extruders should be used for given copy of this entity.
|
||||
// If this extrusion does not have any override, nullptr is returned.
|
||||
// Otherwise it modifies the vector in place and changes all -1 to correct_extruder_id (at the time the overrides were created, correct extruders were not known,
|
||||
// so -1 was used as "print as usual").
|
||||
// The resulting vector therefore keeps track of which extrusions are the ones that were overridden and which were not. If the extruder used is overridden,
|
||||
// its number is saved as is (zero-based index). Regular extrusions are saved as -number-1 (unfortunately there is no negative zero).
|
||||
const WipingExtrusions::ExtruderPerCopy* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies)
|
||||
{
|
||||
ExtruderPerCopy *overrides = nullptr;
|
||||
auto entity_map_it = entity_map.find(entity);
|
||||
if (entity_map_it == entity_map.end())
|
||||
entity_map_it = (entity_map.insert(std::make_pair(entity, std::vector<int>()))).first;
|
||||
|
||||
// Now the entity_map_it should be valid, let's make sure the vector is long enough:
|
||||
entity_map_it->second.resize(num_of_copies, -1);
|
||||
|
||||
// Each -1 now means "print as usual" - we will replace it with actual extruder id (shifted it so we don't lose that information):
|
||||
std::replace(entity_map_it->second.begin(), entity_map_it->second.end(), -1, -correct_extruder_id-1);
|
||||
|
||||
return &(entity_map_it->second);
|
||||
if (entity_map_it != entity_map.end()) {
|
||||
overrides = &entity_map_it->second;
|
||||
overrides->resize(num_of_copies, -1);
|
||||
// Each -1 now means "print as usual" - we will replace it with actual extruder id (shifted it so we don't lose that information):
|
||||
std::replace(overrides->begin(), overrides->end(), -1, -correct_extruder_id-1);
|
||||
}
|
||||
return overrides;
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,6 +5,10 @@
|
||||
|
||||
#include "../libslic3r.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Print;
|
||||
@ -23,8 +27,19 @@ public:
|
||||
return something_overridden;
|
||||
}
|
||||
|
||||
// When allocating extruder overrides of an object's ExtrusionEntity, overrides for maximum 3 copies are allocated in place.
|
||||
typedef boost::container::small_vector<int32_t, 3> ExtruderPerCopy;
|
||||
|
||||
class ExtruderOverrides
|
||||
{
|
||||
public:
|
||||
ExtruderOverrides(const ExtruderPerCopy *overrides, const int correct_extruder_id) : m_overrides(overrides) {}
|
||||
private:
|
||||
const ExtruderPerCopy *m_overrides;
|
||||
};
|
||||
|
||||
// This is called from GCode::process_layer - see implementation for further comments:
|
||||
const std::vector<int>* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies);
|
||||
const ExtruderPerCopy* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies);
|
||||
|
||||
// This function goes through all infill entities, decides which ones will be used for wiping and
|
||||
// marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower:
|
||||
@ -33,6 +48,11 @@ public:
|
||||
void ensure_perimeters_infills_order(const Print& print);
|
||||
|
||||
bool is_overriddable(const ExtrusionEntityCollection& ee, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const;
|
||||
bool is_overriddable_and_mark(const ExtrusionEntityCollection& ee, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) {
|
||||
bool out = this->is_overriddable(ee, print_config, object, region);
|
||||
this->something_overridable |= out;
|
||||
return out;
|
||||
}
|
||||
|
||||
void set_layer_tools_ptr(const LayerTools* lt) { m_layer_tools = lt; }
|
||||
|
||||
@ -41,14 +61,16 @@ private:
|
||||
int last_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const;
|
||||
|
||||
// This function is called from mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual)
|
||||
void set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies);
|
||||
void set_extruder_override(const ExtrusionEntity* entity, size_t copy_id, int extruder, size_t num_of_copies);
|
||||
|
||||
// Returns true in case that entity is not printed with its usual extruder for a given copy:
|
||||
bool is_entity_overridden(const ExtrusionEntity* entity, size_t copy_id) const {
|
||||
return (entity_map.find(entity) == entity_map.end() ? false : entity_map.at(entity).at(copy_id) != -1);
|
||||
auto it = entity_map.find(entity);
|
||||
return it == entity_map.end() ? false : it->second[copy_id] != -1;
|
||||
}
|
||||
|
||||
std::map<const ExtrusionEntity*, std::vector<int>> entity_map; // to keep track of who prints what
|
||||
std::map<const ExtrusionEntity*, ExtruderPerCopy> entity_map; // to keep track of who prints what
|
||||
bool something_overridable = false;
|
||||
bool something_overridden = false;
|
||||
const LayerTools* m_layer_tools; // so we know which LayerTools object this belongs to
|
||||
};
|
||||
@ -58,13 +80,7 @@ private:
|
||||
class LayerTools
|
||||
{
|
||||
public:
|
||||
LayerTools(const coordf_t z, const PrintConfig* print_config_ptr = nullptr) :
|
||||
print_z(z),
|
||||
has_object(false),
|
||||
has_support(false),
|
||||
has_wipe_tower(false),
|
||||
wipe_tower_partitions(0),
|
||||
wipe_tower_layer_height(0.) {}
|
||||
LayerTools(const coordf_t z) : print_z(z) {}
|
||||
|
||||
// Changing these operators to epsilon version can make a problem in cases where support and object layers get close to each other.
|
||||
// In case someone tries to do it, make sure you know what you're doing and test it properly (slice multiple objects at once with supports).
|
||||
@ -72,20 +88,33 @@ public:
|
||||
bool operator==(const LayerTools &rhs) const { return print_z == rhs.print_z; }
|
||||
|
||||
bool is_extruder_order(unsigned int a, unsigned int b) const;
|
||||
bool has_extruder(unsigned int extruder) const { return std::find(this->extruders.begin(), this->extruders.end(), extruder) != this->extruders.end(); }
|
||||
|
||||
coordf_t print_z;
|
||||
bool has_object;
|
||||
bool has_support;
|
||||
// Return a zero based extruder from the region, or extruder_override if overriden.
|
||||
unsigned int perimeter_extruder(const PrintRegion ®ion) const;
|
||||
unsigned int infill_extruder(const PrintRegion ®ion) const;
|
||||
unsigned int solid_infill_extruder(const PrintRegion ®ion) const;
|
||||
// Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden.
|
||||
unsigned int extruder(const ExtrusionEntityCollection &extrusions, const PrintRegion ®ion) const;
|
||||
|
||||
coordf_t print_z = 0.;
|
||||
bool has_object = false;
|
||||
bool has_support = false;
|
||||
// Zero based extruder IDs, ordered to minimize tool switches.
|
||||
std::vector<unsigned int> extruders;
|
||||
// If per layer extruder switches are inserted by the G-code preview slider, this value contains the new (1 based) extruder, with which the whole object layer is being printed with.
|
||||
// If not overriden, it is set to 0.
|
||||
unsigned int extruder_override = 0;
|
||||
// Will there be anything extruded on this layer for the wipe tower?
|
||||
// Due to the support layers possibly interleaving the object layers,
|
||||
// wipe tower will be disabled for some support only layers.
|
||||
bool has_wipe_tower;
|
||||
bool has_wipe_tower = false;
|
||||
// Number of wipe tower partitions to support the required number of tool switches
|
||||
// and to support the wipe tower partitions above this one.
|
||||
size_t wipe_tower_partitions;
|
||||
coordf_t wipe_tower_layer_height;
|
||||
size_t wipe_tower_partitions = 0;
|
||||
coordf_t wipe_tower_layer_height = 0.;
|
||||
// Custom G-code (color change, extruder switch, pause) to be performed before this layer starts to print.
|
||||
const Model::CustomGCode *custom_gcode = nullptr;
|
||||
|
||||
WipingExtrusions& wiping_extrusions() {
|
||||
m_wiping_extrusions.set_layer_tools_ptr(this);
|
||||
@ -106,14 +135,20 @@ public:
|
||||
|
||||
// For the use case when each object is printed separately
|
||||
// (print.config.complete_objects is true).
|
||||
ToolOrdering(const PrintObject &object, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false);
|
||||
ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material = false);
|
||||
|
||||
// For the use case when all objects are printed at once.
|
||||
// (print.config.complete_objects is false).
|
||||
ToolOrdering(const Print &print, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false);
|
||||
ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material = false);
|
||||
|
||||
void clear() { m_layer_tools.clear(); }
|
||||
|
||||
// Only valid for non-sequential print:
|
||||
// Assign a pointer to a custom G-code to the respective ToolOrdering::LayerTools.
|
||||
// Ignore color changes, which are performed on a layer and for such an extruder, that the extruder will not be printing above that layer.
|
||||
// If multiple events are planned over a span of a single layer, use the last one.
|
||||
void assign_custom_gcodes(const Print &print);
|
||||
|
||||
// Get the first extruder printing, including the extruder priming areas, returns -1 if there is no layer printed.
|
||||
unsigned int first_extruder() const { return m_first_printing_extruder; }
|
||||
|
||||
@ -123,25 +158,9 @@ public:
|
||||
// For a multi-material print, the printing extruders are ordered in the order they shall be primed.
|
||||
const std::vector<unsigned int>& all_extruders() const { return m_all_printing_extruders; }
|
||||
|
||||
template<class Self> static auto tools_for_layer(Self& self, coordf_t print_z) -> decltype (*self.m_layer_tools.begin())
|
||||
{
|
||||
auto it_layer_tools = std::lower_bound(self.m_layer_tools.begin(), self.m_layer_tools.end(), LayerTools(print_z - EPSILON));
|
||||
assert(it_layer_tools != self.m_layer_tools.end());
|
||||
coordf_t dist_min = std::abs(it_layer_tools->print_z - print_z);
|
||||
for (++ it_layer_tools; it_layer_tools != self.m_layer_tools.end(); ++it_layer_tools) {
|
||||
coordf_t d = std::abs(it_layer_tools->print_z - print_z);
|
||||
if (d >= dist_min)
|
||||
break;
|
||||
dist_min = d;
|
||||
}
|
||||
-- it_layer_tools;
|
||||
assert(dist_min < EPSILON);
|
||||
return *it_layer_tools;
|
||||
}
|
||||
|
||||
// Find LayerTools with the closest print_z.
|
||||
LayerTools& tools_for_layer(coordf_t print_z) { return tools_for_layer(*this, print_z); }
|
||||
const LayerTools& tools_for_layer(coordf_t print_z) const { return tools_for_layer(*this, print_z); }
|
||||
const LayerTools& tools_for_layer(coordf_t print_z) const;
|
||||
LayerTools& tools_for_layer(coordf_t print_z) { return const_cast<LayerTools&>(std::as_const(*this).tools_for_layer(print_z)); }
|
||||
|
||||
const LayerTools& front() const { return m_layer_tools.front(); }
|
||||
const LayerTools& back() const { return m_layer_tools.back(); }
|
||||
@ -153,7 +172,7 @@ public:
|
||||
|
||||
private:
|
||||
void initialize_layers(std::vector<coordf_t> &zs);
|
||||
void collect_extruders(const PrintObject &object);
|
||||
void collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches);
|
||||
void reorder_extruders(unsigned int last_extruder_id);
|
||||
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z);
|
||||
void collect_extruder_statistics(bool prime_multi_material);
|
||||
@ -166,7 +185,6 @@ private:
|
||||
// All extruders, which extrude some material over m_layer_tools.
|
||||
std::vector<unsigned int> m_all_printing_extruders;
|
||||
|
||||
|
||||
const PrintConfig* m_print_config_ptr = nullptr;
|
||||
};
|
||||
|
||||
|
@ -1261,7 +1261,9 @@ namespace Slic3r {
|
||||
|
||||
if (line.has_e())
|
||||
{
|
||||
set_axis_origin(E, get_axis_position(E) - line.e() * lengthsScaleFactor);
|
||||
// extruder coordinate can grow to the point where its float representation does not allow for proper addition with small increments,
|
||||
// we set the value taken from the G92 line as the new current position for it
|
||||
set_axis_position(E, line.e() * lengthsScaleFactor);
|
||||
anyFound = true;
|
||||
}
|
||||
else
|
||||
|
@ -19,12 +19,13 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|
||||
this->config.apply(print_config, true);
|
||||
m_extrusion_axis = this->config.get_extrusion_axis();
|
||||
m_single_extruder_multi_material = print_config.single_extruder_multi_material.value;
|
||||
m_max_acceleration = (print_config.gcode_flavor.value == gcfMarlin) ?
|
||||
print_config.machine_max_acceleration_extruding.values.front() : 0;
|
||||
m_max_acceleration = std::lrint((print_config.gcode_flavor.value == gcfMarlin) ?
|
||||
print_config.machine_max_acceleration_extruding.values.front() : 0);
|
||||
}
|
||||
|
||||
void GCodeWriter::set_extruders(const std::vector<unsigned int> &extruder_ids)
|
||||
void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids)
|
||||
{
|
||||
std::sort(extruder_ids.begin(), extruder_ids.end());
|
||||
m_extruders.clear();
|
||||
m_extruders.reserve(extruder_ids.size());
|
||||
for (unsigned int extruder_id : extruder_ids)
|
||||
@ -247,9 +248,9 @@ std::string GCodeWriter::toolchange_prefix() const
|
||||
std::string GCodeWriter::toolchange(unsigned int extruder_id)
|
||||
{
|
||||
// set the new extruder
|
||||
auto it_extruder = std::lower_bound(m_extruders.begin(), m_extruders.end(), Extruder::key(extruder_id));
|
||||
assert(it_extruder != m_extruders.end());
|
||||
m_extruder = const_cast<Extruder*>(&*it_extruder);
|
||||
auto it_extruder = Slic3r::lower_bound_by_predicate(m_extruders.begin(), m_extruders.end(), [extruder_id](const Extruder &e) { return e.id() < extruder_id; });
|
||||
assert(it_extruder != m_extruders.end() && it_extruder->id() == extruder_id);
|
||||
m_extruder = &*it_extruder;
|
||||
|
||||
// return the toolchange command
|
||||
// if we are running a single-extruder setup, just set the extruder and return nothing
|
||||
|
@ -13,7 +13,7 @@ namespace Slic3r {
|
||||
// Additional Codes which can be set by user using DoubleSlider
|
||||
static constexpr char ColorChangeCode[] = "M600";
|
||||
static constexpr char PausePrintCode[] = "M601";
|
||||
static constexpr char ExtruderChangeCode[] = "tool_change";
|
||||
static constexpr char ToolChangeCode[] = "tool_change";
|
||||
|
||||
class GCodeWriter {
|
||||
public:
|
||||
@ -33,7 +33,7 @@ public:
|
||||
std::string extrusion_axis() const { return m_extrusion_axis; }
|
||||
void apply_print_config(const PrintConfig &print_config);
|
||||
// Extruders are expected to be sorted in an increasing order.
|
||||
void set_extruders(const std::vector<unsigned int> &extruder_ids);
|
||||
void set_extruders(std::vector<unsigned int> extruder_ids);
|
||||
const std::vector<Extruder>& extruders() const { return m_extruders; }
|
||||
std::vector<unsigned int> extruder_ids() const {
|
||||
std::vector<unsigned int> out;
|
||||
@ -74,7 +74,8 @@ public:
|
||||
Vec3d get_position() const { return m_pos; }
|
||||
|
||||
private:
|
||||
std::vector<Extruder> m_extruders;
|
||||
// Extruders are sorted by their ID, so that binary search is possible.
|
||||
std::vector<Extruder> m_extruders;
|
||||
std::string m_extrusion_axis;
|
||||
bool m_single_extruder_multi_material;
|
||||
Extruder* m_extruder;
|
||||
|
@ -126,7 +126,7 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c
|
||||
if (add_default_instances)
|
||||
model.add_default_instances();
|
||||
|
||||
update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config);
|
||||
update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z.gcodes, config);
|
||||
|
||||
return model;
|
||||
}
|
||||
@ -163,7 +163,7 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig
|
||||
if (add_default_instances)
|
||||
model.add_default_instances();
|
||||
|
||||
update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config);
|
||||
update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z.gcodes, config);
|
||||
|
||||
return model;
|
||||
}
|
||||
@ -598,21 +598,6 @@ std::string Model::propose_export_file_name_and_path(const std::string &new_exte
|
||||
return boost::filesystem::path(this->propose_export_file_name_and_path()).replace_extension(new_extension).string();
|
||||
}
|
||||
|
||||
std::vector<std::pair<double, DynamicPrintConfig>> Model::get_custom_tool_changes(double default_layer_height, size_t num_extruders) const
|
||||
{
|
||||
std::vector<std::pair<double, DynamicPrintConfig>> custom_tool_changes;
|
||||
for (const CustomGCode& custom_gcode : custom_gcode_per_print_z)
|
||||
if (custom_gcode.gcode == ExtruderChangeCode) {
|
||||
DynamicPrintConfig config;
|
||||
// If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
|
||||
config.set_key_value("extruder", new ConfigOptionInt(custom_gcode.extruder > num_extruders ? 0 : custom_gcode.extruder));
|
||||
// For correct extruders(tools) changing, we should decrease custom_gcode.height value by one default layer height
|
||||
custom_tool_changes.push_back({ custom_gcode.print_z - default_layer_height, config });
|
||||
}
|
||||
|
||||
return custom_tool_changes;
|
||||
}
|
||||
|
||||
ModelObject::~ModelObject()
|
||||
{
|
||||
this->clear_volumes();
|
||||
@ -860,7 +845,7 @@ TriangleMesh ModelObject::mesh() const
|
||||
}
|
||||
|
||||
// Non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
|
||||
// Currently used by ModelObject::mesh(), to calculate the 2D envelope for 2D platter
|
||||
// Currently used by ModelObject::mesh(), to calculate the 2D envelope for 2D plater
|
||||
// and to display the object statistics at ModelObject::print_info().
|
||||
TriangleMesh ModelObject::raw_mesh() const
|
||||
{
|
||||
@ -1863,6 +1848,19 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Return pairs of <print_z, 1-based extruder ID> sorted by increasing print_z from custom_gcode_per_print_z.
|
||||
// print_z corresponds to the first layer printed with the new extruder.
|
||||
std::vector<std::pair<double, unsigned int>> custom_tool_changes(const Model &model, size_t num_extruders)
|
||||
{
|
||||
std::vector<std::pair<double, unsigned int>> custom_tool_changes;
|
||||
for (const Model::CustomGCode &custom_gcode : model.custom_gcode_per_print_z.gcodes)
|
||||
if (custom_gcode.gcode == ToolChangeCode) {
|
||||
// If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
|
||||
custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast<unsigned int>(custom_gcode.extruder > num_extruders ? 1 : custom_gcode.extruder));
|
||||
}
|
||||
return custom_tool_changes;
|
||||
}
|
||||
|
||||
// Test whether the two models contain the same number of ModelObjects with the same set of IDs
|
||||
// ordered in the same order. In that case it is not necessary to kill the background processing.
|
||||
bool model_object_list_equal(const Model &model_old, const Model &model_new)
|
||||
|
@ -240,7 +240,7 @@ public:
|
||||
// A mesh containing all transformed instances of this object.
|
||||
TriangleMesh mesh() const;
|
||||
// Non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
|
||||
// Currently used by ModelObject::mesh() and to calculate the 2D envelope for 2D platter.
|
||||
// Currently used by ModelObject::mesh() and to calculate the 2D envelope for 2D plater.
|
||||
TriangleMesh raw_mesh() const;
|
||||
// Non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
|
||||
TriangleMesh full_raw_mesh() const;
|
||||
@ -403,13 +403,9 @@ public:
|
||||
int object_idx{ -1 };
|
||||
int volume_idx{ -1 };
|
||||
Vec3d mesh_offset{ Vec3d::Zero() };
|
||||
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
Geometry::Transformation transform;
|
||||
|
||||
template<class Archive> void serialize(Archive& ar) { ar(input_file, object_idx, volume_idx, mesh_offset, transform); }
|
||||
#else
|
||||
template<class Archive> void serialize(Archive& ar) { ar(input_file, object_idx, volume_idx, mesh_offset); }
|
||||
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
};
|
||||
Source source;
|
||||
|
||||
@ -771,12 +767,34 @@ public:
|
||||
|
||||
double print_z;
|
||||
std::string gcode;
|
||||
int extruder; // 0 - "gcode" will be applied for whole print
|
||||
// else - "gcode" will be applied only for "extruder" print
|
||||
int extruder; // Informative value for ColorChangeCode and ToolChangeCode
|
||||
// "gcode" == ColorChangeCode => M600 will be applied for "extruder" extruder
|
||||
// "gcode" == ToolChangeCode => for whole print tool will be switched to "extruder" extruder
|
||||
std::string color; // if gcode is equal to PausePrintCode,
|
||||
// this field is used for save a short message shown on Printer display
|
||||
};
|
||||
std::vector<CustomGCode> custom_gcode_per_print_z;
|
||||
|
||||
struct CustomGCodeInfo
|
||||
{
|
||||
enum MODE
|
||||
{
|
||||
SingleExtruder, // single extruder printer preset is selected
|
||||
MultiAsSingle, // multiple extruder printer preset is selected, but
|
||||
// this mode works just for Single extruder print
|
||||
// (For all print from objects settings is used just one extruder)
|
||||
MultiExtruder // multiple extruder printer preset is selected
|
||||
} mode;
|
||||
|
||||
std::vector<CustomGCode> gcodes;
|
||||
|
||||
bool operator==(const CustomGCodeInfo& rhs) const
|
||||
{
|
||||
return (rhs.mode == this->mode ) &&
|
||||
(rhs.gcodes == this->gcodes );
|
||||
}
|
||||
bool operator!=(const CustomGCodeInfo& rhs) const { return !(*this == rhs); }
|
||||
}
|
||||
custom_gcode_per_print_z;
|
||||
|
||||
// Default constructor assigns a new ID to the model.
|
||||
Model() { assert(this->id().valid()); }
|
||||
@ -842,9 +860,6 @@ public:
|
||||
// Propose an output path, replace extension. The new_extension shall contain the initial dot.
|
||||
std::string propose_export_file_name_and_path(const std::string &new_extension) const;
|
||||
|
||||
// from custom_gcode_per_print_z get just tool_change codes
|
||||
std::vector<std::pair<double, DynamicPrintConfig>> get_custom_tool_changes(double default_layer_height, size_t num_extruders) const;
|
||||
|
||||
private:
|
||||
explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); };
|
||||
void assign_new_unique_ids_recursive();
|
||||
@ -861,6 +876,10 @@ private:
|
||||
#undef OBJECTBASE_DERIVED_COPY_MOVE_CLONE
|
||||
#undef OBJECTBASE_DERIVED_PRIVATE_COPY_MOVE
|
||||
|
||||
// Return pairs of <print_z, 1-based extruder ID> sorted by increasing print_z from custom_gcode_per_print_z.
|
||||
// print_z corresponds to the first layer printed with the new extruder.
|
||||
extern std::vector<std::pair<double, unsigned int>> custom_tool_changes(const Model &model, size_t num_extruders);
|
||||
|
||||
// Test whether the two models contain the same number of ModelObjects with the same set of IDs
|
||||
// ordered in the same order. In that case it is not necessary to kill the background processing.
|
||||
extern bool model_object_list_equal(const Model &model_old, const Model &model_new);
|
||||
|
@ -332,6 +332,21 @@ namespace client
|
||||
return expr();
|
||||
}
|
||||
|
||||
expr unary_integer(const Iterator start_pos) const
|
||||
{
|
||||
switch (this->type) {
|
||||
case TYPE_INT :
|
||||
return expr<Iterator>(this->i(), start_pos, this->it_range.end());
|
||||
case TYPE_DOUBLE:
|
||||
return expr<Iterator>((int)(this->d()), start_pos, this->it_range.end());
|
||||
default:
|
||||
this->throw_exception("Cannot convert to integer.");
|
||||
}
|
||||
assert(false);
|
||||
// Suppress compiler warnings.
|
||||
return expr();
|
||||
}
|
||||
|
||||
expr unary_not(const Iterator start_pos) const
|
||||
{
|
||||
switch (this->type) {
|
||||
@ -415,6 +430,22 @@ namespace client
|
||||
return *this;
|
||||
}
|
||||
|
||||
expr &operator%=(const expr &rhs)
|
||||
{
|
||||
this->throw_if_not_numeric("Cannot divide a non-numeric type.");
|
||||
rhs.throw_if_not_numeric("Cannot divide with a non-numeric type.");
|
||||
if ((this->type == TYPE_INT) ? (rhs.i() == 0) : (rhs.d() == 0.))
|
||||
rhs.throw_exception("Division by zero");
|
||||
if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) {
|
||||
double d = std::fmod(this->as_d(), rhs.as_d());
|
||||
this->data.d = d;
|
||||
this->type = TYPE_DOUBLE;
|
||||
} else
|
||||
this->data.i %= rhs.i();
|
||||
this->it_range = boost::iterator_range<Iterator>(this->it_range.begin(), rhs.it_range.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
static void to_string2(expr &self, std::string &out)
|
||||
{
|
||||
out = self.to_string();
|
||||
@ -1087,6 +1118,7 @@ namespace client
|
||||
unary_expression(_r1) [_val = _1]
|
||||
>> *( (lit('*') > unary_expression(_r1) ) [_val *= _1]
|
||||
| (lit('/') > unary_expression(_r1) ) [_val /= _1]
|
||||
| (lit('%') > unary_expression(_r1) ) [_val %= _1]
|
||||
);
|
||||
multiplicative_expression.name("multiplicative_expression");
|
||||
|
||||
@ -1107,6 +1139,8 @@ namespace client
|
||||
{ out = value.unary_minus(out.it_range.begin()); }
|
||||
static void not_(expr<Iterator> &value, expr<Iterator> &out)
|
||||
{ out = value.unary_not(out.it_range.begin()); }
|
||||
static void to_int(expr<Iterator> &value, expr<Iterator> &out)
|
||||
{ out = value.unary_integer(out.it_range.begin()); }
|
||||
};
|
||||
unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> (
|
||||
scalar_variable_reference(_r1) [ _val = _1 ]
|
||||
@ -1118,6 +1152,8 @@ namespace client
|
||||
[ px::bind(&expr<Iterator>::min, _val, _2) ]
|
||||
| (kw["max"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')')
|
||||
[ px::bind(&expr<Iterator>::max, _val, _2) ]
|
||||
//FIXME this is likley not correct
|
||||
| (kw["int"] > '(' > unary_expression(_r1) /* > ')' */ ) [ px::bind(&FactorActions::to_int, _1, _val) ]
|
||||
| (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ]
|
||||
| (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ]
|
||||
| (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _1, _2, _val) ]
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
|
||||
// Fill in the template using a macro processing language.
|
||||
// Throws std::runtime_error on syntax or runtime error.
|
||||
std::string process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr) const;
|
||||
std::string process(const std::string &templ, unsigned int current_extruder_id = 0, const DynamicConfig *config_override = nullptr) const;
|
||||
|
||||
// Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax.
|
||||
// Throws std::runtime_error on syntax or runtime error.
|
||||
|
@ -478,7 +478,7 @@ static std::vector<PrintInstances> print_objects_from_model_object(const ModelOb
|
||||
|
||||
// Compare just the layer ranges and their layer heights, not the associated configs.
|
||||
// Ignore the layer heights if check_layer_heights is false.
|
||||
bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_config_ranges &lr2, bool check_layer_height)
|
||||
static bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_config_ranges &lr2, bool check_layer_height)
|
||||
{
|
||||
if (lr1.size() != lr2.size())
|
||||
return false;
|
||||
@ -493,6 +493,37 @@ bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_c
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if va == vb when all CustomGCode items that are not ToolChangeCode are ignored.
|
||||
static bool custom_per_printz_gcodes_tool_changes_differ(const std::vector<Model::CustomGCode> &va, const std::vector<Model::CustomGCode> &vb)
|
||||
{
|
||||
auto it_a = va.begin();
|
||||
auto it_b = vb.begin();
|
||||
while (it_a != va.end() && it_b != vb.end()) {
|
||||
if (it_a != va.end() && it_a->gcode != ToolChangeCode) {
|
||||
// Skip any CustomGCode items, which are not tool changes.
|
||||
++ it_a;
|
||||
continue;
|
||||
}
|
||||
if (it_b != vb.end() && it_b->gcode != ToolChangeCode) {
|
||||
// Skip any CustomGCode items, which are not tool changes.
|
||||
++ it_b;
|
||||
continue;
|
||||
}
|
||||
if (it_a == va.end() || it_b == vb.end())
|
||||
// va or vb contains more Tool Changes than the other.
|
||||
return true;
|
||||
assert(it_a->gcode == ToolChangeCode);
|
||||
assert(it_b->gcode == ToolChangeCode);
|
||||
if (*it_a != *it_b)
|
||||
// The two Tool Changes differ.
|
||||
return true;
|
||||
++ it_a;
|
||||
++ it_b;
|
||||
}
|
||||
// There is no change in custom Tool Changes.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Collect diffs of configuration values at various containers,
|
||||
// resolve the filament rectract overrides of extruder retract values.
|
||||
void Print::config_diffs(
|
||||
@ -638,48 +669,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
m_ranges.emplace_back(t_layer_height_range(m_ranges.back().first.second, DBL_MAX), nullptr);
|
||||
}
|
||||
|
||||
// Convert input config ranges into continuous non-overlapping sorted vector of intervals and their configs,
|
||||
// considering custom_tool_change values
|
||||
void assign(const t_layer_config_ranges &in, const std::vector<std::pair<double, DynamicPrintConfig>> &custom_tool_changes) {
|
||||
m_ranges.clear();
|
||||
m_ranges.reserve(in.size());
|
||||
// Input ranges are sorted lexicographically. First range trims the other ranges.
|
||||
coordf_t last_z = 0;
|
||||
for (const std::pair<const t_layer_height_range, DynamicPrintConfig> &range : in)
|
||||
if (range.first.second > last_z) {
|
||||
coordf_t min_z = std::max(range.first.first, 0.);
|
||||
if (min_z > last_z + EPSILON) {
|
||||
m_ranges.emplace_back(t_layer_height_range(last_z, min_z), nullptr);
|
||||
last_z = min_z;
|
||||
}
|
||||
if (range.first.second > last_z + EPSILON) {
|
||||
const DynamicPrintConfig* cfg = &range.second;
|
||||
m_ranges.emplace_back(t_layer_height_range(last_z, range.first.second), cfg);
|
||||
last_z = range.first.second;
|
||||
}
|
||||
}
|
||||
|
||||
// add ranges for extruder changes from custom_tool_changes
|
||||
for (size_t i = 0; i < custom_tool_changes.size(); i++) {
|
||||
const DynamicPrintConfig* cfg = &custom_tool_changes[i].second;
|
||||
coordf_t cur_Z = custom_tool_changes[i].first;
|
||||
coordf_t next_Z = i == custom_tool_changes.size()-1 ? DBL_MAX : custom_tool_changes[i+1].first;
|
||||
if (cur_Z > last_z + EPSILON) {
|
||||
if (i==0)
|
||||
m_ranges.emplace_back(t_layer_height_range(last_z, cur_Z), nullptr);
|
||||
m_ranges.emplace_back(t_layer_height_range(cur_Z, next_Z), cfg);
|
||||
}
|
||||
else if (next_Z > last_z + EPSILON)
|
||||
m_ranges.emplace_back(t_layer_height_range(last_z, next_Z), cfg);
|
||||
}
|
||||
|
||||
if (m_ranges.empty())
|
||||
m_ranges.emplace_back(t_layer_height_range(0, DBL_MAX), nullptr);
|
||||
else if (m_ranges.back().second == nullptr)
|
||||
m_ranges.back().first.second = DBL_MAX;
|
||||
else if (m_ranges.back().first.second != DBL_MAX)
|
||||
m_ranges.emplace_back(t_layer_height_range(m_ranges.back().first.second, DBL_MAX), nullptr);
|
||||
}
|
||||
const DynamicPrintConfig* config(const t_layer_height_range &range) const {
|
||||
auto it = std::lower_bound(m_ranges.begin(), m_ranges.end(), std::make_pair< t_layer_height_range, const DynamicPrintConfig*>(t_layer_height_range(range.first - EPSILON, range.second - EPSILON), nullptr));
|
||||
// #ys_FIXME_COLOR
|
||||
@ -733,17 +722,18 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
for (const ModelObject *model_object : m_model.objects)
|
||||
model_object_status.emplace(model_object->id(), ModelObjectStatus::New);
|
||||
} else {
|
||||
if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) {
|
||||
update_apply_status(custom_per_printz_gcodes_tool_changes_differ(m_model.custom_gcode_per_print_z.gcodes, model.custom_gcode_per_print_z.gcodes) ?
|
||||
// The Tool Ordering and the Wipe Tower are no more valid.
|
||||
this->invalidate_steps({ psWipeTower, psGCodeExport }) :
|
||||
// There is no change in Tool Changes stored in custom_gcode_per_print_z, therefore there is no need to update Tool Ordering.
|
||||
this->invalidate_step(psGCodeExport));
|
||||
m_model.custom_gcode_per_print_z = model.custom_gcode_per_print_z;
|
||||
}
|
||||
if (model_object_list_equal(m_model, model)) {
|
||||
// The object list did not change.
|
||||
for (const ModelObject *model_object : m_model.objects)
|
||||
model_object_status.emplace(model_object->id(), ModelObjectStatus::Old);
|
||||
|
||||
// But if custom gcode per layer height was changed
|
||||
if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) {
|
||||
// we should stop background processing
|
||||
update_apply_status(this->invalidate_step(psGCodeExport));
|
||||
m_model.custom_gcode_per_print_z = model.custom_gcode_per_print_z;
|
||||
}
|
||||
} else if (model_object_list_extended(m_model, model)) {
|
||||
// Add new objects. Their volumes and configs will be synchronized later.
|
||||
update_apply_status(this->invalidate_step(psGCodeExport));
|
||||
@ -835,9 +825,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
for (PrintObject *print_object : m_objects)
|
||||
print_object_status.emplace(PrintObjectStatus(print_object));
|
||||
|
||||
std::vector<std::pair<double, DynamicPrintConfig>> custom_tool_changes =
|
||||
m_model.get_custom_tool_changes(m_default_object_config.layer_height, num_extruders);
|
||||
|
||||
// 3) Synchronize ModelObjects & PrintObjects.
|
||||
for (size_t idx_model_object = 0; idx_model_object < model.objects.size(); ++ idx_model_object) {
|
||||
ModelObject &model_object = *m_model.objects[idx_model_object];
|
||||
@ -845,9 +832,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
assert(it_status != model_object_status.end());
|
||||
assert(it_status->status != ModelObjectStatus::Deleted);
|
||||
const ModelObject& model_object_new = *model.objects[idx_model_object];
|
||||
// ys_FIXME_COLOR
|
||||
// const_cast<ModelObjectStatus&>(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges);
|
||||
const_cast<ModelObjectStatus&>(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges, custom_tool_changes);
|
||||
const_cast<ModelObjectStatus&>(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges);
|
||||
if (it_status->status == ModelObjectStatus::New)
|
||||
// PrintObject instances will be added in the next loop.
|
||||
continue;
|
||||
@ -1015,8 +1000,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
PrintRegionConfig this_region_config;
|
||||
bool this_region_config_set = false;
|
||||
for (PrintObject *print_object : m_objects) {
|
||||
if(m_force_update_print_regions && !custom_tool_changes.empty())
|
||||
goto print_object_end;
|
||||
const LayerRanges *layer_ranges;
|
||||
{
|
||||
auto it_status = model_object_status.find(ModelObjectStatus(print_object->model_object()->id()));
|
||||
@ -1572,9 +1555,13 @@ void Print::process()
|
||||
obj->generate_support_material();
|
||||
if (this->set_started(psWipeTower)) {
|
||||
m_wipe_tower_data.clear();
|
||||
m_tool_ordering.clear();
|
||||
if (this->has_wipe_tower()) {
|
||||
//this->set_status(95, L("Generating wipe tower"));
|
||||
this->_make_wipe_tower();
|
||||
} else if (! this->config().complete_objects.value) {
|
||||
// Initialize the tool ordering, so it could be used by the G-code preview slider for planning tool changes and filament switches.
|
||||
m_tool_ordering = ToolOrdering(*this, -1, false);
|
||||
}
|
||||
this->set_done(psWipeTower);
|
||||
}
|
||||
@ -1963,8 +1950,8 @@ const WipeTowerData& Print::wipe_tower_data(size_t extruders_cnt, double first_l
|
||||
// If the wipe tower wasn't created yet, make sure the depth and brim_width members are set to default.
|
||||
if (! is_step_done(psWipeTower) && extruders_cnt !=0) {
|
||||
|
||||
float width = m_config.wipe_tower_width;
|
||||
float brim_spacing = nozzle_diameter * 1.25f - first_layer_height * (1. - M_PI_4);
|
||||
float width = float(m_config.wipe_tower_width);
|
||||
float brim_spacing = float(nozzle_diameter * 1.25f - first_layer_height * (1. - M_PI_4));
|
||||
|
||||
const_cast<Print*>(this)->m_wipe_tower_data.depth = (900.f/width) * float(extruders_cnt - 1);
|
||||
const_cast<Print*>(this)->m_wipe_tower_data.brim_width = 4.5f * brim_spacing;
|
||||
@ -1990,6 +1977,7 @@ void Print::_make_wipe_tower()
|
||||
|
||||
// Let the ToolOrdering class know there will be initial priming extrusions at the start of the print.
|
||||
m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true);
|
||||
|
||||
if (! m_wipe_tower_data.tool_ordering.has_wipe_tower())
|
||||
// Don't generate any wipe tower.
|
||||
return;
|
||||
@ -2107,13 +2095,6 @@ void Print::_make_wipe_tower()
|
||||
m_wipe_tower_data.number_of_toolchanges = wipe_tower.get_number_of_toolchanges();
|
||||
}
|
||||
|
||||
// Returns extruder this eec should be printed with, according to PrintRegion config
|
||||
int Print::get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion)
|
||||
{
|
||||
return is_infill(fill.role()) ? std::max<int>(0, (is_solid_infill(fill.entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) - 1) :
|
||||
std::max<int>(region.config().perimeter_extruder.value - 1, 0);
|
||||
}
|
||||
|
||||
// Generate a recommended G-code output file name based on the format template, default extension, and template parameters
|
||||
// (timestamps, object placeholders derived from the model, current placeholder prameters and print statistics.
|
||||
// Use the final print statistics if available, or just keep the print statistics placeholders if not available yet (before G-code is finalized).
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#include "libslic3r.h"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Print;
|
||||
@ -25,8 +27,19 @@ class GCodePreviewData;
|
||||
|
||||
// Print step IDs for keeping track of the print state.
|
||||
enum PrintStep {
|
||||
psSkirt, psBrim, psWipeTower, psGCodeExport, psCount,
|
||||
psSkirt,
|
||||
psBrim,
|
||||
// Synonym for the last step before the Wipe Tower / Tool Ordering, for the G-code preview slider to understand that
|
||||
// all the extrusions are there for the layer slider to add color changes etc.
|
||||
psExtrusionPaths = psBrim,
|
||||
psWipeTower,
|
||||
// psToolOrdering is a synonym to psWipeTower, as the Wipe Tower calculates and modifies the ToolOrdering,
|
||||
// while if printing without the Wipe Tower, the ToolOrdering is calculated as well.
|
||||
psToolOrdering = psWipeTower,
|
||||
psGCodeExport,
|
||||
psCount,
|
||||
};
|
||||
|
||||
enum PrintObjectStep {
|
||||
posSlice, posPerimeters, posPrepareInfill,
|
||||
posInfill, posSupportMaterial, posCount,
|
||||
@ -50,7 +63,7 @@ public:
|
||||
// Average diameter of nozzles participating on extruding this region.
|
||||
coordf_t bridging_height_avg(const PrintConfig &print_config) const;
|
||||
|
||||
// Collect extruder indices used to print this region's object.
|
||||
// Collect 0-based extruder indices used to print this region's object.
|
||||
void collect_object_printing_extruders(std::vector<unsigned int> &object_extruders) const;
|
||||
static void collect_object_printing_extruders(const PrintConfig &print_config, const PrintRegionConfig ®ion_config, std::vector<unsigned int> &object_extruders);
|
||||
|
||||
@ -116,8 +129,21 @@ public:
|
||||
size_t total_layer_count() const { return this->layer_count() + this->support_layer_count(); }
|
||||
size_t layer_count() const { return m_layers.size(); }
|
||||
void clear_layers();
|
||||
Layer* get_layer(int idx) { return m_layers[idx]; }
|
||||
const Layer* get_layer(int idx) const { return m_layers[idx]; }
|
||||
const Layer* get_layer(int idx) const { return m_layers[idx]; }
|
||||
Layer* get_layer(int idx) { return m_layers[idx]; }
|
||||
// Get a layer exactly at print_z.
|
||||
const Layer* get_layer_at_printz(coordf_t print_z) const {
|
||||
auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [print_z](const Layer *layer) { return layer->print_z < print_z; });
|
||||
return (it == m_layers.end() || (*it)->print_z != print_z) ? nullptr : *it;
|
||||
}
|
||||
Layer* get_layer_at_printz(coordf_t print_z) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z)); }
|
||||
// Get a layer approximately at print_z.
|
||||
const Layer* get_layer_at_printz(coordf_t print_z, coordf_t epsilon) const {
|
||||
coordf_t limit = print_z + epsilon;
|
||||
auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [limit](const Layer *layer) { return layer->print_z < limit; });
|
||||
return (it == m_layers.end() || (*it)->print_z < print_z - epsilon) ? nullptr : *it;
|
||||
}
|
||||
Layer* get_layer_at_printz(coordf_t print_z, coordf_t epsilon) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z, epsilon)); }
|
||||
|
||||
// print_z: top of the layer; slice_z: center of the layer.
|
||||
Layer* add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
|
||||
@ -219,7 +245,7 @@ struct WipeTowerData
|
||||
// Following section will be consumed by the GCodeGenerator.
|
||||
// Tool ordering of a non-sequential print has to be known to calculate the wipe tower.
|
||||
// Cache it here, so it does not need to be recalculated during the G-code generation.
|
||||
ToolOrdering tool_ordering;
|
||||
ToolOrdering &tool_ordering;
|
||||
// Cache of tool changes per print layer.
|
||||
std::unique_ptr<std::vector<WipeTower::ToolChangeResult>> priming;
|
||||
std::vector<std::vector<WipeTower::ToolChangeResult>> tool_changes;
|
||||
@ -232,7 +258,6 @@ struct WipeTowerData
|
||||
float brim_width;
|
||||
|
||||
void clear() {
|
||||
tool_ordering.clear();
|
||||
priming.reset(nullptr);
|
||||
tool_changes.clear();
|
||||
final_purge.reset(nullptr);
|
||||
@ -241,6 +266,14 @@ struct WipeTowerData
|
||||
depth = 0.f;
|
||||
brim_width = 0.f;
|
||||
}
|
||||
|
||||
private:
|
||||
// Only allow the WipeTowerData to be instantiated internally by Print,
|
||||
// as this WipeTowerData shares reference to Print::m_tool_ordering.
|
||||
friend class Print;
|
||||
WipeTowerData(ToolOrdering &tool_ordering) : tool_ordering(tool_ordering) { clear(); }
|
||||
WipeTowerData(const WipeTowerData & /* rhs */) = delete;
|
||||
WipeTowerData &operator=(const WipeTowerData & /* rhs */) = delete;
|
||||
};
|
||||
|
||||
struct PrintStatistics
|
||||
@ -345,6 +378,7 @@ public:
|
||||
const PrintConfig& config() const { return m_config; }
|
||||
const PrintObjectConfig& default_object_config() const { return m_default_object_config; }
|
||||
const PrintRegionConfig& default_region_config() const { return m_default_region_config; }
|
||||
//FIXME returning const vector to non-const PrintObject*, caller could modify PrintObjects!
|
||||
const PrintObjectPtrs& objects() const { return m_objects; }
|
||||
PrintObject* get_object(size_t idx) { return m_objects[idx]; }
|
||||
const PrintObject* get_object(size_t idx) const { return m_objects[idx]; }
|
||||
@ -353,9 +387,6 @@ public:
|
||||
// If zero, then the print is empty and the print shall not be executed.
|
||||
unsigned int num_object_instances() const;
|
||||
|
||||
// Returns extruder this eec should be printed with, according to PrintRegion config:
|
||||
static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion);
|
||||
|
||||
const ExtrusionEntityCollection& skirt() const { return m_skirt; }
|
||||
const ExtrusionEntityCollection& brim() const { return m_brim; }
|
||||
|
||||
@ -364,14 +395,13 @@ public:
|
||||
// Wipe tower support.
|
||||
bool has_wipe_tower() const;
|
||||
const WipeTowerData& wipe_tower_data(size_t extruders_cnt = 0, double first_layer_height = 0., double nozzle_diameter = 0.) const;
|
||||
const ToolOrdering& tool_ordering() const { return m_tool_ordering; }
|
||||
|
||||
std::string output_filename(const std::string &filename_base = std::string()) const override;
|
||||
|
||||
// Accessed by SupportMaterial
|
||||
const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; }
|
||||
|
||||
// force update of PrintRegions, when custom_tool_change is not empty and (Re)Slicing is started
|
||||
void set_force_update_print_regions(bool force_update_print_regions) { m_force_update_print_regions = force_update_print_regions; }
|
||||
const ToolOrdering& get_tool_ordering() const { return m_wipe_tower_data.tool_ordering; } // #ys_FIXME just for testing
|
||||
|
||||
protected:
|
||||
// methods for handling regions
|
||||
@ -410,14 +440,12 @@ private:
|
||||
ExtrusionEntityCollection m_brim;
|
||||
|
||||
// Following section will be consumed by the GCodeGenerator.
|
||||
WipeTowerData m_wipe_tower_data;
|
||||
ToolOrdering m_tool_ordering;
|
||||
WipeTowerData m_wipe_tower_data {m_tool_ordering};
|
||||
|
||||
// Estimated print time, filament consumed.
|
||||
PrintStatistics m_print_statistics;
|
||||
|
||||
// flag used
|
||||
bool m_force_update_print_regions = false;
|
||||
|
||||
// To allow GCode to set the Print's GCodeExport step status.
|
||||
friend class GCode;
|
||||
// Allow PrintObject to access m_mutex and m_cancel_callback.
|
||||
|
@ -37,7 +37,7 @@ void PrintBase::update_object_placeholders(DynamicConfig &config, const std::str
|
||||
}
|
||||
}
|
||||
|
||||
config.set_key_value("year", new ConfigOptionStrings(v_scale));
|
||||
config.set_key_value("scale", new ConfigOptionStrings(v_scale));
|
||||
if (! input_file.empty()) {
|
||||
// get basename with and without suffix
|
||||
const std::string input_filename = boost::filesystem::path(input_file).filename().string();
|
||||
|
@ -1337,7 +1337,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_labels.push_back("OctoPrint");
|
||||
def->enum_labels.push_back("Duet");
|
||||
def->enum_labels.push_back("FlashAir");
|
||||
def->enum_values.push_back("AstroBox");
|
||||
def->enum_labels.push_back("AstroBox");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionEnum<PrintHostType>(htOctoPrint));
|
||||
|
||||
|
@ -300,26 +300,14 @@ std::vector<double> layer_height_profile_adaptive(const SlicingParameters& slici
|
||||
layer_height_profile.push_back(print_z);
|
||||
layer_height_profile.push_back(height);
|
||||
print_z += height;
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
layer_height_profile.push_back(print_z);
|
||||
layer_height_profile.push_back(height);
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
}
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
double z_gap = slicing_params.object_print_z_height() - layer_height_profile[layer_height_profile.size() - 2];
|
||||
if (z_gap > 0.0)
|
||||
{
|
||||
layer_height_profile.push_back(slicing_params.object_print_z_height());
|
||||
layer_height_profile.push_back(clamp(slicing_params.min_layer_height, slicing_params.max_layer_height, z_gap));
|
||||
}
|
||||
#else
|
||||
double last = std::max(slicing_params.first_object_layer_height, layer_height_profile[layer_height_profile.size() - 2]);
|
||||
layer_height_profile.push_back(last);
|
||||
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||
layer_height_profile.push_back(slicing_params.object_print_z_height());
|
||||
layer_height_profile.push_back(slicing_params.first_object_layer_height);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
return layer_height_profile;
|
||||
}
|
||||
|
@ -41,24 +41,6 @@
|
||||
#define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1)
|
||||
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR)
|
||||
|
||||
// Enable adaptive layer height profile
|
||||
#define ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE (1 && ENABLE_2_2_0_ALPHA1)
|
||||
|
||||
// Enable grayed variant for gizmos icons in non activable state
|
||||
#define ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE (1 && ENABLE_2_2_0_ALPHA1)
|
||||
|
||||
// Enable fix for view toolbar background not showing up on Mac with dark mode
|
||||
#define ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX (1 && ENABLE_2_2_0_ALPHA1)
|
||||
|
||||
// Enable selection for missing files in reload from disk command
|
||||
#define ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION (1 && ENABLE_2_2_0_ALPHA1)
|
||||
|
||||
// Enable closing 3Dconnextion imgui settings dialog by clicking on [X] and [Close] buttons
|
||||
#define ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG (1 && ENABLE_2_2_0_ALPHA1)
|
||||
|
||||
// Enable not applying volume transformation during 3mf and amf loading, but keeping it as a ModelVolume member
|
||||
#define ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE (1 && ENABLE_2_2_0_ALPHA1)
|
||||
|
||||
|
||||
//==================
|
||||
// 2.2.0.beta1 techs
|
||||
@ -68,4 +50,13 @@
|
||||
// Enable using Y axis of 3Dconnexion devices as zoom
|
||||
#define ENABLE_3DCONNEXION_Y_AS_ZOOM (1 && ENABLE_2_2_0_BETA1)
|
||||
|
||||
// Enable a modified version of the toolbar textures where all the icons are separated by 1 pixel
|
||||
#define ENABLE_MODIFIED_TOOLBAR_TEXTURES (1 && ENABLE_2_2_0_BETA1)
|
||||
|
||||
// Enable configurable paths export (fullpath or not) to 3mf and amf
|
||||
#define ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF (1 && ENABLE_2_2_0_BETA1)
|
||||
|
||||
// Enable 6 degrees of freedom camera
|
||||
#define ENABLE_6DOF_CAMERA (1 && ENABLE_2_2_0_BETA1)
|
||||
|
||||
#endif // _technologies_h_
|
||||
|
@ -158,6 +158,53 @@ inline std::unique_ptr<T> make_unique(Args&&... args) {
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
// Variant of std::lower_bound() with compare predicate, but without the key.
|
||||
// This variant is very useful in case that the T type is large or it does not even have a public constructor.
|
||||
template<class ForwardIt, class LowerThanKeyPredicate>
|
||||
ForwardIt lower_bound_by_predicate(ForwardIt first, ForwardIt last, LowerThanKeyPredicate lower_thank_key)
|
||||
{
|
||||
ForwardIt it;
|
||||
typename std::iterator_traits<ForwardIt>::difference_type count, step;
|
||||
count = std::distance(first, last);
|
||||
|
||||
while (count > 0) {
|
||||
it = first;
|
||||
step = count / 2;
|
||||
std::advance(it, step);
|
||||
if (lower_thank_key(*it)) {
|
||||
first = ++it;
|
||||
count -= step + 1;
|
||||
}
|
||||
else
|
||||
count = step;
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
// from https://en.cppreference.com/w/cpp/algorithm/lower_bound
|
||||
template<class ForwardIt, class T, class Compare=std::less<>>
|
||||
ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, Compare comp={})
|
||||
{
|
||||
// Note: BOTH type T and the type after ForwardIt is dereferenced
|
||||
// must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
|
||||
// This is stricter than lower_bound requirement (see above)
|
||||
|
||||
first = std::lower_bound(first, last, value, comp);
|
||||
return first != last && !comp(value, *first) ? first : last;
|
||||
}
|
||||
|
||||
// from https://en.cppreference.com/w/cpp/algorithm/lower_bound
|
||||
template<class ForwardIt, class LowerThanKeyPredicate, class EqualToKeyPredicate>
|
||||
ForwardIt binary_find_by_predicate(ForwardIt first, ForwardIt last, LowerThanKeyPredicate lower_thank_key, EqualToKeyPredicate equal_to_key)
|
||||
{
|
||||
// Note: BOTH type T and the type after ForwardIt is dereferenced
|
||||
// must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
|
||||
// This is stricter than lower_bound requirement (see above)
|
||||
|
||||
first = lower_bound_by_predicate(first, last, lower_thank_key);
|
||||
return first != last && equal_to_key(*first) ? first : last;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline T sqr(T x)
|
||||
{
|
||||
|
@ -26,8 +26,20 @@ bool open_zip(mz_zip_archive *zip, const char *fname, bool isread)
|
||||
return false;
|
||||
}
|
||||
|
||||
return isread ? mz_zip_reader_init_cfile(zip, f, 0, 0)
|
||||
: mz_zip_writer_init_cfile(zip, f, 0);
|
||||
bool res = false;
|
||||
if (isread)
|
||||
{
|
||||
res = mz_zip_reader_init_cfile(zip, f, 0, 0);
|
||||
if (!res)
|
||||
// if we get here it means we tried to open a non-zip file
|
||||
// we need to close the file here because the call to mz_zip_get_cfile() made into close_zip() returns a null pointer
|
||||
// see: https://github.com/prusa3d/PrusaSlicer/issues/3536
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
res = mz_zip_writer_init_cfile(zip, f, 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool close_zip(mz_zip_archive *zip, bool isread)
|
||||
|
@ -63,6 +63,7 @@
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/warning_disable.hpp>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <boost/date_time/local_time/local_time.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
@ -189,8 +189,6 @@ void Bed3D::Axes::render_axis(double length) const
|
||||
|
||||
Bed3D::Bed3D()
|
||||
: m_type(Custom)
|
||||
, m_custom_texture("")
|
||||
, m_custom_model("")
|
||||
, m_vbo_id(0)
|
||||
, m_scale_factor(1.0f)
|
||||
{
|
||||
@ -198,31 +196,31 @@ Bed3D::Bed3D()
|
||||
|
||||
bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model)
|
||||
{
|
||||
EType new_type = detect_type(shape);
|
||||
auto check_texture = [](const std::string& texture) {
|
||||
return !texture.empty() && (boost::algorithm::iends_with(texture, ".png") || boost::algorithm::iends_with(texture, ".svg")) && boost::filesystem::exists(texture);
|
||||
};
|
||||
|
||||
// check that the passed custom texture filename is valid
|
||||
std::string cst_texture(custom_texture);
|
||||
if (!cst_texture.empty())
|
||||
{
|
||||
if ((!boost::algorithm::iends_with(custom_texture, ".png") && !boost::algorithm::iends_with(custom_texture, ".svg")) || !boost::filesystem::exists(custom_texture))
|
||||
cst_texture = "";
|
||||
}
|
||||
auto check_model = [](const std::string& model) {
|
||||
return !model.empty() && boost::algorithm::iends_with(model, ".stl") && boost::filesystem::exists(model);
|
||||
};
|
||||
|
||||
// check that the passed custom texture filename is valid
|
||||
std::string cst_model(custom_model);
|
||||
if (!cst_model.empty())
|
||||
{
|
||||
if (!boost::algorithm::iends_with(custom_model, ".stl") || !boost::filesystem::exists(custom_model))
|
||||
cst_model = "";
|
||||
}
|
||||
auto [new_type, system_model, system_texture] = detect_type(shape);
|
||||
|
||||
if ((m_shape == shape) && (m_type == new_type) && (m_custom_texture == cst_texture) && (m_custom_model == cst_model))
|
||||
std::string texture_filename = custom_texture.empty() ? system_texture : custom_texture;
|
||||
if (!check_texture(texture_filename))
|
||||
texture_filename.clear();
|
||||
|
||||
std::string model_filename = custom_model.empty() ? system_model : custom_model;
|
||||
if (!check_model(model_filename))
|
||||
model_filename.clear();
|
||||
|
||||
if ((m_shape == shape) && (m_type == new_type) && (m_texture_filename == texture_filename) && (m_model_filename == model_filename))
|
||||
// No change, no need to update the UI.
|
||||
return false;
|
||||
|
||||
m_shape = shape;
|
||||
m_custom_texture = cst_texture;
|
||||
m_custom_model = cst_model;
|
||||
m_texture_filename = texture_filename;
|
||||
m_model_filename = model_filename;
|
||||
m_type = new_type;
|
||||
|
||||
calc_bounding_boxes();
|
||||
@ -244,7 +242,7 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
|
||||
m_texture.reset();
|
||||
m_model.reset();
|
||||
|
||||
// Set the origin and size for painting of the coordinate system axes.
|
||||
// Set the origin and size for rendering the coordinate system axes.
|
||||
m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z);
|
||||
m_axes.length = 0.1 * m_bounding_box.max_size() * Vec3d::Ones();
|
||||
|
||||
@ -262,7 +260,11 @@ Point Bed3D::point_projection(const Point& point) const
|
||||
return m_polygon.point_projection(point);
|
||||
}
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) const
|
||||
#else
|
||||
void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor, bool show_axes) const
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
{
|
||||
m_scale_factor = scale_factor;
|
||||
|
||||
@ -273,13 +275,15 @@ void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor, bool sho
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
case MK2: { render_prusa(canvas, "mk2", theta > 90.0f); break; }
|
||||
case MK3: { render_prusa(canvas, "mk3", theta > 90.0f); break; }
|
||||
case SL1: { render_prusa(canvas, "sl1", theta > 90.0f); break; }
|
||||
case MINI: { render_prusa(canvas, "mini", theta > 90.0f); break; }
|
||||
case ENDER3: { render_prusa(canvas, "ender3", theta > 90.0f); break; }
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
case System: { render_system(canvas, bottom); break; }
|
||||
default:
|
||||
case Custom: { render_custom(canvas, bottom); break; }
|
||||
#else
|
||||
case System: { render_system(canvas, theta > 90.0f); break; }
|
||||
default:
|
||||
case Custom: { render_custom(canvas, theta > 90.0f); break; }
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
}
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
@ -341,10 +345,26 @@ void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox)
|
||||
printf("Unable to create bed grid lines\n");
|
||||
}
|
||||
|
||||
Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const
|
||||
static std::string system_print_bed_model(const Preset &preset)
|
||||
{
|
||||
EType type = Custom;
|
||||
std::string out;
|
||||
const VendorProfile::PrinterModel *pm = PresetUtils::system_printer_model(preset);
|
||||
if (pm != nullptr && ! pm->bed_model.empty())
|
||||
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_model;
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::string system_print_bed_texture(const Preset &preset)
|
||||
{
|
||||
std::string out;
|
||||
const VendorProfile::PrinterModel *pm = PresetUtils::system_printer_model(preset);
|
||||
if (pm != nullptr && ! pm->bed_texture.empty())
|
||||
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_texture;
|
||||
return out;
|
||||
}
|
||||
|
||||
std::tuple<Bed3D::EType, std::string, std::string> Bed3D::detect_type(const Pointfs& shape) const
|
||||
{
|
||||
auto bundle = wxGetApp().preset_bundle;
|
||||
if (bundle != nullptr)
|
||||
{
|
||||
@ -353,39 +373,12 @@ Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const
|
||||
{
|
||||
if (curr->config.has("bed_shape"))
|
||||
{
|
||||
if (curr->vendor != nullptr)
|
||||
if (shape == dynamic_cast<const ConfigOptionPoints*>(curr->config.option("bed_shape"))->values)
|
||||
{
|
||||
if ((curr->vendor->name == "Prusa Research") && (shape == dynamic_cast<const ConfigOptionPoints*>(curr->config.option("bed_shape"))->values))
|
||||
{
|
||||
if (boost::contains(curr->name, "SL1"))
|
||||
{
|
||||
type = SL1;
|
||||
break;
|
||||
}
|
||||
else if (boost::contains(curr->name, "MK3") || boost::contains(curr->name, "MK2.5"))
|
||||
{
|
||||
type = MK3;
|
||||
break;
|
||||
}
|
||||
else if (boost::contains(curr->name, "MK2"))
|
||||
{
|
||||
type = MK2;
|
||||
break;
|
||||
}
|
||||
else if (boost::contains(curr->name, "MINI"))
|
||||
{
|
||||
type = MINI;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((curr->vendor->name == "Creality") && (shape == dynamic_cast<const ConfigOptionPoints*>(curr->config.option("bed_shape"))->values))
|
||||
{
|
||||
if (boost::contains(curr->name, "ENDER-3"))
|
||||
{
|
||||
type = ENDER3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::string model_filename = system_print_bed_model(*curr);
|
||||
std::string texture_filename = system_print_bed_texture(*curr);
|
||||
if (!model_filename.empty() && !texture_filename.empty())
|
||||
return std::make_tuple(System, model_filename, texture_filename);
|
||||
}
|
||||
}
|
||||
|
||||
@ -393,7 +386,7 @@ Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
return std::make_tuple(Custom, "", "");
|
||||
}
|
||||
|
||||
void Bed3D::render_axes() const
|
||||
@ -402,35 +395,35 @@ void Bed3D::render_axes() const
|
||||
m_axes.render();
|
||||
}
|
||||
|
||||
void Bed3D::render_prusa(GLCanvas3D& canvas, const std::string& key, bool bottom) const
|
||||
void Bed3D::render_system(GLCanvas3D& canvas, bool bottom) const
|
||||
{
|
||||
if (!bottom)
|
||||
render_model(m_custom_model.empty() ? resources_dir() + "/models/" + key + "_bed.stl" : m_custom_model);
|
||||
render_model();
|
||||
|
||||
render_texture(m_custom_texture.empty() ? resources_dir() + "/icons/bed/" + key + ".svg" : m_custom_texture, bottom, canvas);
|
||||
render_texture(bottom, canvas);
|
||||
}
|
||||
|
||||
void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D& canvas) const
|
||||
void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
||||
{
|
||||
if (filename.empty())
|
||||
if (m_texture_filename.empty())
|
||||
{
|
||||
m_texture.reset();
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_texture.get_id() == 0) || (m_texture.get_source() != filename))
|
||||
if ((m_texture.get_id() == 0) || (m_texture.get_source() != m_texture_filename))
|
||||
{
|
||||
m_texture.reset();
|
||||
|
||||
if (boost::algorithm::iends_with(filename, ".svg"))
|
||||
if (boost::algorithm::iends_with(m_texture_filename, ".svg"))
|
||||
{
|
||||
// use higher resolution images if graphic card and opengl version allow
|
||||
GLint max_tex_size = GLCanvas3DManager::get_gl_info().get_max_tex_size();
|
||||
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != filename))
|
||||
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename))
|
||||
{
|
||||
// generate a temporary lower resolution texture to show while no main texture levels have been compressed
|
||||
if (!m_temp_texture.load_from_svg_file(filename, false, false, false, max_tex_size / 8))
|
||||
if (!m_temp_texture.load_from_svg_file(m_texture_filename, false, false, false, max_tex_size / 8))
|
||||
{
|
||||
render_default(bottom);
|
||||
return;
|
||||
@ -439,18 +432,18 @@ void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D&
|
||||
}
|
||||
|
||||
// starts generating the main texture, compression will run asynchronously
|
||||
if (!m_texture.load_from_svg_file(filename, true, true, true, max_tex_size))
|
||||
if (!m_texture.load_from_svg_file(m_texture_filename, true, true, true, max_tex_size))
|
||||
{
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (boost::algorithm::iends_with(filename, ".png"))
|
||||
else if (boost::algorithm::iends_with(m_texture_filename, ".png"))
|
||||
{
|
||||
// generate a temporary lower resolution texture to show while no main texture levels have been compressed
|
||||
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != filename))
|
||||
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename))
|
||||
{
|
||||
if (!m_temp_texture.load_from_file(filename, false, GLTexture::None, false))
|
||||
if (!m_temp_texture.load_from_file(m_texture_filename, false, GLTexture::None, false))
|
||||
{
|
||||
render_default(bottom);
|
||||
return;
|
||||
@ -459,7 +452,7 @@ void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D&
|
||||
}
|
||||
|
||||
// starts generating the main texture, compression will run asynchronously
|
||||
if (!m_texture.load_from_file(filename, true, GLTexture::MultiThreaded, true))
|
||||
if (!m_texture.load_from_file(m_texture_filename, true, GLTexture::MultiThreaded, true))
|
||||
{
|
||||
render_default(bottom);
|
||||
return;
|
||||
@ -558,12 +551,12 @@ void Bed3D::render_texture(const std::string& filename, bool bottom, GLCanvas3D&
|
||||
}
|
||||
}
|
||||
|
||||
void Bed3D::render_model(const std::string& filename) const
|
||||
void Bed3D::render_model() const
|
||||
{
|
||||
if (filename.empty())
|
||||
if (m_model_filename.empty())
|
||||
return;
|
||||
|
||||
if ((m_model.get_filename() != filename) && m_model.init_from_file(filename))
|
||||
if ((m_model.get_filename() != m_model_filename) && m_model.init_from_file(m_model_filename))
|
||||
{
|
||||
// move the model so that its origin (0.0, 0.0, 0.0) goes into the bed shape center and a bit down to avoid z-fighting with the texture quad
|
||||
Vec3d shift = m_bounding_box.center();
|
||||
@ -584,16 +577,16 @@ void Bed3D::render_model(const std::string& filename) const
|
||||
|
||||
void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) const
|
||||
{
|
||||
if (m_custom_texture.empty() && m_custom_model.empty())
|
||||
if (m_texture_filename.empty() && m_model_filename.empty())
|
||||
{
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bottom)
|
||||
render_model(m_custom_model);
|
||||
render_model();
|
||||
|
||||
render_texture(m_custom_texture, bottom, canvas);
|
||||
render_texture(bottom, canvas);
|
||||
}
|
||||
|
||||
void Bed3D::render_default(bool bottom) const
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include "3DScene.hpp"
|
||||
#include "GLShader.hpp"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
class GLUquadric;
|
||||
typedef class GLUquadric GLUquadricObj;
|
||||
|
||||
@ -64,11 +66,7 @@ class Bed3D
|
||||
public:
|
||||
enum EType : unsigned char
|
||||
{
|
||||
MK2,
|
||||
MK3,
|
||||
SL1,
|
||||
MINI,
|
||||
ENDER3,
|
||||
System,
|
||||
Custom,
|
||||
Num_Types
|
||||
};
|
||||
@ -76,19 +74,19 @@ public:
|
||||
private:
|
||||
EType m_type;
|
||||
Pointfs m_shape;
|
||||
std::string m_custom_texture;
|
||||
std::string m_custom_model;
|
||||
std::string m_texture_filename;
|
||||
std::string m_model_filename;
|
||||
mutable BoundingBoxf3 m_bounding_box;
|
||||
mutable BoundingBoxf3 m_extended_bounding_box;
|
||||
Polygon m_polygon;
|
||||
GeometryBuffer m_triangles;
|
||||
GeometryBuffer m_gridlines;
|
||||
mutable GLTexture m_texture;
|
||||
mutable GLBed m_model;
|
||||
// temporary texture shown until the main texture has still no levels compressed
|
||||
mutable GLTexture m_temp_texture;
|
||||
mutable Shader m_shader;
|
||||
mutable unsigned int m_vbo_id;
|
||||
mutable GLBed m_model;
|
||||
Axes m_axes;
|
||||
|
||||
mutable float m_scale_factor;
|
||||
@ -99,7 +97,6 @@ public:
|
||||
|
||||
EType get_type() const { return m_type; }
|
||||
|
||||
bool is_prusa() const { return (m_type == MK2) || (m_type == MK3) || (m_type == SL1); }
|
||||
bool is_custom() const { return m_type == Custom; }
|
||||
|
||||
const Pointfs& get_shape() const { return m_shape; }
|
||||
@ -110,17 +107,21 @@ public:
|
||||
bool contains(const Point& point) const;
|
||||
Point point_projection(const Point& point) const;
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
void render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) const;
|
||||
#else
|
||||
void render(GLCanvas3D& canvas, float theta, float scale_factor, bool show_axes) const;
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
private:
|
||||
void calc_bounding_boxes() const;
|
||||
void calc_triangles(const ExPolygon& poly);
|
||||
void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox);
|
||||
EType detect_type(const Pointfs& shape) const;
|
||||
std::tuple<EType, std::string, std::string> detect_type(const Pointfs& shape) const;
|
||||
void render_axes() const;
|
||||
void render_prusa(GLCanvas3D& canvas, const std::string& key, bool bottom) const;
|
||||
void render_texture(const std::string& filename, bool bottom, GLCanvas3D& canvas) const;
|
||||
void render_model(const std::string& filename) const;
|
||||
void render_system(GLCanvas3D& canvas, bool bottom) const;
|
||||
void render_texture(bool bottom, GLCanvas3D& canvas) const;
|
||||
void render_model() const;
|
||||
void render_custom(GLCanvas3D& canvas, bool bottom) const;
|
||||
void render_default(bool bottom) const;
|
||||
void reset();
|
||||
|
@ -877,13 +877,10 @@ bool can_export_to_obj(const GLVolume& volume)
|
||||
if (!volume.is_active || !volume.is_extrusion_path)
|
||||
return false;
|
||||
|
||||
if (volume.indexed_vertex_array.triangle_indices.empty() && (std::min(volume.indexed_vertex_array.triangle_indices_size, volume.tverts_range.second - volume.tverts_range.first) == 0))
|
||||
return false;
|
||||
bool has_triangles = !volume.indexed_vertex_array.triangle_indices.empty() || (std::min(volume.indexed_vertex_array.triangle_indices_size, volume.tverts_range.second - volume.tverts_range.first) > 0);
|
||||
bool has_quads = !volume.indexed_vertex_array.quad_indices.empty() || (std::min(volume.indexed_vertex_array.quad_indices_size, volume.qverts_range.second - volume.qverts_range.first) > 0);
|
||||
|
||||
if (volume.indexed_vertex_array.quad_indices.empty() && (std::min(volume.indexed_vertex_array.quad_indices_size, volume.qverts_range.second - volume.qverts_range.first) == 0))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return has_triangles || has_quads;
|
||||
}
|
||||
|
||||
bool GLVolumeCollection::has_toolpaths_to_export() const
|
||||
|
@ -61,6 +61,11 @@ void AppConfig::set_defaults()
|
||||
if (get("preset_update").empty())
|
||||
set("preset_update", "1");
|
||||
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
if (get("export_sources_full_pathnames").empty())
|
||||
set("export_sources_full_pathnames", "0");
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
|
||||
// remove old 'use_legacy_opengl' parameter from this config, if present
|
||||
if (!get("use_legacy_opengl").empty())
|
||||
erase("", "use_legacy_opengl");
|
||||
@ -82,6 +87,11 @@ void AppConfig::set_defaults()
|
||||
if (get("use_perspective_camera").empty())
|
||||
set("use_perspective_camera", "1");
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
if (get("use_free_camera").empty())
|
||||
set("use_free_camera", "0");
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
// Remove legacy window positions/sizes
|
||||
erase("", "main_frame_maximized");
|
||||
erase("", "main_frame_pos");
|
||||
|
@ -95,14 +95,6 @@ void BackgroundSlicingProcess::process_fff()
|
||||
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
/* #ys_FIXME_no_exported_codes
|
||||
if (m_fff_print->model().custom_gcode_per_print_z != GUI::wxGetApp().model().custom_gcode_per_print_z) {
|
||||
GUI::wxGetApp().model().custom_gcode_per_print_z = m_fff_print->model().custom_gcode_per_print_z;
|
||||
GUI::show_info(nullptr, _(L("To except of redundant tool manipulation, \n"
|
||||
"Color change(s) for unused extruder(s) was(were) deleted")), _(L("Info")));
|
||||
}
|
||||
*/
|
||||
|
||||
if (this->set_step_started(bspsGCodeFinalize)) {
|
||||
if (! m_export_path.empty()) {
|
||||
//FIXME localize the messages
|
||||
|
@ -53,11 +53,11 @@ public:
|
||||
void set_thumbnail_cb(ThumbnailsGeneratorCallback cb) { m_thumbnail_cb = cb; }
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// The following wxCommandEvent will be sent to the UI thread / Platter window, when the slicing is finished
|
||||
// The following wxCommandEvent will be sent to the UI thread / Plater window, when the slicing is finished
|
||||
// and the background processing will transition into G-code export.
|
||||
// The wxCommandEvent is sent to the UI thread asynchronously without waiting for the event to be processed.
|
||||
void set_slicing_completed_event(int event_id) { m_event_slicing_completed_id = event_id; }
|
||||
// The following wxCommandEvent will be sent to the UI thread / Platter window, when the G-code export is finished.
|
||||
// The following wxCommandEvent will be sent to the UI thread / Plater window, when the G-code export is finished.
|
||||
// The wxCommandEvent is sent to the UI thread asynchronously without waiting for the event to be processed.
|
||||
void set_finished_event(int event_id) { m_event_finished_id = event_id; }
|
||||
|
||||
@ -132,11 +132,6 @@ public:
|
||||
// This "finished" flag does not account for the final export of the output file (.gcode or zipped PNGs),
|
||||
// and it does not account for the OctoPrint scheduling.
|
||||
bool finished() const { return m_print->finished(); }
|
||||
|
||||
void set_force_update_print_regions(bool force_update_print_regions) {
|
||||
if (m_fff_print)
|
||||
m_fff_print->set_force_update_print_regions(force_update_print_regions);
|
||||
}
|
||||
|
||||
private:
|
||||
void thread_proc();
|
||||
@ -191,9 +186,9 @@ private:
|
||||
void throw_if_canceled() const { if (m_print->canceled()) throw CanceledException(); }
|
||||
void prepare_upload();
|
||||
|
||||
// wxWidgets command ID to be sent to the platter to inform that the slicing is finished, and the G-code export will continue.
|
||||
// wxWidgets command ID to be sent to the plater to inform that the slicing is finished, and the G-code export will continue.
|
||||
int m_event_slicing_completed_id = 0;
|
||||
// wxWidgets command ID to be sent to the platter to inform that the task finished.
|
||||
// wxWidgets command ID to be sent to the plater to inform that the task finished.
|
||||
int m_event_finished_id = 0;
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "BitmapCache.hpp"
|
||||
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#if ! defined(WIN32) && ! defined(__APPLE__)
|
||||
#define BROKEN_ALPHA
|
||||
@ -15,7 +16,7 @@
|
||||
#include "nanosvg/nanosvg.h"
|
||||
#define NANOSVGRAST_IMPLEMENTATION
|
||||
#include "nanosvg/nanosvgrast.h"
|
||||
#include "GUI_App.hpp"
|
||||
//#include "GUI_App.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
@ -226,7 +227,7 @@ wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned width,
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_width, unsigned target_height,
|
||||
float scale /* = 1.0f */, const bool grayscale/* = false*/)
|
||||
float scale /* = 1.0f */, const bool grayscale/* = false*/, const bool dark_mode/* = false*/)
|
||||
{
|
||||
std::string bitmap_key = bitmap_name + ( target_height !=0 ?
|
||||
"-h" + std::to_string(target_height) :
|
||||
@ -234,16 +235,45 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_
|
||||
+ (scale != 1.0f ? "-s" + std::to_string(scale) : "")
|
||||
+ (grayscale ? "-gs" : "");
|
||||
|
||||
target_height != 0 ? target_height *= scale : target_width *= scale;
|
||||
/* For the Dark mode of any platform, we should draw icons in respect to OS background
|
||||
* Note: All standard(regular) icons are collected in "icons" folder,
|
||||
* SVG-icons, which have "Dark mode" variant, are collected in "icons/white" folder
|
||||
*/
|
||||
std::string folder;
|
||||
if (dark_mode)
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
folder = "white\\";
|
||||
#else
|
||||
folder = "white/";
|
||||
#endif
|
||||
auto it = m_map.find(folder + bitmap_key);
|
||||
if (it != m_map.end())
|
||||
return it->second;
|
||||
else {
|
||||
it = m_map.find(bitmap_key);
|
||||
if (it != m_map.end())
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto it = m_map.find(bitmap_key);
|
||||
if (it != m_map.end())
|
||||
return it->second;
|
||||
if (!boost::filesystem::exists(Slic3r::var(folder + bitmap_name + ".svg")))
|
||||
folder.clear();
|
||||
else
|
||||
bitmap_key = folder + bitmap_key;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = m_map.find(bitmap_key);
|
||||
if (it != m_map.end())
|
||||
return it->second;
|
||||
}
|
||||
|
||||
NSVGimage *image = ::nsvgParseFromFile(Slic3r::var(bitmap_name + ".svg").c_str(), "px", 96.0f);
|
||||
NSVGimage *image = ::nsvgParseFromFile(Slic3r::var(folder + bitmap_name + ".svg").c_str(), "px", 96.0f);
|
||||
if (image == nullptr)
|
||||
return nullptr;
|
||||
|
||||
target_height != 0 ? target_height *= scale : target_width *= scale;
|
||||
|
||||
float svg_scale = target_height != 0 ?
|
||||
(float)target_height / image->height : target_width != 0 ?
|
||||
(float)target_width / image->width : 1;
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
// Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height/width if nonzero.
|
||||
wxBitmap* load_png(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false);
|
||||
// Load svg from resources/icons. bitmap_key is given without the .svg suffix. SVG will be rasterized to provided height/width.
|
||||
wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, float scale = 1.0f, const bool grayscale = false);
|
||||
wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, float scale = 1.0f, const bool grayscale = false, const bool dark_mode = false);
|
||||
|
||||
static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency);
|
||||
static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); }
|
||||
|
@ -6,6 +6,11 @@
|
||||
#endif // !ENABLE_THUMBNAIL_GENERATOR
|
||||
#include "GUI_App.hpp"
|
||||
#include "AppConfig.hpp"
|
||||
#if ENABLE_CAMERA_STATISTICS
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
#include "Mouse3DController.hpp"
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
#endif // ENABLE_CAMERA_STATISTICS
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
@ -34,18 +39,27 @@ double Camera::FrustrumZMargin = 10.0;
|
||||
double Camera::MaxFovDeg = 60.0;
|
||||
|
||||
Camera::Camera()
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
: requires_zoom_to_bed(false)
|
||||
#else
|
||||
: phi(45.0f)
|
||||
, requires_zoom_to_bed(false)
|
||||
, inverted_phi(false)
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
, m_type(Perspective)
|
||||
, m_target(Vec3d::Zero())
|
||||
#if !ENABLE_6DOF_CAMERA
|
||||
, m_theta(45.0f)
|
||||
#endif // !ENABLE_6DOF_CAMERA
|
||||
, m_zoom(1.0)
|
||||
, m_distance(DefaultDistance)
|
||||
, m_gui_scale(1.0)
|
||||
, m_view_matrix(Transform3d::Identity())
|
||||
, m_projection_matrix(Transform3d::Identity())
|
||||
{
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
set_default_orientation();
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
}
|
||||
|
||||
std::string Camera::get_type_as_string() const
|
||||
@ -91,6 +105,9 @@ void Camera::select_next_type()
|
||||
|
||||
void Camera::set_target(const Vec3d& target)
|
||||
{
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
translate_world(target - m_target);
|
||||
#else
|
||||
BoundingBoxf3 test_box = m_scene_box;
|
||||
test_box.translate(-m_scene_box.center());
|
||||
// We may let this factor be customizable
|
||||
@ -101,8 +118,10 @@ void Camera::set_target(const Vec3d& target)
|
||||
m_target(0) = clamp(test_box.min(0), test_box.max(0), target(0));
|
||||
m_target(1) = clamp(test_box.min(1), test_box.max(1), target(1));
|
||||
m_target(2) = clamp(test_box.min(2), test_box.max(2), target(2));
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
}
|
||||
|
||||
#if !ENABLE_6DOF_CAMERA
|
||||
void Camera::set_theta(float theta, bool apply_limit)
|
||||
{
|
||||
if (apply_limit)
|
||||
@ -114,6 +133,7 @@ void Camera::set_theta(float theta, bool apply_limit)
|
||||
m_theta += 360.0f;
|
||||
}
|
||||
}
|
||||
#endif // !ENABLE_6DOF_CAMERA
|
||||
|
||||
void Camera::update_zoom(double delta_zoom)
|
||||
{
|
||||
@ -123,14 +143,33 @@ void Camera::update_zoom(double delta_zoom)
|
||||
void Camera::set_zoom(double zoom)
|
||||
{
|
||||
// Don't allow to zoom too far outside the scene.
|
||||
double zoom_min = calc_zoom_to_bounding_box_factor(m_scene_box, (int)m_viewport[2], (int)m_viewport[3]);
|
||||
double zoom_min = min_zoom();
|
||||
if (zoom_min > 0.0)
|
||||
zoom = std::max(zoom, zoom_min * 0.7);
|
||||
zoom = std::max(zoom, zoom_min);
|
||||
|
||||
// Don't allow to zoom too close to the scene.
|
||||
m_zoom = std::min(zoom, 100.0);
|
||||
m_zoom = std::min(zoom, max_zoom());
|
||||
}
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
void Camera::select_view(const std::string& direction)
|
||||
{
|
||||
if (direction == "iso")
|
||||
set_default_orientation();
|
||||
else if (direction == "left")
|
||||
m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitX(), m_target, Vec3d::UnitZ());
|
||||
else if (direction == "right")
|
||||
m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitX(), m_target, Vec3d::UnitZ());
|
||||
else if (direction == "top")
|
||||
m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitZ(), m_target, Vec3d::UnitY());
|
||||
else if (direction == "bottom")
|
||||
m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitZ(), m_target, -Vec3d::UnitY());
|
||||
else if (direction == "front")
|
||||
m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitY(), m_target, Vec3d::UnitZ());
|
||||
else if (direction == "rear")
|
||||
m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitY(), m_target, Vec3d::UnitZ());
|
||||
}
|
||||
#else
|
||||
bool Camera::select_view(const std::string& direction)
|
||||
{
|
||||
const float* dir_vec = nullptr;
|
||||
@ -159,6 +198,7 @@ bool Camera::select_view(const std::string& direction)
|
||||
else
|
||||
return false;
|
||||
}
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
double Camera::get_fov() const
|
||||
{
|
||||
@ -180,20 +220,26 @@ void Camera::apply_viewport(int x, int y, unsigned int w, unsigned int h) const
|
||||
|
||||
void Camera::apply_view_matrix() const
|
||||
{
|
||||
#if !ENABLE_6DOF_CAMERA
|
||||
double theta_rad = Geometry::deg2rad(-(double)m_theta);
|
||||
double phi_rad = Geometry::deg2rad((double)phi);
|
||||
double sin_theta = ::sin(theta_rad);
|
||||
Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad));
|
||||
#endif // !ENABLE_6DOF_CAMERA
|
||||
|
||||
glsafe(::glMatrixMode(GL_MODELVIEW));
|
||||
glsafe(::glLoadIdentity());
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
glsafe(::glMultMatrixd(m_view_matrix.data()));
|
||||
#else
|
||||
glsafe(::glRotatef(-m_theta, 1.0f, 0.0f, 0.0f)); // pitch
|
||||
glsafe(::glRotatef(phi, 0.0f, 0.0f, 1.0f)); // yaw
|
||||
|
||||
glsafe(::glTranslated(-camera_pos(0), -camera_pos(1), -camera_pos(2)));
|
||||
|
||||
glsafe(::glGetDoublev(GL_MODELVIEW_MATRIX, m_view_matrix.data()));
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
}
|
||||
|
||||
void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double far_z) const
|
||||
@ -300,7 +346,11 @@ void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h)
|
||||
{
|
||||
m_zoom = zoom;
|
||||
// center view around box center
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
set_target(box.center());
|
||||
#else
|
||||
m_target = box.center();
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,7 +363,11 @@ void Camera::zoom_to_volumes(const GLVolumePtrs& volumes, int canvas_w, int canv
|
||||
{
|
||||
m_zoom = zoom;
|
||||
// center view around the calculated center
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
set_target(center);
|
||||
#else
|
||||
m_target = center;
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
@ -325,6 +379,12 @@ void Camera::debug_render() const
|
||||
imgui.begin(std::string("Camera statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
std::string type = get_type_as_string();
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
if (wxGetApp().plater()->get_mouse3d_controller().is_running() || (wxGetApp().app_config->get("use_free_camera") == "1"))
|
||||
type += "/free";
|
||||
else
|
||||
type += "/constrained";
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
Vec3f position = get_position().cast<float>();
|
||||
Vec3f target = m_target.cast<float>();
|
||||
float distance = (float)get_distance();
|
||||
@ -360,6 +420,50 @@ void Camera::debug_render() const
|
||||
}
|
||||
#endif // ENABLE_CAMERA_STATISTICS
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
void Camera::translate_world(const Vec3d& displacement)
|
||||
{
|
||||
Vec3d new_target = validate_target(m_target + displacement);
|
||||
Vec3d new_displacement = new_target - m_target;
|
||||
if (!new_displacement.isApprox(Vec3d::Zero()))
|
||||
{
|
||||
m_target += new_displacement;
|
||||
m_view_matrix.translate(-new_displacement);
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad)
|
||||
{
|
||||
Vec3d target = m_target;
|
||||
translate_world(-target);
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(delta_zenit_rad, get_dir_right()));
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ()));
|
||||
translate_world(target);
|
||||
}
|
||||
|
||||
void Camera::rotate_local_around_target(const Vec3d& rotation_rad)
|
||||
{
|
||||
rotate_local_around_pivot(rotation_rad, m_target);
|
||||
}
|
||||
|
||||
void Camera::rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot)
|
||||
{
|
||||
// we use a copy of the pivot because a reference to the current m_target may be passed in (see i.e. rotate_local_around_target())
|
||||
// and m_target is modified by the translate_world() calls
|
||||
Vec3d center = pivot;
|
||||
translate_world(-center);
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(0), get_dir_right()));
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(1), get_dir_up()));
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(2), get_dir_forward()));
|
||||
translate_world(center);
|
||||
}
|
||||
|
||||
double Camera::min_zoom() const
|
||||
{
|
||||
return 0.7 * calc_zoom_to_bounding_box_factor(m_scene_box, (int)m_viewport[2], (int)m_viewport[3]);
|
||||
}
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
std::pair<double, double> Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const
|
||||
{
|
||||
std::pair<double, double> ret;
|
||||
@ -540,6 +644,63 @@ void Camera::set_distance(double distance) const
|
||||
apply_view_matrix();
|
||||
}
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
Transform3d Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up) const
|
||||
{
|
||||
Vec3d unit_z = (position - target).normalized();
|
||||
Vec3d unit_x = up.cross(unit_z).normalized();
|
||||
Vec3d unit_y = unit_z.cross(unit_x).normalized();
|
||||
|
||||
Transform3d matrix;
|
||||
|
||||
matrix(0, 0) = unit_x(0);
|
||||
matrix(0, 1) = unit_x(1);
|
||||
matrix(0, 2) = unit_x(2);
|
||||
matrix(0, 3) = -unit_x.dot(position);
|
||||
|
||||
matrix(1, 0) = unit_y(0);
|
||||
matrix(1, 1) = unit_y(1);
|
||||
matrix(1, 2) = unit_y(2);
|
||||
matrix(1, 3) = -unit_y.dot(position);
|
||||
|
||||
matrix(2, 0) = unit_z(0);
|
||||
matrix(2, 1) = unit_z(1);
|
||||
matrix(2, 2) = unit_z(2);
|
||||
matrix(2, 3) = -unit_z.dot(position);
|
||||
|
||||
matrix(3, 0) = 0.0;
|
||||
matrix(3, 1) = 0.0;
|
||||
matrix(3, 2) = 0.0;
|
||||
matrix(3, 3) = 1.0;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
void Camera::set_default_orientation()
|
||||
{
|
||||
double theta_rad = Geometry::deg2rad(-45.0);
|
||||
double phi_rad = Geometry::deg2rad(45.0);
|
||||
double sin_theta = ::sin(theta_rad);
|
||||
Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad));
|
||||
m_view_matrix = Transform3d::Identity();
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(theta_rad, Vec3d::UnitX())).rotate(Eigen::AngleAxisd(phi_rad, Vec3d::UnitZ())).translate(-camera_pos);
|
||||
}
|
||||
|
||||
Vec3d Camera::validate_target(const Vec3d& target) const
|
||||
{
|
||||
BoundingBoxf3 test_box = m_scene_box;
|
||||
test_box.translate(-m_scene_box.center());
|
||||
// We may let this factor be customizable
|
||||
static const double ScaleFactor = 1.5;
|
||||
test_box.scale(ScaleFactor);
|
||||
test_box.translate(m_scene_box.center());
|
||||
|
||||
return Vec3d(std::clamp(target(0), test_box.min(0), test_box.max(0)),
|
||||
std::clamp(target(1), test_box.min(1), test_box.max(1)),
|
||||
std::clamp(target(2), test_box.min(2), test_box.max(2)));
|
||||
}
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
|
@ -30,21 +30,29 @@ struct Camera
|
||||
Num_types
|
||||
};
|
||||
|
||||
#if !ENABLE_6DOF_CAMERA
|
||||
float phi;
|
||||
bool requires_zoom_to_bed;
|
||||
bool inverted_phi;
|
||||
#endif // !ENABLE_6DOF_CAMERA
|
||||
bool requires_zoom_to_bed;
|
||||
|
||||
private:
|
||||
EType m_type;
|
||||
Vec3d m_target;
|
||||
#if !ENABLE_6DOF_CAMERA
|
||||
float m_theta;
|
||||
#endif // !ENABLE_6DOF_CAMERA
|
||||
double m_zoom;
|
||||
// Distance between camera position and camera target measured along the camera Z axis
|
||||
mutable double m_distance;
|
||||
mutable double m_gui_scale;
|
||||
|
||||
mutable std::array<int, 4> m_viewport;
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
Transform3d m_view_matrix;
|
||||
#else
|
||||
mutable Transform3d m_view_matrix;
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
mutable Transform3d m_projection_matrix;
|
||||
mutable std::pair<double, double> m_frustrum_zs;
|
||||
|
||||
@ -66,17 +74,24 @@ public:
|
||||
double get_distance() const { return m_distance; }
|
||||
double get_gui_scale() const { return m_gui_scale; }
|
||||
|
||||
#if !ENABLE_6DOF_CAMERA
|
||||
float get_theta() const { return m_theta; }
|
||||
void set_theta(float theta, bool apply_limit);
|
||||
#endif // !ENABLE_6DOF_CAMERA
|
||||
|
||||
double get_zoom() const { return m_zoom; }
|
||||
double get_inv_zoom() const { assert(m_zoom != 0.0); return 1.0 / m_zoom; }
|
||||
void update_zoom(double delta_zoom);
|
||||
void set_zoom(double zoom);
|
||||
|
||||
const BoundingBoxf3& get_scene_box() const { return m_scene_box; }
|
||||
void set_scene_box(const BoundingBoxf3& box) { m_scene_box = box; }
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
void select_view(const std::string& direction);
|
||||
#else
|
||||
bool select_view(const std::string& direction);
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
const std::array<int, 4>& get_viewport() const { return m_viewport; }
|
||||
const Transform3d& get_view_matrix() const { return m_view_matrix; }
|
||||
@ -110,6 +125,27 @@ public:
|
||||
void debug_render() const;
|
||||
#endif // ENABLE_CAMERA_STATISTICS
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
// translate the camera in world space
|
||||
void translate_world(const Vec3d& displacement);
|
||||
|
||||
// rotate the camera on a sphere having center == m_target and radius == m_distance
|
||||
// using the given variations of spherical coordinates
|
||||
void rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad);
|
||||
|
||||
// rotate the camera around three axes parallel to the camera local axes and passing through m_target
|
||||
void rotate_local_around_target(const Vec3d& rotation_rad);
|
||||
|
||||
// rotate the camera around three axes parallel to the camera local axes and passing through the given pivot point
|
||||
void rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot);
|
||||
|
||||
// returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis
|
||||
bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; }
|
||||
|
||||
double max_zoom() const { return 100.0; }
|
||||
double min_zoom() const;
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
private:
|
||||
// returns tight values for nearZ and farZ plane around the given bounding box
|
||||
// the camera MUST be outside of the bounding box in eye coordinate of the given box
|
||||
@ -121,6 +157,12 @@ private:
|
||||
double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const;
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
void set_distance(double distance) const;
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
Transform3d look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up) const;
|
||||
void set_default_orientation();
|
||||
Vec3d validate_target(const Vec3d& target) const;
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
};
|
||||
|
||||
} // GUI
|
||||
|
@ -350,6 +350,21 @@ bool PrinterPicker::any_selected() const
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<std::string> PrinterPicker::get_selected_models() const
|
||||
{
|
||||
std::set<std::string> ret_set;
|
||||
|
||||
for (const auto& cb : cboxes)
|
||||
if (cb->GetValue())
|
||||
ret_set.emplace(cb->model);
|
||||
|
||||
for (const auto& cb : cboxes_alt)
|
||||
if (cb->GetValue())
|
||||
ret_set.emplace(cb->model);
|
||||
|
||||
return ret_set;
|
||||
}
|
||||
|
||||
void PrinterPicker::on_checkbox(const Checkbox *cbox, bool checked)
|
||||
{
|
||||
PrinterPickerEvent evt(EVT_PRINTER_PICK, GetId(), vendor_id, cbox->model, cbox->variant, checked);
|
||||
@ -500,6 +515,19 @@ bool PagePrinters::any_selected() const
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<std::string> PagePrinters::get_selected_models()
|
||||
{
|
||||
std::set<std::string> ret_set;
|
||||
|
||||
for (const auto *picker : printer_pickers)
|
||||
{
|
||||
std::set<std::string> tmp_models = picker->get_selected_models();
|
||||
ret_set.insert(tmp_models.begin(), tmp_models.end());
|
||||
}
|
||||
|
||||
return ret_set;
|
||||
}
|
||||
|
||||
void PagePrinters::set_run_reason(ConfigWizard::RunReason run_reason)
|
||||
{
|
||||
if (technology == T_FFF
|
||||
@ -765,6 +793,23 @@ PageUpdate::PageUpdate(ConfigWizard *parent)
|
||||
box_presets->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { this->preset_update = event.IsChecked(); });
|
||||
}
|
||||
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
PageReloadFromDisk::PageReloadFromDisk(ConfigWizard* parent)
|
||||
: ConfigWizardPage(parent, _(L("Reload from disk")), _(L("Reload from disk")))
|
||||
, full_pathnames(false)
|
||||
{
|
||||
auto* box_pathnames = new wxCheckBox(this, wxID_ANY, _(L("Export full pathnames of models and parts sources into 3mf and amf files")));
|
||||
box_pathnames->SetValue(wxGetApp().app_config->get("export_sources_full_pathnames") == "1");
|
||||
append(box_pathnames);
|
||||
append_text(_(L(
|
||||
"If enabled, allows the Reload from disk command to automatically find and load the files when invoked.\n"
|
||||
"If not enabled, the Reload from disk command will ask to select each file using an open file dialog."
|
||||
)));
|
||||
|
||||
box_pathnames->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& event) { this->full_pathnames = event.IsChecked(); });
|
||||
}
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
|
||||
PageMode::PageMode(ConfigWizard *parent)
|
||||
: ConfigWizardPage(parent, _(L("View mode")), _(L("View mode")))
|
||||
{
|
||||
@ -1356,6 +1401,9 @@ void ConfigWizard::priv::load_pages()
|
||||
btn_finish->Enable(any_fff_selected || any_sla_selected);
|
||||
|
||||
index->add_page(page_update);
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
index->add_page(page_reload_from_disk);
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
index->add_page(page_mode);
|
||||
|
||||
index->go_to(former_active); // Will restore the active item/page if possible
|
||||
@ -1580,6 +1628,10 @@ void ConfigWizard::priv::on_printer_pick(PagePrinters *page, const PrinterPicker
|
||||
preset.is_visible = evt.enable;
|
||||
}
|
||||
}
|
||||
|
||||
// if at list one printer is selected but there in no one selected material,
|
||||
// select materials which is default for selected printer(s)
|
||||
select_default_materials_if_needed(pair.second.vendor_profile, page->technology, evt.model_id);
|
||||
}
|
||||
|
||||
if (page->technology & T_FFF) {
|
||||
@ -1589,6 +1641,57 @@ void ConfigWizard::priv::on_printer_pick(PagePrinters *page, const PrinterPicker
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigWizard::priv::select_default_materials_for_printer_model(const std::vector<VendorProfile::PrinterModel>& models, Technology technology, const std::string& model_id)
|
||||
{
|
||||
PageMaterials* page_materials = technology & T_FFF ? page_filaments : page_sla_materials;
|
||||
|
||||
auto it = std::find_if(models.begin(), models.end(), [model_id](VendorProfile::PrinterModel model) {return model_id == model.id; });
|
||||
if (it != models.end())
|
||||
for (const std::string& material : it->default_materials)
|
||||
appconfig_new.set(page_materials->materials->appconfig_section(), material, "1");
|
||||
}
|
||||
|
||||
void ConfigWizard::priv::select_default_materials_if_needed(VendorProfile* vendor_profile, Technology technology, const std::string& model_id)
|
||||
{
|
||||
if ((technology & T_FFF && !any_fff_selected) ||
|
||||
(technology & T_SLA && !any_sla_selected) ||
|
||||
check_materials_in_config(technology, false))
|
||||
return;
|
||||
|
||||
select_default_materials_for_printer_model(vendor_profile->models, technology, model_id);
|
||||
}
|
||||
|
||||
void ConfigWizard::priv::selected_default_materials(Technology technology)
|
||||
{
|
||||
auto select_default_materials_for_printer_page = [this](PagePrinters * page_printers, Technology technology)
|
||||
{
|
||||
std::set<std::string> selected_models = page_printers->get_selected_models();
|
||||
const std::string vendor_id = page_printers->get_vendor_id();
|
||||
|
||||
for (auto& pair : bundles)
|
||||
{
|
||||
if (pair.first != vendor_id)
|
||||
continue;
|
||||
|
||||
for (const std::string& model_id : selected_models)
|
||||
select_default_materials_for_printer_model(pair.second.vendor_profile->models, technology, model_id);
|
||||
}
|
||||
};
|
||||
|
||||
PagePrinters* page_printers = technology & T_FFF ? page_fff : page_msla;
|
||||
select_default_materials_for_printer_page(page_printers, technology);
|
||||
|
||||
for (const auto& printer : pages_3rdparty)
|
||||
{
|
||||
page_printers = technology & T_FFF ? printer.second.first : printer.second.second;
|
||||
if (page_printers)
|
||||
select_default_materials_for_printer_page(page_printers, technology);
|
||||
}
|
||||
|
||||
update_materials(technology);
|
||||
(technology& T_FFF ? page_filaments : page_sla_materials)->reload_presets();
|
||||
}
|
||||
|
||||
void ConfigWizard::priv::on_3rdparty_install(const VendorProfile *vendor, bool install)
|
||||
{
|
||||
auto it = pages_3rdparty.find(vendor->id);
|
||||
@ -1625,7 +1728,7 @@ bool ConfigWizard::priv::on_bnt_finish()
|
||||
return check_materials_in_config(T_ANY);
|
||||
}
|
||||
|
||||
bool ConfigWizard::priv::check_materials_in_config(Technology technology)
|
||||
bool ConfigWizard::priv::check_materials_in_config(Technology technology, bool show_info_msg)
|
||||
{
|
||||
const auto exist_preset = [this](const std::string& section, const Materials& materials)
|
||||
{
|
||||
@ -1640,15 +1743,32 @@ bool ConfigWizard::priv::check_materials_in_config(Technology technology)
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto ask_and_selected_default_materials = [this](wxString message, Technology technology)
|
||||
{
|
||||
wxMessageDialog msg(q, message, _(L("Notice")), wxYES_NO);
|
||||
if (msg.ShowModal() == wxID_YES)
|
||||
selected_default_materials(technology);
|
||||
};
|
||||
|
||||
if (any_fff_selected && technology & T_FFF && !exist_preset(AppConfig::SECTION_FILAMENTS, filaments))
|
||||
{
|
||||
show_info(q, _(L("You have to select at least one filament for selected printers")), "");
|
||||
if (show_info_msg)
|
||||
{
|
||||
wxString message = _(L("You have to select at least one filament for selected printers")) + "\n\n\t" +
|
||||
_(L("Do you want to automatic select default filaments?"));
|
||||
ask_and_selected_default_materials(message, T_FFF);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (any_sla_selected && technology & T_SLA && !exist_preset(AppConfig::SECTION_MATERIALS, sla_materials))
|
||||
{
|
||||
show_info(q, _(L("You have to select at least one material for selected printers")), "");
|
||||
if (show_info_msg)
|
||||
{
|
||||
wxString message = _(L("You have to select at least one material for selected printers")) + "\n\n\t" +
|
||||
_(L("Do you want to automatic select default materials?"));
|
||||
ask_and_selected_default_materials(message, T_SLA);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1730,6 +1850,11 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
|
||||
}
|
||||
app_config->set("version_check", page_update->version_check ? "1" : "0");
|
||||
app_config->set("preset_update", page_update->preset_update ? "1" : "0");
|
||||
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
app_config->set("export_sources_full_pathnames", page_reload_from_disk->full_pathnames ? "1" : "0");
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
|
||||
page_mode->serialize_mode(app_config);
|
||||
|
||||
std::string preferred_model;
|
||||
@ -1885,6 +2010,9 @@ ConfigWizard::ConfigWizard(wxWindow *parent)
|
||||
|
||||
p->add_page(p->page_custom = new PageCustom(this));
|
||||
p->add_page(p->page_update = new PageUpdate(this));
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
p->add_page(p->page_reload_from_disk = new PageReloadFromDisk(this));
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
p->add_page(p->page_mode = new PageMode(this));
|
||||
p->add_page(p->page_firmware = new PageFirmware(this));
|
||||
p->add_page(p->page_bed = new PageBedShape(this));
|
||||
|
@ -149,6 +149,7 @@ struct PrinterPicker: wxPanel
|
||||
void select_all(bool select, bool alternates = false);
|
||||
void select_one(size_t i, bool select);
|
||||
bool any_selected() const;
|
||||
std::set<std::string> get_selected_models() const ;
|
||||
|
||||
int get_width() const { return width; }
|
||||
const std::vector<int>& get_button_indexes() { return m_button_indexes; }
|
||||
@ -215,6 +216,9 @@ struct PagePrinters: ConfigWizardPage
|
||||
void select_all(bool select, bool alternates = false);
|
||||
int get_width() const;
|
||||
bool any_selected() const;
|
||||
std::set<std::string> get_selected_models();
|
||||
|
||||
std::string get_vendor_id() const { return printer_pickers.empty() ? "" : printer_pickers[0]->vendor_id; }
|
||||
|
||||
virtual void set_run_reason(ConfigWizard::RunReason run_reason) override;
|
||||
};
|
||||
@ -301,6 +305,17 @@ struct PageUpdate: ConfigWizardPage
|
||||
PageUpdate(ConfigWizard *parent);
|
||||
};
|
||||
|
||||
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
struct PageReloadFromDisk : ConfigWizardPage
|
||||
{
|
||||
bool full_pathnames;
|
||||
|
||||
PageReloadFromDisk(ConfigWizard* parent);
|
||||
};
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
struct PageMode: ConfigWizardPage
|
||||
{
|
||||
wxRadioButton *radio_simple;
|
||||
@ -455,6 +470,11 @@ struct ConfigWizard::priv
|
||||
PageMaterials *page_sla_materials = nullptr;
|
||||
PageCustom *page_custom = nullptr;
|
||||
PageUpdate *page_update = nullptr;
|
||||
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
PageReloadFromDisk *page_reload_from_disk = nullptr;
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
PageMode *page_mode = nullptr;
|
||||
PageVendors *page_vendors = nullptr;
|
||||
Pages3rdparty pages_3rdparty;
|
||||
@ -487,10 +507,17 @@ struct ConfigWizard::priv
|
||||
|
||||
void on_custom_setup();
|
||||
void on_printer_pick(PagePrinters *page, const PrinterPickerEvent &evt);
|
||||
void select_default_materials_for_printer_model(const std::vector<VendorProfile::PrinterModel> &models,
|
||||
Technology technology,
|
||||
const std::string & model_id);
|
||||
void select_default_materials_if_needed(VendorProfile* vendor_profile,
|
||||
Technology technology,
|
||||
const std::string &model_id);
|
||||
void selected_default_materials(Technology technology);
|
||||
void on_3rdparty_install(const VendorProfile *vendor, bool install);
|
||||
|
||||
bool on_bnt_finish();
|
||||
bool check_materials_in_config(Technology technology);
|
||||
bool check_materials_in_config(Technology technology, bool show_info_msg = true);
|
||||
void apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater);
|
||||
// #ys_FIXME_alise
|
||||
void update_presets_in_config(const std::string& section, const std::string& alias_key, bool add);
|
||||
|
@ -132,9 +132,7 @@ GLCanvas3D::LayersEditing::LayersEditing()
|
||||
, m_object_max_z(0.f)
|
||||
, m_slicing_parameters(nullptr)
|
||||
, m_layer_height_profile_modified(false)
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
, m_adaptive_quality(0.5f)
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
, state(Unknown)
|
||||
, band_width(2.0f)
|
||||
, strength(0.005f)
|
||||
@ -155,9 +153,6 @@ GLCanvas3D::LayersEditing::~LayersEditing()
|
||||
}
|
||||
|
||||
const float GLCanvas3D::LayersEditing::THICKNESS_BAR_WIDTH = 70.0f;
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
const float GLCanvas3D::LayersEditing::THICKNESS_RESET_BUTTON_HEIGHT = 22.0f;
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
bool GLCanvas3D::LayersEditing::init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename)
|
||||
{
|
||||
@ -224,7 +219,6 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f);
|
||||
|
||||
const Size& cnv_size = canvas.get_canvas_size();
|
||||
@ -319,13 +313,6 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
|
||||
imgui.end();
|
||||
|
||||
const Rect& bar_rect = get_bar_rect_viewport(canvas);
|
||||
#else
|
||||
const Rect& bar_rect = get_bar_rect_viewport(canvas);
|
||||
const Rect& reset_rect = get_reset_rect_viewport(canvas);
|
||||
|
||||
_render_tooltip_texture(canvas, bar_rect, reset_rect);
|
||||
_render_reset_texture(reset_rect);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
render_active_object_annotations(canvas, bar_rect);
|
||||
render_profile(bar_rect);
|
||||
}
|
||||
@ -352,68 +339,26 @@ bool GLCanvas3D::LayersEditing::bar_rect_contains(const GLCanvas3D& canvas, floa
|
||||
return (rect.get_left() <= x) && (x <= rect.get_right()) && (rect.get_top() <= y) && (y <= rect.get_bottom());
|
||||
}
|
||||
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
bool GLCanvas3D::LayersEditing::reset_rect_contains(const GLCanvas3D& canvas, float x, float y)
|
||||
{
|
||||
const Rect& rect = get_reset_rect_screen(canvas);
|
||||
return (rect.get_left() <= x) && (x <= rect.get_right()) && (rect.get_top() <= y) && (y <= rect.get_bottom());
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas)
|
||||
{
|
||||
const Size& cnv_size = canvas.get_canvas_size();
|
||||
float w = (float)cnv_size.get_width();
|
||||
float h = (float)cnv_size.get_height();
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
return Rect(w - thickness_bar_width(canvas), 0.0f, w, h);
|
||||
#else
|
||||
return Rect(w - thickness_bar_width(canvas), 0.0f, w, h - reset_button_height(canvas));
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
}
|
||||
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
Rect GLCanvas3D::LayersEditing::get_reset_rect_screen(const GLCanvas3D& canvas)
|
||||
{
|
||||
const Size& cnv_size = canvas.get_canvas_size();
|
||||
float w = (float)cnv_size.get_width();
|
||||
float h = (float)cnv_size.get_height();
|
||||
|
||||
return Rect(w - thickness_bar_width(canvas), h - reset_button_height(canvas), w, h);
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas)
|
||||
{
|
||||
const Size& cnv_size = canvas.get_canvas_size();
|
||||
float half_w = 0.5f * (float)cnv_size.get_width();
|
||||
float half_h = 0.5f * (float)cnv_size.get_height();
|
||||
|
||||
float zoom = (float)canvas.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)canvas.get_camera().get_inv_zoom();
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom);
|
||||
#else
|
||||
return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
}
|
||||
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
Rect GLCanvas3D::LayersEditing::get_reset_rect_viewport(const GLCanvas3D& canvas)
|
||||
{
|
||||
const Size& cnv_size = canvas.get_canvas_size();
|
||||
float half_w = 0.5f * (float)cnv_size.get_width();
|
||||
float half_h = 0.5f * (float)cnv_size.get_height();
|
||||
|
||||
float zoom = (float)canvas.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
|
||||
return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom);
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
bool GLCanvas3D::LayersEditing::is_initialized() const
|
||||
{
|
||||
return m_shader.is_initialized();
|
||||
@ -448,54 +393,6 @@ std::string GLCanvas3D::LayersEditing::get_tooltip(const GLCanvas3D& canvas) con
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void GLCanvas3D::LayersEditing::_render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const
|
||||
{
|
||||
// TODO: do this with ImGui
|
||||
|
||||
if (m_tooltip_texture.get_id() == 0)
|
||||
{
|
||||
std::string filename = resources_dir() + "/icons/variable_layer_height_tooltip.png";
|
||||
if (!m_tooltip_texture.load_from_file(filename, false, GLTexture::SingleThreaded, false))
|
||||
return;
|
||||
}
|
||||
|
||||
#if ENABLE_RETINA_GL
|
||||
const float scale = canvas.get_canvas_size().get_scale_factor();
|
||||
#else
|
||||
const float scale = canvas.get_wxglcanvas()->GetContentScaleFactor();
|
||||
#endif
|
||||
const float width = (float)m_tooltip_texture.get_width() * scale;
|
||||
const float height = (float)m_tooltip_texture.get_height() * scale;
|
||||
|
||||
float zoom = (float)canvas.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float gap = 10.0f * inv_zoom;
|
||||
|
||||
float bar_left = bar_rect.get_left();
|
||||
float reset_bottom = reset_rect.get_bottom();
|
||||
|
||||
float l = bar_left - width * inv_zoom - gap;
|
||||
float r = bar_left - gap;
|
||||
float t = reset_bottom + height * inv_zoom + gap;
|
||||
float b = reset_bottom + gap;
|
||||
|
||||
GLTexture::render_texture(m_tooltip_texture.get_id(), l, r, b, t);
|
||||
}
|
||||
|
||||
void GLCanvas3D::LayersEditing::_render_reset_texture(const Rect& reset_rect) const
|
||||
{
|
||||
if (m_reset_texture.get_id() == 0)
|
||||
{
|
||||
std::string filename = resources_dir() + "/icons/variable_layer_height_reset.png";
|
||||
if (!m_reset_texture.load_from_file(filename, false, GLTexture::SingleThreaded, false))
|
||||
return;
|
||||
}
|
||||
|
||||
GLTexture::render_texture(m_reset_texture.get_id(), reset_rect.get_left(), reset_rect.get_right(), reset_rect.get_bottom(), reset_rect.get_top());
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const
|
||||
{
|
||||
m_shader.start_using();
|
||||
@ -644,7 +541,6 @@ void GLCanvas3D::LayersEditing::reset_layer_height_profile(GLCanvas3D& canvas)
|
||||
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor)
|
||||
{
|
||||
this->update_slicing_parameters();
|
||||
@ -662,7 +558,6 @@ void GLCanvas3D::LayersEditing::smooth_layer_height_profile(GLCanvas3D& canvas,
|
||||
m_layers_texture.valid = false;
|
||||
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
void GLCanvas3D::LayersEditing::generate_layer_height_texture()
|
||||
{
|
||||
@ -725,19 +620,6 @@ float GLCanvas3D::LayersEditing::thickness_bar_width(const GLCanvas3D &canvas)
|
||||
* THICKNESS_BAR_WIDTH;
|
||||
}
|
||||
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
float GLCanvas3D::LayersEditing::reset_button_height(const GLCanvas3D &canvas)
|
||||
{
|
||||
return
|
||||
#if ENABLE_RETINA_GL
|
||||
canvas.get_canvas_size().get_scale_factor()
|
||||
#else
|
||||
canvas.get_wxglcanvas()->GetContentScaleFactor()
|
||||
#endif
|
||||
* THICKNESS_RESET_BUTTON_HEIGHT;
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
|
||||
const Point GLCanvas3D::Mouse::Drag::Invalid_2D_Point(INT_MAX, INT_MAX);
|
||||
const Vec3d GLCanvas3D::Mouse::Drag::Invalid_3D_Point(DBL_MAX, DBL_MAX, DBL_MAX);
|
||||
@ -964,8 +846,7 @@ void GLCanvas3D::WarningTexture::render(const GLCanvas3D& canvas) const
|
||||
if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0))
|
||||
{
|
||||
const Size& cnv_size = canvas.get_canvas_size();
|
||||
float zoom = (float)canvas.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)canvas.get_camera().get_inv_zoom();
|
||||
float left = (-0.5f * (float)m_original_width) * inv_zoom;
|
||||
float top = (-0.5f * (float)cnv_size.get_height() + (float)m_original_height + 2.0f) * inv_zoom;
|
||||
float right = left + (float)m_original_width * inv_zoom;
|
||||
@ -1011,7 +892,7 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
|
||||
std::vector<float>& colors,
|
||||
std::vector<std::string>& cp_legend_items)
|
||||
{
|
||||
std::vector<Model::CustomGCode> custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z;
|
||||
std::vector<Model::CustomGCode> custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes;
|
||||
|
||||
const int extruders_cnt = wxGetApp().extruders_edited_cnt();
|
||||
if (extruders_cnt == 1)
|
||||
@ -1137,6 +1018,12 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
|
||||
|
||||
// calculate scaling
|
||||
const float scale_gl = canvas.get_canvas_size().get_scale_factor();
|
||||
#if ENABLE_RETINA_GL
|
||||
// For non-visible or non-created window getBackingScaleFactor function return 0.0 value.
|
||||
// And using of the zero scale causes a crash, when we trying to draw text to the (0,0) rectangle
|
||||
if (scale_gl <= 0.0f)
|
||||
return false;
|
||||
#endif
|
||||
const float scale = scale_gl * wxGetApp().em_unit()*0.1; // get scale from em_unit() value, because of get_scale_factor() return 1
|
||||
const int scaled_square = std::floor((float)Px_Square * scale);
|
||||
const int scaled_title_offset = Px_Title_Offset * scale;
|
||||
@ -1321,8 +1208,7 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const
|
||||
if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0))
|
||||
{
|
||||
const Size& cnv_size = canvas.get_canvas_size();
|
||||
float zoom = (float)canvas.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)canvas.get_camera().get_inv_zoom();
|
||||
float left = (-0.5f * (float)cnv_size.get_width()) * inv_zoom;
|
||||
float top = (0.5f * (float)cnv_size.get_height()) * inv_zoom;
|
||||
float right = left + (float)m_original_width * inv_zoom;
|
||||
@ -1343,9 +1229,6 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const
|
||||
}
|
||||
}
|
||||
|
||||
#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
|
||||
#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
|
||||
@ -1369,11 +1252,9 @@ wxDEFINE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25;
|
||||
@ -1515,10 +1396,6 @@ bool GLCanvas3D::init()
|
||||
if (m_selection.is_enabled() && !m_selection.init())
|
||||
return false;
|
||||
|
||||
#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_INIT));
|
||||
#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
m_initialized = true;
|
||||
|
||||
return true;
|
||||
@ -1675,7 +1552,6 @@ bool GLCanvas3D::is_layers_editing_allowed() const
|
||||
return m_layers_editing.is_allowed();
|
||||
}
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void GLCanvas3D::reset_layer_height_profile()
|
||||
{
|
||||
wxGetApp().plater()->take_snapshot(_(L("Variable layer height - Reset")));
|
||||
@ -1699,7 +1575,6 @@ void GLCanvas3D::smooth_layer_height_profile(const HeightProfileSmoothingParams&
|
||||
m_layers_editing.state = LayersEditing::Completed;
|
||||
m_dirty = true;
|
||||
}
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
bool GLCanvas3D::is_reload_delayed() const
|
||||
{
|
||||
@ -1786,8 +1661,14 @@ void GLCanvas3D::zoom_to_selection()
|
||||
|
||||
void GLCanvas3D::select_view(const std::string& direction)
|
||||
{
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
m_camera.select_view(direction);
|
||||
if (m_canvas != nullptr)
|
||||
m_canvas->Refresh();
|
||||
#else
|
||||
if (m_camera.select_view(direction) && (m_canvas != nullptr))
|
||||
m_canvas->Refresh();
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
}
|
||||
|
||||
void GLCanvas3D::update_volumes_colors_by_extruder()
|
||||
@ -1844,10 +1725,12 @@ void GLCanvas3D::render()
|
||||
GLfloat position_top[4] = { -0.5f, -0.5f, 1.0f, 0.0f };
|
||||
glsafe(::glLightfv(GL_LIGHT0, GL_POSITION, position_top));
|
||||
|
||||
#if !ENABLE_6DOF_CAMERA
|
||||
float theta = m_camera.get_theta();
|
||||
if (theta > 180.f)
|
||||
// absolute value of the rotation
|
||||
theta = 360.f - theta;
|
||||
#endif // !ENABLE_6DOF_CAMERA
|
||||
|
||||
wxGetApp().imgui()->new_frame();
|
||||
|
||||
@ -1872,7 +1755,11 @@ void GLCanvas3D::render()
|
||||
_render_objects();
|
||||
_render_sla_slices();
|
||||
_render_selection();
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
_render_bed(!m_camera.is_looking_downward(), true);
|
||||
#else
|
||||
_render_bed(theta, true);
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
_render_selection_center();
|
||||
@ -1921,11 +1808,7 @@ void GLCanvas3D::render()
|
||||
m_camera.debug_render();
|
||||
#endif // ENABLE_CAMERA_STATISTICS
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this);
|
||||
#else
|
||||
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height());
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
wxGetApp().imgui()->render();
|
||||
|
||||
@ -2421,7 +2304,7 @@ static void load_gcode_retractions(const GCodePreviewData::Retraction& retractio
|
||||
|
||||
volume_index.first_volumes.emplace_back(extrusion_type, 0, (unsigned int)volumes.volumes.size());
|
||||
|
||||
GLVolume *volume = volumes.new_nontoolpath_volume(retractions.color.rgba, VERTEX_BUFFER_RESERVE_SIZE);
|
||||
GLVolume *volume = volumes.new_nontoolpath_volume(retractions.color.rgba.data(), VERTEX_BUFFER_RESERVE_SIZE);
|
||||
|
||||
GCodePreviewData::Retraction::PositionsList copy(retractions.positions);
|
||||
std::sort(copy.begin(), copy.end(), [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2) { return p1.position(2) < p2.position(2); });
|
||||
@ -3111,20 +2994,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
m_layers_editing.state = LayersEditing::Editing;
|
||||
_perform_layer_editing_action(&evt);
|
||||
}
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
else if ((layer_editing_object_idx != -1) && m_layers_editing.reset_rect_contains(*this, pos(0), pos(1)))
|
||||
{
|
||||
if (evt.LeftDown())
|
||||
{
|
||||
// A volume is selected and the mouse is inside the reset button. Reset the ModelObject's layer height profile.
|
||||
m_layers_editing.reset_layer_height_profile(*this);
|
||||
// Index 2 means no editing, just wait for mouse up event.
|
||||
m_layers_editing.state = LayersEditing::Completed;
|
||||
|
||||
m_dirty = true;
|
||||
}
|
||||
}
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
else if (evt.LeftDown() && (evt.ShiftDown() || evt.AltDown()) && m_picking_enabled)
|
||||
{
|
||||
if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)
|
||||
@ -3207,7 +3076,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
// we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag
|
||||
if (m_selection.contains_volume(get_first_hover_volume_idx()))
|
||||
{
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
if (std::abs(m_camera.get_dir_forward()(2)) < EPSILON)
|
||||
#else
|
||||
if (m_camera.get_theta() == 90.0f)
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
{
|
||||
// side view -> move selected volumes orthogonally to camera view direction
|
||||
Linef3 ray = mouse_ray(pos);
|
||||
@ -3267,9 +3140,18 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
if (m_hover_volume_idxs.empty() && m_mouse.is_start_position_3D_defined())
|
||||
{
|
||||
const Vec3d& orig = m_mouse.drag.start_position_3D;
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
double x = Geometry::deg2rad(pos(0) - orig(0)) * (double)TRACKBALLSIZE;
|
||||
double y = Geometry::deg2rad(pos(1) - orig(1)) * (double)TRACKBALLSIZE;
|
||||
if (wxGetApp().plater()->get_mouse3d_controller().is_running() || (wxGetApp().app_config->get("use_free_camera") == "1"))
|
||||
m_camera.rotate_local_around_target(Vec3d(y, x, 0.0));
|
||||
else
|
||||
m_camera.rotate_on_sphere(x, y);
|
||||
#else
|
||||
float sign = m_camera.inverted_phi ? -1.0f : 1.0f;
|
||||
m_camera.phi += sign * ((float)pos(0) - (float)orig(0)) * TRACKBALLSIZE;
|
||||
m_camera.set_theta(m_camera.get_theta() - ((float)pos(1) - (float)orig(1)) * TRACKBALLSIZE, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
m_dirty = true;
|
||||
}
|
||||
m_mouse.drag.start_position_3D = Vec3d((double)pos(0), (double)pos(1), 0.0);
|
||||
@ -3319,9 +3201,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
if (!evt.ShiftDown() && m_picking_enabled)
|
||||
deselect_all();
|
||||
}
|
||||
#if !ENABLE_6DOF_CAMERA
|
||||
else if (evt.LeftUp() && m_mouse.dragging)
|
||||
// Flips X mouse deltas if bed is upside down
|
||||
m_camera.inverted_phi = (m_camera.get_dir_up()(2) < 0.0);
|
||||
#endif // !ENABLE_6DOF_CAMERA
|
||||
else if (evt.RightUp())
|
||||
{
|
||||
m_mouse.position = pos.cast<double>();
|
||||
@ -3926,6 +3810,9 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
|
||||
|
||||
Camera camera;
|
||||
camera.set_type(Camera::Ortho);
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
camera.set_scene_box(scene_bounding_box());
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
camera.zoom_to_volumes(visible_volumes, thumbnail_data.width, thumbnail_data.height);
|
||||
camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height);
|
||||
camera.apply_view_matrix();
|
||||
@ -3976,7 +3863,11 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
if (show_bed)
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
_render_bed(!camera.is_looking_downward(), false);
|
||||
#else
|
||||
_render_bed(camera.get_theta(), false);
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
if (transparent_background)
|
||||
glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
@ -4227,10 +4118,8 @@ bool GLCanvas3D::_init_toolbars()
|
||||
if (!_init_undoredo_toolbar())
|
||||
return false;
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
if (!_init_view_toolbar())
|
||||
return false;
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -4489,12 +4378,10 @@ bool GLCanvas3D::_init_undoredo_toolbar()
|
||||
return true;
|
||||
}
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
bool GLCanvas3D::_init_view_toolbar()
|
||||
{
|
||||
return wxGetApp().plater()->init_view_toolbar();
|
||||
}
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
bool GLCanvas3D::_set_current()
|
||||
{
|
||||
@ -4933,8 +4820,7 @@ void GLCanvas3D::_render_main_toolbar() const
|
||||
#endif // ENABLE_RETINA_GL
|
||||
|
||||
Size cnv_size = get_canvas_size();
|
||||
float zoom = (float)m_camera.get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)m_camera.get_inv_zoom();
|
||||
|
||||
float top = 0.5f * (float)cnv_size.get_height() * inv_zoom;
|
||||
float left = -0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width()) * inv_zoom;
|
||||
@ -4960,8 +4846,7 @@ void GLCanvas3D::_render_undoredo_toolbar() const
|
||||
#endif // ENABLE_RETINA_GL
|
||||
|
||||
Size cnv_size = get_canvas_size();
|
||||
float zoom = (float)m_camera.get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)m_camera.get_inv_zoom();
|
||||
|
||||
float top = 0.5f * (float)cnv_size.get_height() * inv_zoom;
|
||||
float left = (m_main_toolbar.get_width() - 0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width())) * inv_zoom;
|
||||
@ -4983,8 +4868,7 @@ void GLCanvas3D::_render_view_toolbar() const
|
||||
#endif // ENABLE_RETINA_GL
|
||||
|
||||
Size cnv_size = get_canvas_size();
|
||||
float zoom = (float)m_camera.get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)m_camera.get_inv_zoom();
|
||||
|
||||
// places the toolbar on the bottom-left corner of the 3d scene
|
||||
float top = (-0.5f * (float)cnv_size.get_height() + m_view_toolbar.get_height()) * inv_zoom;
|
||||
@ -5407,11 +5291,11 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
||||
const std::string& code = it->gcode;
|
||||
// pause print or custom Gcode
|
||||
if (code == PausePrintCode ||
|
||||
(code != ColorChangeCode && code != ExtruderChangeCode))
|
||||
(code != ColorChangeCode && code != ToolChangeCode))
|
||||
return number_tools()-1; // last color item is a gray color for pause print or custom G-code
|
||||
|
||||
// change tool (extruder)
|
||||
if (code == ExtruderChangeCode)
|
||||
if (code == ToolChangeCode)
|
||||
return get_color_idx_for_tool_change(it, extruder);
|
||||
// change color for current extruder
|
||||
if (code == ColorChangeCode) {
|
||||
@ -5433,7 +5317,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
||||
return color_idx;
|
||||
}
|
||||
// change tool (extruder)
|
||||
if (it->gcode == ExtruderChangeCode)
|
||||
if (it->gcode == ToolChangeCode)
|
||||
return get_color_idx_for_tool_change(it, extruder);
|
||||
}
|
||||
|
||||
@ -5477,7 +5361,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
||||
bool is_tool_change = false;
|
||||
while (it_n != color_print_values->begin()) {
|
||||
--it_n;
|
||||
if (it_n->gcode == ExtruderChangeCode) {
|
||||
if (it_n->gcode == ToolChangeCode) {
|
||||
is_tool_change = true;
|
||||
if (it_n->extruder == it->extruder || (it_n->extruder == 0 && it->extruder == extruder))
|
||||
return get_m600_color_idx(it);
|
||||
@ -5857,7 +5741,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
static GCodePreviewData::Color path_color(const GCodePreviewData& data, const std::vector<float>& tool_colors, float value)
|
||||
static Color path_color(const GCodePreviewData& data, const std::vector<float>& tool_colors, float value)
|
||||
{
|
||||
switch (data.extrusion.view_type)
|
||||
{
|
||||
@ -5875,8 +5759,8 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
|
||||
return data.get_volumetric_rate_color(value);
|
||||
case GCodePreviewData::Extrusion::Tool:
|
||||
{
|
||||
GCodePreviewData::Color color;
|
||||
::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + (unsigned int)value * 4), 4 * sizeof(float));
|
||||
Color color;
|
||||
::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + (unsigned int)value * 4), 4 * sizeof(float));
|
||||
return color;
|
||||
}
|
||||
case GCodePreviewData::Extrusion::ColorPrint:
|
||||
@ -5884,16 +5768,16 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
|
||||
int color_cnt = (int)tool_colors.size() / 4;
|
||||
int val = value > color_cnt ? color_cnt - 1 : value;
|
||||
|
||||
GCodePreviewData::Color color;
|
||||
::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + val * 4), 4 * sizeof(float));
|
||||
Color color;
|
||||
::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + val * 4), 4 * sizeof(float));
|
||||
|
||||
return color;
|
||||
}
|
||||
default:
|
||||
return GCodePreviewData::Color::Dummy;
|
||||
return Color{};
|
||||
}
|
||||
|
||||
return GCodePreviewData::Color::Dummy;
|
||||
return Color{};
|
||||
}
|
||||
};
|
||||
|
||||
@ -5936,7 +5820,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
|
||||
if (! values.empty()) {
|
||||
m_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Extrusion, role, (unsigned int)m_volumes.volumes.size());
|
||||
for (const float value : values)
|
||||
roles_filters.back().emplace_back(value, m_volumes.new_toolpath_volume(Helper::path_color(preview_data, tool_colors, value).rgba, vertex_buffer_prealloc_size));
|
||||
roles_filters.back().emplace_back(value, m_volumes.new_toolpath_volume(Helper::path_color(preview_data, tool_colors, value).rgba.data(), vertex_buffer_prealloc_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6019,7 +5903,7 @@ inline void travel_paths_internal(
|
||||
by_type.reserve(values.size());
|
||||
// creates a new volume for each feedrate
|
||||
for (TYPE type : values)
|
||||
by_type.emplace_back(type, volumes.new_nontoolpath_volume(func_color(type).rgba, VERTEX_BUFFER_RESERVE_SIZE));
|
||||
by_type.emplace_back(type, volumes.new_nontoolpath_volume(func_color(type).rgba.data(), VERTEX_BUFFER_RESERVE_SIZE));
|
||||
}
|
||||
|
||||
// populates volumes
|
||||
@ -6066,19 +5950,19 @@ void GLCanvas3D::_load_gcode_travel_paths(const GCodePreviewData& preview_data,
|
||||
case GCodePreviewData::Extrusion::Feedrate:
|
||||
travel_paths_internal<float>(preview_data,
|
||||
[](const GCodePreviewData::Travel::Polyline &polyline) { return polyline.feedrate; },
|
||||
[&preview_data](const float feedrate) -> const GCodePreviewData::Color { return preview_data.get_feedrate_color(feedrate); },
|
||||
[&preview_data](const float feedrate) -> const Color { return preview_data.get_feedrate_color(feedrate); },
|
||||
m_volumes, m_initialized);
|
||||
break;
|
||||
case GCodePreviewData::Extrusion::Tool:
|
||||
travel_paths_internal<unsigned int>(preview_data,
|
||||
[](const GCodePreviewData::Travel::Polyline &polyline) { return polyline.extruder_id; },
|
||||
[&tool_colors](const unsigned int extruder_id) -> const GCodePreviewData::Color { assert((extruder_id + 1) * 4 <= tool_colors.size()); return GCodePreviewData::Color(tool_colors.data() + extruder_id * 4); },
|
||||
[&tool_colors](const unsigned int extruder_id) -> const Color { assert((extruder_id + 1) * 4 <= tool_colors.size()); return Color(tool_colors.data() + extruder_id * 4); },
|
||||
m_volumes, m_initialized);
|
||||
break;
|
||||
default:
|
||||
travel_paths_internal<unsigned int>(preview_data,
|
||||
[](const GCodePreviewData::Travel::Polyline &polyline) { return polyline.type; },
|
||||
[&preview_data](const unsigned int type) -> const GCodePreviewData::Color& { return preview_data.travel.type_colors[type]; },
|
||||
[&preview_data](const unsigned int type) -> const Color& { return preview_data.travel.type_colors[type]; },
|
||||
m_volumes, m_initialized);
|
||||
break;
|
||||
}
|
||||
|
@ -83,9 +83,6 @@ template <size_t N> using Vec3dsEvent = ArrayEvent<Vec3d, N>;
|
||||
|
||||
using HeightProfileSmoothEvent = Event<HeightProfileSmoothingParams>;
|
||||
|
||||
#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
|
||||
#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
|
||||
@ -108,11 +105,9 @@ wxDECLARE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
class GLCanvas3D
|
||||
{
|
||||
@ -162,17 +157,10 @@ private:
|
||||
|
||||
private:
|
||||
static const float THICKNESS_BAR_WIDTH;
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static const float THICKNESS_RESET_BUTTON_HEIGHT;
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
bool m_enabled;
|
||||
Shader m_shader;
|
||||
unsigned int m_z_texture_id;
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
mutable GLTexture m_tooltip_texture;
|
||||
mutable GLTexture m_reset_texture;
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
// Not owned by LayersEditing.
|
||||
const DynamicPrintConfig *m_config;
|
||||
// ModelObject for the currently selected object (Model::objects[last_object_id]).
|
||||
@ -184,10 +172,8 @@ private:
|
||||
std::vector<double> m_layer_height_profile;
|
||||
bool m_layer_height_profile_modified;
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
mutable float m_adaptive_quality;
|
||||
mutable HeightProfileSmoothingParams m_smooth_params;
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
class LayersTexture
|
||||
{
|
||||
@ -235,24 +221,13 @@ private:
|
||||
void adjust_layer_height_profile();
|
||||
void accept_changes(GLCanvas3D& canvas);
|
||||
void reset_layer_height_profile(GLCanvas3D& canvas);
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor);
|
||||
void smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_params);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
static float get_cursor_z_relative(const GLCanvas3D& canvas);
|
||||
static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y);
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static bool reset_rect_contains(const GLCanvas3D& canvas, float x, float y);
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static Rect get_bar_rect_screen(const GLCanvas3D& canvas);
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static Rect get_reset_rect_screen(const GLCanvas3D& canvas);
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static Rect get_bar_rect_viewport(const GLCanvas3D& canvas);
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static Rect get_reset_rect_viewport(const GLCanvas3D& canvas);
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
float object_max_z() const { return m_object_max_z; }
|
||||
|
||||
@ -261,18 +236,11 @@ private:
|
||||
private:
|
||||
bool is_initialized() const;
|
||||
void generate_layer_height_texture();
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void _render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const;
|
||||
void _render_reset_texture(const Rect& reset_rect) const;
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const;
|
||||
void render_profile(const Rect& bar_rect) const;
|
||||
void update_slicing_parameters();
|
||||
|
||||
static float thickness_bar_width(const GLCanvas3D &canvas);
|
||||
#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
static float reset_button_height(const GLCanvas3D &canvas);
|
||||
#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
};
|
||||
|
||||
struct Mouse
|
||||
@ -540,11 +508,9 @@ public:
|
||||
bool is_layers_editing_enabled() const;
|
||||
bool is_layers_editing_allowed() const;
|
||||
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
void reset_layer_height_profile();
|
||||
void adaptive_layer_height_profile(float quality_factor);
|
||||
void smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params);
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
bool is_reload_delayed() const;
|
||||
|
||||
@ -684,9 +650,7 @@ private:
|
||||
bool _init_toolbars();
|
||||
bool _init_main_toolbar();
|
||||
bool _init_undoredo_toolbar();
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
bool _init_view_toolbar();
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
bool _set_current();
|
||||
void _resize(unsigned int w, unsigned int h);
|
||||
|
@ -69,8 +69,7 @@ namespace GUI {
|
||||
return;
|
||||
|
||||
const Camera& camera = canvas.get_camera();
|
||||
float zoom = (float)camera.get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)camera.get_inv_zoom();
|
||||
|
||||
Size cnv_size = canvas.get_canvas_size();
|
||||
float cnv_half_width = 0.5f * (float)cnv_size.get_width();
|
||||
|
@ -168,12 +168,26 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
|
||||
if (filenames.empty() || states.empty() || (sprite_size_px == 0))
|
||||
return false;
|
||||
|
||||
#if ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
// every tile needs to have a 1px border around it to avoid artifacts when linear sampling on its edges
|
||||
unsigned int sprite_size_px_ex = sprite_size_px + 1;
|
||||
|
||||
m_width = 1 + (int)(sprite_size_px_ex * states.size());
|
||||
m_height = 1 + (int)(sprite_size_px_ex * filenames.size());
|
||||
#else
|
||||
m_width = (int)(sprite_size_px * states.size());
|
||||
m_height = (int)(sprite_size_px * filenames.size());
|
||||
#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
|
||||
int n_pixels = m_width * m_height;
|
||||
#if ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
int sprite_n_pixels = sprite_size_px_ex * sprite_size_px_ex;
|
||||
int sprite_stride = sprite_size_px_ex * 4;
|
||||
#else
|
||||
int sprite_n_pixels = sprite_size_px * sprite_size_px;
|
||||
int sprite_bytes = sprite_n_pixels * 4;
|
||||
int sprite_stride = sprite_size_px * 4;
|
||||
#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
int sprite_bytes = sprite_n_pixels * 4;
|
||||
|
||||
if (n_pixels <= 0)
|
||||
{
|
||||
@ -211,7 +225,12 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
|
||||
|
||||
float scale = (float)sprite_size_px / std::max(image->width, image->height);
|
||||
|
||||
#if ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
// offset by 1 to leave the first pixel empty (both in x and y)
|
||||
nsvgRasterize(rast, image, 1, 1, scale, sprite_data.data(), sprite_size_px, sprite_size_px, sprite_stride);
|
||||
#else
|
||||
nsvgRasterize(rast, image, 0, 0, scale, sprite_data.data(), sprite_size_px, sprite_size_px, sprite_stride);
|
||||
#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
|
||||
// makes white only copy of the sprite
|
||||
::memcpy((void*)sprite_white_only_data.data(), (const void*)sprite_data.data(), sprite_bytes);
|
||||
@ -231,7 +250,11 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
|
||||
::memset((void*)&sprite_gray_only_data.data()[offset], 128, 3);
|
||||
}
|
||||
|
||||
#if ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
int sprite_offset_px = sprite_id * (int)sprite_size_px_ex * m_width;
|
||||
#else
|
||||
int sprite_offset_px = sprite_id * sprite_size_px * m_width;
|
||||
#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
int state_id = -1;
|
||||
for (const std::pair<int, bool>& state : states)
|
||||
{
|
||||
@ -250,6 +273,23 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
|
||||
// applies background, if needed
|
||||
if (state.second)
|
||||
{
|
||||
#if ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
float inv_255 = 1.0f / 255.0f;
|
||||
// offset by 1 to leave the first pixel empty (both in x and y)
|
||||
for (unsigned int r = 1; r <= sprite_size_px; ++r)
|
||||
{
|
||||
unsigned int offset_r = r * sprite_size_px_ex;
|
||||
for (unsigned int c = 1; c <= sprite_size_px; ++c)
|
||||
{
|
||||
unsigned int offset = (offset_r + c) * 4;
|
||||
float alpha = (float)output_data.data()[offset + 3] * inv_255;
|
||||
output_data.data()[offset + 0] = (unsigned char)(output_data.data()[offset + 0] * alpha);
|
||||
output_data.data()[offset + 1] = (unsigned char)(output_data.data()[offset + 1] * alpha);
|
||||
output_data.data()[offset + 2] = (unsigned char)(output_data.data()[offset + 2] * alpha);
|
||||
output_data.data()[offset + 3] = (unsigned char)(128 * (1.0f - alpha) + output_data.data()[offset + 3] * alpha);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < sprite_n_pixels; ++i)
|
||||
{
|
||||
int offset = i * 4;
|
||||
@ -259,13 +299,22 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
|
||||
output_data.data()[offset + 2] = (unsigned char)(output_data.data()[offset + 2] * alpha);
|
||||
output_data.data()[offset + 3] = (unsigned char)(128 * (1.0f - alpha) + output_data.data()[offset + 3] * alpha);
|
||||
}
|
||||
#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
}
|
||||
|
||||
#if ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
int state_offset_px = sprite_offset_px + state_id * sprite_size_px_ex;
|
||||
for (int j = 0; j < (int)sprite_size_px_ex; ++j)
|
||||
{
|
||||
::memcpy((void*)&data.data()[(state_offset_px + j * m_width) * 4], (const void*)&output_data.data()[j * sprite_stride], sprite_stride);
|
||||
}
|
||||
#else
|
||||
int state_offset_px = sprite_offset_px + state_id * sprite_size_px;
|
||||
for (int j = 0; j < (int)sprite_size_px; ++j)
|
||||
{
|
||||
::memcpy((void*)&data.data()[(state_offset_px + j * m_width) * 4], (const void*)&output_data.data()[j * sprite_stride], sprite_stride);
|
||||
}
|
||||
#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
}
|
||||
|
||||
nsvgDelete(image);
|
||||
|
@ -86,7 +86,35 @@ bool GLToolbarItem::update_enabled_state()
|
||||
|
||||
void GLToolbarItem::render(unsigned int tex_id, float left, float right, float bottom, float top, unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) const
|
||||
{
|
||||
#if ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
auto uvs = [this](unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) ->GLTexture::Quad_UVs
|
||||
{
|
||||
assert((tex_width != 0) && (tex_height != 0));
|
||||
GLTexture::Quad_UVs ret;
|
||||
// tiles in the texture are spaced by 1 pixel
|
||||
float icon_size_px = (float)(tex_width - 1) / (float)Num_States;
|
||||
float inv_tex_width = 1.0f / (float)tex_width;
|
||||
float inv_tex_height = 1.0f / (float)tex_height;
|
||||
// tiles in the texture are spaced by 1 pixel
|
||||
float u_offset = 1.0f * inv_tex_width;
|
||||
float v_offset = 1.0f * inv_tex_height;
|
||||
float du = icon_size_px * inv_tex_width;
|
||||
float dv = icon_size_px * inv_tex_height;
|
||||
float left = u_offset + (float)m_state * du;
|
||||
float right = left + du - u_offset;
|
||||
float top = v_offset + (float)m_data.sprite_id * dv;
|
||||
float bottom = top + dv - v_offset;
|
||||
ret.left_top = { left, top };
|
||||
ret.left_bottom = { left, bottom };
|
||||
ret.right_bottom = { right, bottom };
|
||||
ret.right_top = { right, top };
|
||||
return ret;
|
||||
};
|
||||
|
||||
GLTexture::render_sub_texture(tex_id, left, right, bottom, top, uvs(tex_width, tex_height, icon_size));
|
||||
#else
|
||||
GLTexture::render_sub_texture(tex_id, left, right, bottom, top, get_uvs(tex_width, tex_height, icon_size));
|
||||
#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
|
||||
if (is_pressed())
|
||||
{
|
||||
@ -97,6 +125,7 @@ void GLToolbarItem::render(unsigned int tex_id, float left, float right, float b
|
||||
}
|
||||
}
|
||||
|
||||
#if !ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
GLTexture::Quad_UVs GLToolbarItem::get_uvs(unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) const
|
||||
{
|
||||
GLTexture::Quad_UVs uvs;
|
||||
@ -110,14 +139,14 @@ GLTexture::Quad_UVs GLToolbarItem::get_uvs(unsigned int tex_width, unsigned int
|
||||
float right = left + scaled_icon_width;
|
||||
float top = (float)m_data.sprite_id * scaled_icon_height;
|
||||
float bottom = top + scaled_icon_height;
|
||||
|
||||
uvs.left_top = { left, top };
|
||||
uvs.left_bottom = { left, bottom };
|
||||
uvs.right_bottom = { right, bottom };
|
||||
uvs.right_top = { right, top };
|
||||
|
||||
|
||||
return uvs;
|
||||
}
|
||||
#endif // !ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
|
||||
BackgroundTexture::Metadata::Metadata()
|
||||
: filename("")
|
||||
@ -624,8 +653,7 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC
|
||||
{
|
||||
// NB: mouse_pos is already scaled appropriately
|
||||
|
||||
float zoom = (float)parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)parent.get_camera().get_inv_zoom();
|
||||
float factor = m_layout.scale * inv_zoom;
|
||||
|
||||
Size cnv_size = parent.get_canvas_size();
|
||||
@ -729,8 +757,7 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan
|
||||
{
|
||||
// NB: mouse_pos is already scaled appropriately
|
||||
|
||||
float zoom = (float)parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)parent.get_camera().get_inv_zoom();
|
||||
float factor = m_layout.scale * inv_zoom;
|
||||
|
||||
Size cnv_size = parent.get_canvas_size();
|
||||
@ -846,8 +873,7 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3
|
||||
{
|
||||
// NB: mouse_pos is already scaled appropriately
|
||||
|
||||
float zoom = (float)parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)parent.get_camera().get_inv_zoom();
|
||||
float factor = m_layout.scale * inv_zoom;
|
||||
|
||||
Size cnv_size = parent.get_canvas_size();
|
||||
@ -920,8 +946,7 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D&
|
||||
{
|
||||
// NB: mouse_pos is already scaled appropriately
|
||||
|
||||
float zoom = (float)parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)parent.get_camera().get_inv_zoom();
|
||||
float factor = m_layout.scale * inv_zoom;
|
||||
|
||||
Size cnv_size = parent.get_canvas_size();
|
||||
@ -1073,8 +1098,7 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const
|
||||
int tex_width = m_icons_texture.get_width();
|
||||
int tex_height = m_icons_texture.get_height();
|
||||
|
||||
float zoom = (float)parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)parent.get_camera().get_inv_zoom();
|
||||
float factor = inv_zoom * m_layout.scale;
|
||||
|
||||
float scaled_icons_size = m_layout.icons_size * factor;
|
||||
@ -1122,8 +1146,7 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const
|
||||
int tex_width = m_icons_texture.get_width();
|
||||
int tex_height = m_icons_texture.get_height();
|
||||
|
||||
float zoom = (float)parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)parent.get_camera().get_inv_zoom();
|
||||
float factor = inv_zoom * m_layout.scale;
|
||||
|
||||
float scaled_icons_size = m_layout.icons_size * factor;
|
||||
|
@ -143,7 +143,9 @@ public:
|
||||
void render(unsigned int tex_id, float left, float right, float bottom, float top, unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) const;
|
||||
|
||||
private:
|
||||
#if !ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
GLTexture::Quad_UVs get_uvs(unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) const;
|
||||
#endif // !ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
void set_visible(bool visible) { m_data.visible = visible; }
|
||||
|
||||
friend class GLToolbar;
|
||||
@ -293,9 +295,7 @@ public:
|
||||
|
||||
bool is_any_item_pressed() const;
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
unsigned int get_items_count() const { return (unsigned int)m_items.size(); }
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
int get_item_id(const std::string& name) const;
|
||||
|
||||
void force_left_action(int item_id, GLCanvas3D& parent) { do_action(GLToolbarItem::Left, item_id, parent, false); }
|
||||
|
@ -533,7 +533,9 @@ void Preview::on_combochecklist_features(wxCommandEvent& evt)
|
||||
void Preview::on_checkbox_travel(wxCommandEvent& evt)
|
||||
{
|
||||
m_gcode_preview_data->travel.is_visible = m_checkbox_travel->IsChecked();
|
||||
refresh_print();
|
||||
m_gcode_preview_data->ranges.feedrate.set_mode(GCodePreviewData::FeedrateKind::TRAVEL, m_gcode_preview_data->travel.is_visible);
|
||||
// Rather than refresh, reload print so that speed color ranges get recomputed (affected by travel visibility)
|
||||
reload_print();
|
||||
}
|
||||
|
||||
void Preview::on_checkbox_retractions(wxCommandEvent& evt)
|
||||
@ -564,7 +566,7 @@ void Preview::update_view_type(bool slice_completed)
|
||||
{
|
||||
const DynamicPrintConfig& config = wxGetApp().preset_bundle->project_config;
|
||||
|
||||
const wxString& choice = !wxGetApp().plater()->model().custom_gcode_per_print_z.empty() /*&&
|
||||
const wxString& choice = !wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes.empty() /*&&
|
||||
(wxGetApp().extruders_edited_cnt()==1 || !slice_completed) */?
|
||||
_(L("Color Print")) :
|
||||
config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values.size() > 1 ?
|
||||
@ -664,8 +666,11 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
|
||||
bool snap_to_min = force_sliders_full_range || m_slider->is_lower_at_min();
|
||||
bool snap_to_max = force_sliders_full_range || m_slider->is_higher_at_max();
|
||||
|
||||
std::vector<Model::CustomGCode> &ticks_from_model = wxGetApp().plater()->model().custom_gcode_per_print_z;
|
||||
check_slider_values(ticks_from_model, layers_z);
|
||||
// Detect and set manipulation mode for double slider
|
||||
update_double_slider_mode();
|
||||
|
||||
Model::CustomGCodeInfo &ticks_info_from_model = wxGetApp().plater()->model().custom_gcode_per_print_z;
|
||||
check_slider_values(ticks_info_from_model.gcodes, layers_z);
|
||||
|
||||
m_slider->SetSliderValues(layers_z);
|
||||
assert(m_slider->GetMinValue() == 0);
|
||||
@ -687,12 +692,61 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
|
||||
}
|
||||
m_slider->SetSelectionSpan(idx_low, idx_high);
|
||||
|
||||
m_slider->SetTicksValues(ticks_from_model);
|
||||
m_slider->SetTicksValues(ticks_info_from_model);
|
||||
|
||||
bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF);
|
||||
m_slider->EnableTickManipulation(wxGetApp().plater()->printer_technology() == ptFFF);
|
||||
}
|
||||
|
||||
m_slider->EnableTickManipulation(color_print_enable);
|
||||
m_slider->SetManipulationState(wxGetApp().extruders_edited_cnt());
|
||||
void Preview::update_double_slider_mode()
|
||||
{
|
||||
// true -> single-extruder printer profile OR
|
||||
// multi-extruder printer profile , but whole model is printed by only one extruder
|
||||
// false -> multi-extruder printer profile , and model is printed by several extruders
|
||||
bool one_extruder_printed_model = true;
|
||||
|
||||
// extruder used for whole model for multi-extruder printer profile
|
||||
int only_extruder = -1;
|
||||
|
||||
if (wxGetApp().extruders_edited_cnt() > 1)
|
||||
{
|
||||
const ModelObjectPtrs& objects = wxGetApp().plater()->model().objects;
|
||||
|
||||
// check if whole model uses just only one extruder
|
||||
if (!objects.empty())
|
||||
{
|
||||
const int extruder = objects[0]->config.has("extruder") ?
|
||||
objects[0]->config.option("extruder")->getInt() : 0;
|
||||
|
||||
auto is_one_extruder_printed_model = [objects, extruder]()
|
||||
{
|
||||
for (ModelObject* object : objects)
|
||||
{
|
||||
if (object->config.has("extruder") &&
|
||||
object->config.option("extruder")->getInt() != extruder)
|
||||
return false;
|
||||
|
||||
if (object->volumes.size() > 1)
|
||||
for (ModelVolume* volume : object->volumes)
|
||||
if (volume->config.has("extruder") &&
|
||||
volume->config.option("extruder")->getInt() != extruder)
|
||||
return false;
|
||||
|
||||
for (const auto& range : object->layer_config_ranges)
|
||||
if (range.second.has("extruder") &&
|
||||
range.second.option("extruder")->getInt() != extruder)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (is_one_extruder_printed_model())
|
||||
only_extruder = extruder;
|
||||
else
|
||||
one_extruder_printed_model = false;
|
||||
}
|
||||
}
|
||||
|
||||
m_slider->SetModeAndOnlyExtruder(one_extruder_printed_model, only_extruder);
|
||||
}
|
||||
|
||||
void Preview::reset_double_slider()
|
||||
@ -784,7 +838,7 @@ void Preview::load_print_as_fff(bool keep_z_range)
|
||||
colors.push_back("#808080"); // gray color for pause print or custom G-code
|
||||
|
||||
if (!gcode_preview_data_valid)
|
||||
color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z;
|
||||
color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes;
|
||||
}
|
||||
else if (gcode_preview_data_valid || (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::Tool) )
|
||||
{
|
||||
|
@ -157,8 +157,9 @@ private:
|
||||
void create_double_slider();
|
||||
void check_slider_values(std::vector<Model::CustomGCode> &ticks_from_model,
|
||||
const std::vector<double> &layers_z);
|
||||
void update_double_slider(const std::vector<double>& layers_z, bool keep_z_range = false);
|
||||
void reset_double_slider();
|
||||
void update_double_slider(const std::vector<double>& layers_z, bool keep_z_range = false);
|
||||
void update_double_slider_mode();
|
||||
// update DoubleSlider after keyDown in canvas
|
||||
void update_double_slider_from_canvas(wxKeyEvent& event);
|
||||
|
||||
|
@ -48,12 +48,10 @@ std::string GLGizmoMove3D::on_get_name() const
|
||||
return (_(L("Move")) + " [M]").ToUTF8().data();
|
||||
}
|
||||
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
bool GLGizmoMove3D::on_is_activable() const
|
||||
{
|
||||
return !m_parent.get_selection().is_empty();
|
||||
}
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
|
||||
void GLGizmoMove3D::on_start_dragging()
|
||||
{
|
||||
|
@ -33,9 +33,7 @@ public:
|
||||
protected:
|
||||
virtual bool on_init();
|
||||
virtual std::string on_get_name() const;
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
virtual bool on_is_activable() const;
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_stop_dragging();
|
||||
virtual void on_update(const UpdateData& data);
|
||||
|
@ -449,12 +449,10 @@ std::string GLGizmoRotate3D::on_get_name() const
|
||||
return (_(L("Rotate")) + " [R]").ToUTF8().data();
|
||||
}
|
||||
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
bool GLGizmoRotate3D::on_is_activable() const
|
||||
{
|
||||
return !m_parent.get_selection().is_empty();
|
||||
}
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
|
||||
void GLGizmoRotate3D::on_start_dragging()
|
||||
{
|
||||
|
@ -104,9 +104,7 @@ protected:
|
||||
if (id < 3)
|
||||
m_gizmos[id].disable_grabber(0);
|
||||
}
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
virtual bool on_is_activable() const;
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_stop_dragging();
|
||||
virtual void on_update(const UpdateData& data)
|
||||
|
@ -49,12 +49,8 @@ std::string GLGizmoScale3D::on_get_name() const
|
||||
|
||||
bool GLGizmoScale3D::on_is_activable() const
|
||||
{
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
return !selection.is_empty() && !selection.is_wipe_tower();
|
||||
#else
|
||||
return !m_parent.get_selection().is_wipe_tower();
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_start_dragging()
|
||||
|
@ -567,7 +567,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
||||
update_data();
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
// Let the platter know that the dragging finished, so a delayed refresh
|
||||
// Let the plater know that the dragging finished, so a delayed refresh
|
||||
// of the scene with the background processing data should be performed.
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
||||
// updates camera target constraints
|
||||
@ -861,13 +861,19 @@ void GLGizmosManager::render_background(float left, float top, float right, floa
|
||||
|
||||
void GLGizmosManager::do_render_overlay() const
|
||||
{
|
||||
#if ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
std::vector<size_t> selectable_idxs = get_selectable_idxs();
|
||||
if (selectable_idxs.empty())
|
||||
return;
|
||||
#else
|
||||
if (m_gizmos.empty())
|
||||
return;
|
||||
#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
|
||||
float cnv_w = (float)m_parent.get_canvas_size().get_width();
|
||||
float cnv_h = (float)m_parent.get_canvas_size().get_height();
|
||||
float zoom = (float)m_parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
float inv_zoom = (float)m_parent.get_camera().get_inv_zoom();
|
||||
|
||||
float height = get_scaled_total_height();
|
||||
float width = get_scaled_total_width();
|
||||
@ -893,23 +899,42 @@ void GLGizmosManager::do_render_overlay() const
|
||||
unsigned int icons_texture_id = m_icons_texture.get_id();
|
||||
int tex_width = m_icons_texture.get_width();
|
||||
int tex_height = m_icons_texture.get_height();
|
||||
float inv_tex_width = (tex_width != 0) ? 1.0f / tex_width : 0.0f;
|
||||
float inv_tex_height = (tex_height != 0) ? 1.0f / tex_height : 0.0f;
|
||||
|
||||
#if ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
if ((icons_texture_id == 0) || (tex_width <= 1) || (tex_height <= 1))
|
||||
return;
|
||||
|
||||
float du = (float)(tex_width - 1) / (4.0f * (float)tex_width); // 4 is the number of possible states if the icons
|
||||
float dv = (float)(tex_height - 1) / (float)(m_gizmos.size() * tex_height);
|
||||
|
||||
// tiles in the texture are spaced by 1 pixel
|
||||
float u_offset = 1.0f / (float)tex_width;
|
||||
float v_offset = 1.0f / (float)tex_height;
|
||||
#else
|
||||
if ((icons_texture_id == 0) || (tex_width <= 0) || (tex_height <= 0))
|
||||
return;
|
||||
|
||||
float inv_tex_width = (tex_width != 0) ? 1.0f / tex_width : 0.0f;
|
||||
float inv_tex_height = (tex_height != 0) ? 1.0f / tex_height : 0.0f;
|
||||
#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
|
||||
#if ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
for (size_t idx : selectable_idxs)
|
||||
#else
|
||||
for (size_t idx : get_selectable_idxs())
|
||||
#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
{
|
||||
GLGizmoBase* gizmo = m_gizmos[idx].get();
|
||||
|
||||
unsigned int sprite_id = gizmo->get_sprite_id();
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
int icon_idx = (m_current == idx) ? 2 : ((m_hover == idx) ? 1 : (gizmo->is_activable()? 0 : 3));
|
||||
#else
|
||||
int icon_idx = m_current == idx ? 2 : (m_hover == idx ? 1 : 0);
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
|
||||
#if ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
float v_top = v_offset + sprite_id * dv;
|
||||
float u_left = u_offset + icon_idx * du;
|
||||
float v_bottom = v_top + dv - v_offset;
|
||||
float u_right = u_left + du - u_offset;
|
||||
#else
|
||||
float u_icon_size = icons_size * inv_tex_width;
|
||||
float v_icon_size = icons_size * inv_tex_height;
|
||||
|
||||
@ -917,6 +942,7 @@ void GLGizmosManager::do_render_overlay() const
|
||||
float u_left = icon_idx * u_icon_size;
|
||||
float v_bottom = v_top + v_icon_size;
|
||||
float u_right = u_left + u_icon_size;
|
||||
#endif // ENABLE_MODIFIED_TOOLBAR_TEXTURES
|
||||
|
||||
GLTexture::render_sub_texture(icons_texture_id, zoomed_top_x, zoomed_top_x + zoomed_icons_size, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } });
|
||||
if (idx == m_current) {
|
||||
@ -960,9 +986,7 @@ bool GLGizmosManager::generate_icons_texture() const
|
||||
states.push_back(std::make_pair(1, false)); // Activable
|
||||
states.push_back(std::make_pair(0, false)); // Hovered
|
||||
states.push_back(std::make_pair(0, true)); // Selected
|
||||
#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
states.push_back(std::make_pair(2, false)); // Disabled
|
||||
#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
|
||||
|
||||
unsigned int sprite_size_px = (unsigned int)m_layout.scaled_icons_size();
|
||||
// // force even size
|
||||
|
@ -125,7 +125,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
|
||||
_3DScene::remove_all_canvases();
|
||||
// Slic3r::GUI::deregister_on_request_update_callback();
|
||||
|
||||
// set to null tabs and a platter
|
||||
// set to null tabs and a plater
|
||||
// to avoid any manipulations with them from App->wxEVT_IDLE after of the mainframe closing
|
||||
wxGetApp().tabs_list.clear();
|
||||
wxGetApp().plater_ = nullptr;
|
||||
@ -1007,7 +1007,7 @@ void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool re
|
||||
}
|
||||
|
||||
// Load a provied DynamicConfig into the Print / Filament / Printer tabs, thus modifying the active preset.
|
||||
// Also update the platter with the new presets.
|
||||
// Also update the plater with the new presets.
|
||||
void MainFrame::load_config(const DynamicPrintConfig& config)
|
||||
{
|
||||
PrinterTechnology printer_technology = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology();
|
||||
|
@ -125,7 +125,7 @@ public:
|
||||
void load_config(const DynamicPrintConfig& config);
|
||||
void select_tab(size_t tab) const;
|
||||
void select_view(const std::string& direction);
|
||||
// Propagate changed configuration from the Tab to the Platter and save changes to the AppConfig
|
||||
// Propagate changed configuration from the Tab to the Plater and save changes to the AppConfig
|
||||
void on_config_changed(DynamicPrintConfig* cfg) const ;
|
||||
|
||||
void add_to_recent_projects(const wxString& filename);
|
||||
|
@ -5,9 +5,7 @@
|
||||
#include "GUI_App.hpp"
|
||||
#include "PresetBundle.hpp"
|
||||
#include "AppConfig.hpp"
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
#include "GLCanvas3D.hpp"
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
#include <wx/glcanvas.h>
|
||||
|
||||
@ -156,7 +154,8 @@ bool Mouse3DController::State::apply(Camera& camera)
|
||||
{
|
||||
const Vec3d& translation = m_translation.queue.front();
|
||||
#if ENABLE_3DCONNEXION_Y_AS_ZOOM
|
||||
camera.set_target(camera.get_target() + m_translation_params.scale * (translation(0) * camera.get_dir_right() + translation(2) * camera.get_dir_up()));
|
||||
double zoom_factor = camera.min_zoom() / camera.get_zoom();
|
||||
camera.set_target(camera.get_target() + zoom_factor * m_translation_params.scale * (translation(0) * camera.get_dir_right() + translation(2) * camera.get_dir_up()));
|
||||
if (translation(1) != 0.0)
|
||||
camera.update_zoom(m_zoom_params.scale * translation(1) / std::abs(translation(1)));
|
||||
#else
|
||||
@ -168,12 +167,17 @@ bool Mouse3DController::State::apply(Camera& camera)
|
||||
|
||||
if (has_rotation())
|
||||
{
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
Vec3d rotation = (m_rotation_params.scale * m_rotation.queue.front()).cast<double>();
|
||||
camera.rotate_local_around_target(Vec3d(Geometry::deg2rad(rotation(0)), Geometry::deg2rad(-rotation(2)), Geometry::deg2rad(-rotation(1))));
|
||||
#else
|
||||
const Vec3f& rotation = m_rotation.queue.front();
|
||||
float theta = m_rotation_params.scale * rotation(0);
|
||||
float phi = m_rotation_params.scale * rotation(2);
|
||||
float sign = camera.inverted_phi ? -1.0f : 1.0f;
|
||||
camera.phi += sign * phi;
|
||||
camera.set_theta(camera.get_theta() + theta, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
m_rotation.queue.pop();
|
||||
ret = true;
|
||||
}
|
||||
@ -200,9 +204,7 @@ Mouse3DController::Mouse3DController()
|
||||
, m_device_str("")
|
||||
, m_running(false)
|
||||
, m_show_settings_dialog(false)
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
, m_settings_dialog_closed_by_user(false)
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
{
|
||||
m_last_time = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
@ -247,9 +249,7 @@ bool Mouse3DController::apply(Camera& camera)
|
||||
disconnect_device();
|
||||
// hides the settings dialog if the user un-plug the device
|
||||
m_show_settings_dialog = false;
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
m_settings_dialog_closed_by_user = false;
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
}
|
||||
|
||||
// check if the user plugged the device
|
||||
@ -259,16 +259,11 @@ bool Mouse3DController::apply(Camera& camera)
|
||||
return is_device_connected() ? m_state.apply(camera) : false;
|
||||
}
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
|
||||
#else
|
||||
void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
{
|
||||
if (!m_running || !m_show_settings_dialog)
|
||||
return;
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
// when the user clicks on [X] or [Close] button we need to trigger
|
||||
// an extra frame to let the dialog disappear
|
||||
if (m_settings_dialog_closed_by_user)
|
||||
@ -280,16 +275,10 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign
|
||||
}
|
||||
|
||||
Size cnv_size = canvas.get_canvas_size();
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
imgui.set_next_window_pos(0.5f * (float)cnv_size.get_width(), 0.5f * (float)cnv_size.get_height(), ImGuiCond_Always, 0.5f, 0.5f);
|
||||
#else
|
||||
imgui.set_next_window_pos(0.5f * (float)canvas_width, 0.5f * (float)canvas_height, ImGuiCond_Always, 0.5f, 0.5f);
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
static ImVec2 last_win_size(0.0f, 0.0f);
|
||||
bool shown = true;
|
||||
if (imgui.begin(_(L("3Dconnexion settings")), &shown, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse))
|
||||
@ -304,9 +293,6 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign
|
||||
last_win_size = win_size;
|
||||
canvas.request_extra_frame();
|
||||
}
|
||||
#else
|
||||
imgui.begin(_(L("3Dconnexion settings")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
const ImVec4& color = ImGui::GetStyleColorVec4(ImGuiCol_Separator);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
@ -321,16 +307,16 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
float translation_scale = (float)m_state.get_translation_scale() / State::DefaultTranslationScale;
|
||||
if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.2f, 5.0f, "%.1f"))
|
||||
if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.1f, 10.0f, "%.1f"))
|
||||
m_state.set_translation_scale(State::DefaultTranslationScale * (double)translation_scale);
|
||||
|
||||
float rotation_scale = m_state.get_rotation_scale() / State::DefaultRotationScale;
|
||||
if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.2f, 5.0f, "%.1f"))
|
||||
if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.1f, 10.0f, "%.1f"))
|
||||
m_state.set_rotation_scale(State::DefaultRotationScale * rotation_scale);
|
||||
|
||||
#if ENABLE_3DCONNEXION_Y_AS_ZOOM
|
||||
float zoom_scale = m_state.get_zoom_scale() / State::DefaultZoomScale;
|
||||
if (imgui.slider_float(_(L("Zoom")), &zoom_scale, 0.2f, 5.0f, "%.1f"))
|
||||
if (imgui.slider_float(_(L("Zoom")), &zoom_scale, 0.1f, 10.0f, "%.1f"))
|
||||
m_state.set_zoom_scale(State::DefaultZoomScale * zoom_scale);
|
||||
#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM
|
||||
|
||||
@ -389,7 +375,6 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign
|
||||
Vec3f target = wxGetApp().plater()->get_camera().get_target().cast<float>();
|
||||
ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
ImGui::Separator();
|
||||
if (imgui.button(_(L("Close"))))
|
||||
@ -406,7 +391,6 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign
|
||||
canvas.set_as_dirty();
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
imgui.end();
|
||||
}
|
||||
@ -631,13 +615,16 @@ bool Mouse3DController::connect_device()
|
||||
|
||||
if (m_device != nullptr)
|
||||
{
|
||||
std::vector<wchar_t> manufacturer(1024, 0);
|
||||
hid_get_manufacturer_string(m_device, manufacturer.data(), 1024);
|
||||
m_device_str = boost::nowide::narrow(manufacturer.data());
|
||||
wchar_t buffer[1024];
|
||||
hid_get_manufacturer_string(m_device, buffer, 1024);
|
||||
m_device_str = boost::nowide::narrow(buffer);
|
||||
// #3479 seems to show that sometimes an extra whitespace is added, so we remove it
|
||||
boost::algorithm::trim(m_device_str);
|
||||
|
||||
std::vector<wchar_t> product(1024, 0);
|
||||
hid_get_product_string(m_device, product.data(), 1024);
|
||||
m_device_str += "/" + boost::nowide::narrow(product.data());
|
||||
hid_get_product_string(m_device, buffer, 1024);
|
||||
m_device_str += "/" + boost::nowide::narrow(buffer);
|
||||
// #3479 seems to show that sometimes an extra whitespace is added, so we remove it
|
||||
boost::algorithm::trim(m_device_str);
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Connected 3DConnexion device:";
|
||||
BOOST_LOG_TRIVIAL(info) << "Manufacturer/product: " << m_device_str;
|
||||
@ -647,12 +634,12 @@ bool Mouse3DController::connect_device()
|
||||
BOOST_LOG_TRIVIAL(info) << "Path................: '" << path << "'";
|
||||
|
||||
// get device parameters from the config, if present
|
||||
double translation_speed = 1.0;
|
||||
float rotation_speed = 1.0;
|
||||
double translation_speed = 4.0;
|
||||
float rotation_speed = 4.0;
|
||||
double translation_deadzone = State::DefaultTranslationDeadzone;
|
||||
float rotation_deadzone = State::DefaultRotationDeadzone;
|
||||
#if ENABLE_3DCONNEXION_Y_AS_ZOOM
|
||||
double zoom_speed = 1.0;
|
||||
double zoom_speed = 2.0;
|
||||
#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM
|
||||
wxGetApp().app_config->get_mouse_device_translation_speed(m_device_str, translation_speed);
|
||||
wxGetApp().app_config->get_mouse_device_translation_deadzone(m_device_str, translation_deadzone);
|
||||
@ -662,12 +649,12 @@ bool Mouse3DController::connect_device()
|
||||
wxGetApp().app_config->get_mouse_device_zoom_speed(m_device_str, zoom_speed);
|
||||
#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM
|
||||
// clamp to valid values
|
||||
m_state.set_translation_scale(State::DefaultTranslationScale * std::clamp(translation_speed, 0.2, 5.0));
|
||||
m_state.set_translation_scale(State::DefaultTranslationScale * std::clamp(translation_speed, 0.1, 10.0));
|
||||
m_state.set_translation_deadzone(std::clamp(translation_deadzone, 0.0, State::MaxTranslationDeadzone));
|
||||
m_state.set_rotation_scale(State::DefaultRotationScale * std::clamp(rotation_speed, 0.2f, 5.0f));
|
||||
m_state.set_rotation_scale(State::DefaultRotationScale * std::clamp(rotation_speed, 0.1f, 10.0f));
|
||||
m_state.set_rotation_deadzone(std::clamp(rotation_deadzone, 0.0f, State::MaxRotationDeadzone));
|
||||
#if ENABLE_3DCONNEXION_Y_AS_ZOOM
|
||||
m_state.set_zoom_scale(State::DefaultZoomScale * std::clamp(zoom_speed, 0.2, 5.0));
|
||||
m_state.set_zoom_scale(State::DefaultZoomScale * std::clamp(zoom_speed, 0.1, 10.0));
|
||||
#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM
|
||||
}
|
||||
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
@ -874,9 +861,15 @@ bool Mouse3DController::handle_packet_translation(const DataPacket& packet)
|
||||
bool Mouse3DController::handle_packet_rotation(const DataPacket& packet, unsigned int first_byte)
|
||||
{
|
||||
double deadzone = (double)m_state.get_rotation_deadzone();
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
Vec3f rotation((float)convert_input(packet[first_byte + 0], packet[first_byte + 1], deadzone),
|
||||
(float)convert_input(packet[first_byte + 2], packet[first_byte + 3], deadzone),
|
||||
(float)convert_input(packet[first_byte + 4], packet[first_byte + 5], deadzone));
|
||||
#else
|
||||
Vec3f rotation(-(float)convert_input(packet[first_byte + 0], packet[first_byte + 1], deadzone),
|
||||
(float)convert_input(packet[first_byte + 2], packet[first_byte + 3], deadzone),
|
||||
-(float)convert_input(packet[first_byte + 4], packet[first_byte + 5], deadzone));
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
if (!rotation.isApprox(Vec3f::Zero()))
|
||||
{
|
||||
|
@ -18,9 +18,7 @@ namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
struct Camera;
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
class GLCanvas3D;
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
class Mouse3DController
|
||||
{
|
||||
@ -68,7 +66,7 @@ class Mouse3DController
|
||||
CustomParameters<double> m_translation_params;
|
||||
CustomParameters<float> m_rotation_params;
|
||||
#if ENABLE_3DCONNEXION_Y_AS_ZOOM
|
||||
CustomParameters<float> m_zoom_params;
|
||||
CustomParameters<double> m_zoom_params;
|
||||
#endif // ENABLE_3DCONNEXION_Y_AS_ZOOM
|
||||
|
||||
// When the 3Dconnexion driver is running the system gets, by default, mouse wheel events when rotations around the X axis are detected.
|
||||
@ -143,13 +141,9 @@ class Mouse3DController
|
||||
hid_device* m_device;
|
||||
std::string m_device_str;
|
||||
bool m_running;
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
mutable bool m_show_settings_dialog;
|
||||
// set to true when ther user closes the dialog by clicking on [X] or [Close] buttons
|
||||
mutable bool m_settings_dialog_closed_by_user;
|
||||
#else
|
||||
bool m_show_settings_dialog;
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> m_last_time;
|
||||
|
||||
public:
|
||||
@ -167,11 +161,7 @@ public:
|
||||
|
||||
bool is_settings_dialog_shown() const { return m_show_settings_dialog; }
|
||||
void show_settings_dialog(bool show) { m_show_settings_dialog = show && is_running(); }
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
void render_settings_dialog(GLCanvas3D& canvas) const;
|
||||
#else
|
||||
void render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const;
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
private:
|
||||
bool connect_device();
|
||||
|
@ -326,7 +326,7 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 *
|
||||
cfg_new.set_key_value("extruder_colour", colors);
|
||||
|
||||
wxGetApp().get_tab(Preset::TYPE_PRINTER)->load_config(cfg_new);
|
||||
wxGetApp().preset_bundle->update_platter_filament_ui(extruder_idx, this);
|
||||
wxGetApp().preset_bundle->update_plater_filament_ui(extruder_idx, this);
|
||||
wxGetApp().plater()->on_config_change(cfg_new);
|
||||
}
|
||||
});
|
||||
@ -952,18 +952,18 @@ void Sidebar::update_all_preset_comboboxes()
|
||||
|
||||
// Update the print choosers to only contain the compatible presets, update the dirty flags.
|
||||
if (print_tech == ptFFF)
|
||||
preset_bundle.prints.update_platter_ui(p->combo_print);
|
||||
preset_bundle.prints.update_plater_ui(p->combo_print);
|
||||
else {
|
||||
preset_bundle.sla_prints.update_platter_ui(p->combo_sla_print);
|
||||
preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material);
|
||||
preset_bundle.sla_prints.update_plater_ui(p->combo_sla_print);
|
||||
preset_bundle.sla_materials.update_plater_ui(p->combo_sla_material);
|
||||
}
|
||||
// Update the printer choosers, update the dirty flags.
|
||||
preset_bundle.printers.update_platter_ui(p->combo_printer);
|
||||
preset_bundle.printers.update_plater_ui(p->combo_printer);
|
||||
// Update the filament choosers to only contain the compatible presets, update the color preview,
|
||||
// update the dirty flags.
|
||||
if (print_tech == ptFFF) {
|
||||
for (size_t i = 0; i < p->combos_filament.size(); ++i)
|
||||
preset_bundle.update_platter_filament_ui(i, p->combos_filament[i]);
|
||||
preset_bundle.update_plater_filament_ui(i, p->combos_filament[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -986,22 +986,22 @@ void Sidebar::update_presets(Preset::Type preset_type)
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < filament_cnt; i++) {
|
||||
preset_bundle.update_platter_filament_ui(i, p->combos_filament[i]);
|
||||
preset_bundle.update_plater_filament_ui(i, p->combos_filament[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Preset::TYPE_PRINT:
|
||||
preset_bundle.prints.update_platter_ui(p->combo_print);
|
||||
preset_bundle.prints.update_plater_ui(p->combo_print);
|
||||
break;
|
||||
|
||||
case Preset::TYPE_SLA_PRINT:
|
||||
preset_bundle.sla_prints.update_platter_ui(p->combo_sla_print);
|
||||
preset_bundle.sla_prints.update_plater_ui(p->combo_sla_print);
|
||||
break;
|
||||
|
||||
case Preset::TYPE_SLA_MATERIAL:
|
||||
preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material);
|
||||
preset_bundle.sla_materials.update_plater_ui(p->combo_sla_material);
|
||||
break;
|
||||
|
||||
case Preset::TYPE_PRINTER:
|
||||
@ -1195,9 +1195,9 @@ void Sidebar::update_sliced_info_sizer()
|
||||
{
|
||||
double material_cost = cfg->option("bottle_cost")->getFloat() /
|
||||
cfg->option("bottle_volume")->getFloat();
|
||||
str_total_cost = wxString::Format("%.2f", material_cost*(ps.objects_used_material + ps.support_used_material) / 1000);
|
||||
str_total_cost = wxString::Format("%.3f", material_cost*(ps.objects_used_material + ps.support_used_material) / 1000);
|
||||
}
|
||||
p->sliced_info->SetTextAndShow(siCost, str_total_cost);
|
||||
p->sliced_info->SetTextAndShow(siCost, str_total_cost, "Cost");
|
||||
|
||||
wxString t_est = std::isnan(ps.estimated_print_time) ? "N/A" : get_time_dhms(float(ps.estimated_print_time));
|
||||
p->sliced_info->SetTextAndShow(siEstimatedTime, t_est, _(L("Estimated printing time")) + " :");
|
||||
@ -1774,9 +1774,7 @@ struct Plater::priv
|
||||
|
||||
void set_current_canvas_as_dirty();
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
bool init_view_toolbar();
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
void reset_all_gizmos();
|
||||
void update_ui_from_settings();
|
||||
@ -1924,9 +1922,6 @@ private:
|
||||
bool complit_init_object_menu();
|
||||
bool complit_init_sla_object_menu();
|
||||
bool complit_init_part_menu();
|
||||
#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
void init_view_toolbar();
|
||||
#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
bool can_split() const;
|
||||
bool layers_height_allowed() const;
|
||||
@ -1995,7 +1990,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
background_process.set_finished_event(EVT_PROCESS_COMPLETED);
|
||||
// Default printer technology for default config.
|
||||
background_process.select_technology(this->printer_technology);
|
||||
// Register progress callback from the Print class to the Platter.
|
||||
// Register progress callback from the Print class to the Plater.
|
||||
|
||||
auto statuscb = [this](const Slic3r::PrintBase::SlicingStatus &status) {
|
||||
wxQueueEvent(this->q, new Slic3r::SlicingStatusEvent(EVT_SLICING_UPDATE, 0, status));
|
||||
@ -2060,11 +2055,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_RESETGIZMOS, [this](SimpleEvent&) { reset_all_gizmos(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_UNDO, [this](SimpleEvent&) { this->undo(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_REDO, [this](SimpleEvent&) { this->redo(); });
|
||||
#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, [this](SimpleEvent&) { this->view3D->get_canvas3d()->reset_layer_height_profile(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, [this](Event<float>& evt) { this->view3D->get_canvas3d()->adaptive_layer_height_profile(evt.data); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, [this](HeightProfileSmoothEvent& evt) { this->view3D->get_canvas3d()->smooth_layer_height_profile(evt.data); });
|
||||
#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
|
||||
|
||||
// 3DScene/Toolbar:
|
||||
view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this);
|
||||
@ -2078,9 +2071,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_OBJECTS, &priv::on_action_split_objects, this);
|
||||
view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_VOLUMES, &priv::on_action_split_volumes, this);
|
||||
view3D_canvas->Bind(EVT_GLTOOLBAR_LAYERSEDITING, &priv::on_action_layersediting, this);
|
||||
#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_INIT, [this](SimpleEvent&) { init_view_toolbar(); });
|
||||
#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [this](SimpleEvent&)
|
||||
{
|
||||
set_bed_shape(config->option<ConfigOptionPoints>("bed_shape")->values,
|
||||
@ -2276,7 +2266,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
if (object->volumes.size() > 1)
|
||||
{
|
||||
Slic3r::GUI::show_info(nullptr,
|
||||
_(L("You can't load SLA project if there is at least one multi-part object on the bed")) + "\n\n" +
|
||||
_(L("You cannot load SLA project with a multi-part object on the bed")) + "\n\n" +
|
||||
_(L("Please check your object list before preset changing.")),
|
||||
_(L("Attention!")));
|
||||
return obj_idxs;
|
||||
@ -2709,7 +2699,7 @@ void Plater::priv::reset()
|
||||
// The hiding of the slicing results, if shown, is not taken care by the background process, so we do it here
|
||||
this->sidebar->show_sliced_info_sizer(false);
|
||||
|
||||
model.custom_gcode_per_print_z.clear();
|
||||
model.custom_gcode_per_print_z.gcodes.clear();
|
||||
}
|
||||
|
||||
void Plater::priv::mirror(Axis axis)
|
||||
@ -3008,7 +2998,6 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
|
||||
this->update_print_volume_state();
|
||||
// Apply new config to the possibly running background task.
|
||||
bool was_running = this->background_process.running();
|
||||
this->background_process.set_force_update_print_regions(force_validation);
|
||||
Print::ApplyStatus invalidated = this->background_process.apply(this->q->model(), wxGetApp().preset_bundle->full_config());
|
||||
|
||||
// Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile.
|
||||
@ -3228,12 +3217,9 @@ void Plater::priv::reload_from_disk()
|
||||
|
||||
// collects paths of files to load
|
||||
std::vector<fs::path> input_paths;
|
||||
#if ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
|
||||
std::vector<fs::path> missing_input_paths;
|
||||
#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
|
||||
for (const SelectedVolume& v : selected_volumes)
|
||||
{
|
||||
#if ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
|
||||
const ModelObject* object = model.objects[v.object_idx];
|
||||
const ModelVolume* volume = object->volumes[v.volume_idx];
|
||||
|
||||
@ -3244,14 +3230,8 @@ void Plater::priv::reload_from_disk()
|
||||
else
|
||||
missing_input_paths.push_back(volume->source.input_file);
|
||||
}
|
||||
#else
|
||||
const ModelVolume* volume = model.objects[v.object_idx]->volumes[v.volume_idx];
|
||||
if (!volume->source.input_file.empty() && boost::filesystem::exists(volume->source.input_file))
|
||||
input_paths.push_back(volume->source.input_file);
|
||||
#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
|
||||
}
|
||||
|
||||
#if ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
|
||||
std::sort(missing_input_paths.begin(), missing_input_paths.end());
|
||||
missing_input_paths.erase(std::unique(missing_input_paths.begin(), missing_input_paths.end()), missing_input_paths.end());
|
||||
|
||||
@ -3301,7 +3281,6 @@ void Plater::priv::reload_from_disk()
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
|
||||
|
||||
std::sort(input_paths.begin(), input_paths.end());
|
||||
input_paths.erase(std::unique(input_paths.begin(), input_paths.end()), input_paths.end());
|
||||
@ -3347,27 +3326,17 @@ void Plater::priv::reload_from_disk()
|
||||
new_volume->config.apply(old_volume->config);
|
||||
new_volume->set_type(old_volume->type());
|
||||
new_volume->set_material_id(old_volume->material_id());
|
||||
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
new_volume->set_transformation(old_volume->get_transformation() * old_volume->source.transform);
|
||||
#else
|
||||
new_volume->set_transformation(old_volume->get_transformation());
|
||||
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
|
||||
new_volume->source.input_file = path;
|
||||
std::swap(old_model_object->volumes[old_v.volume_idx], old_model_object->volumes.back());
|
||||
old_model_object->delete_volume(old_model_object->volumes.size() - 1);
|
||||
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
old_model_object->ensure_on_bed();
|
||||
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
model.adjust_min_z();
|
||||
#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
|
||||
|
||||
// update 3D scene
|
||||
update();
|
||||
|
||||
@ -3490,8 +3459,8 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
|
||||
|
||||
// TODO: ?
|
||||
if (preset_type == Preset::TYPE_FILAMENT && sidebar->is_multifilament()) {
|
||||
// Only update the platter UI for the 2nd and other filaments.
|
||||
wxGetApp().preset_bundle->update_platter_filament_ui(idx, combo);
|
||||
// Only update the plater UI for the 2nd and other filaments.
|
||||
wxGetApp().preset_bundle->update_plater_filament_ui(idx, combo);
|
||||
}
|
||||
else {
|
||||
wxWindowUpdateLocker noUpdates(sidebar->presets_panel());
|
||||
@ -3981,17 +3950,11 @@ void Plater::priv::set_current_canvas_as_dirty()
|
||||
preview->set_as_dirty();
|
||||
}
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
bool Plater::priv::init_view_toolbar()
|
||||
#else
|
||||
void Plater::priv::init_view_toolbar()
|
||||
#endif //!ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
{
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
if (view_toolbar.get_items_count() > 0)
|
||||
// already initialized
|
||||
return true;
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
BackgroundTexture::Metadata background_data;
|
||||
background_data.filename = "toolbar_background.png";
|
||||
@ -4001,11 +3964,7 @@ void Plater::priv::init_view_toolbar()
|
||||
background_data.bottom = 16;
|
||||
|
||||
if (!view_toolbar.init(background_data))
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
return false;
|
||||
#else
|
||||
return;
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
view_toolbar.set_horizontal_orientation(GLToolbar::Layout::HO_Left);
|
||||
view_toolbar.set_vertical_orientation(GLToolbar::Layout::VO_Bottom);
|
||||
@ -4020,11 +3979,7 @@ void Plater::priv::init_view_toolbar()
|
||||
item.sprite_id = 0;
|
||||
item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_3D)); };
|
||||
if (!view_toolbar.add_item(item))
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
return false;
|
||||
#else
|
||||
return;
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
item.name = "Preview";
|
||||
item.icon_filename = "preview.svg";
|
||||
@ -4032,18 +3987,12 @@ void Plater::priv::init_view_toolbar()
|
||||
item.sprite_id = 1;
|
||||
item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); };
|
||||
if (!view_toolbar.add_item(item))
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
return false;
|
||||
#else
|
||||
return;
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
view_toolbar.select_item("3D");
|
||||
view_toolbar.set_enabled(true);
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
return true;
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
}
|
||||
|
||||
bool Plater::priv::can_set_instance_to_object() const
|
||||
@ -4108,11 +4057,7 @@ bool Plater::priv::can_reload_from_disk() const
|
||||
for (const SelectedVolume& v : selected_volumes)
|
||||
{
|
||||
const ModelVolume* volume = model.objects[v.object_idx]->volumes[v.volume_idx];
|
||||
#if ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
|
||||
if (!volume->source.input_file.empty())
|
||||
#else
|
||||
if (!volume->source.input_file.empty() && boost::filesystem::exists(volume->source.input_file))
|
||||
#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
|
||||
paths.push_back(volume->source.input_file);
|
||||
}
|
||||
std::sort(paths.begin(), paths.end());
|
||||
@ -4895,7 +4840,12 @@ void Plater::export_amf()
|
||||
wxBusyCursor wait;
|
||||
bool export_config = true;
|
||||
DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure();
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
bool full_pathnames = wxGetApp().app_config->get("export_sources_full_pathnames") == "1";
|
||||
if (Slic3r::store_amf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames)) {
|
||||
#else
|
||||
if (Slic3r::store_amf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) {
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
// Success
|
||||
p->statusbar()->set_status_text(wxString::Format(_(L("AMF file exported to %s")), path));
|
||||
} else {
|
||||
@ -4924,6 +4874,16 @@ void Plater::export_3mf(const boost::filesystem::path& output_path)
|
||||
DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure();
|
||||
const std::string path_u8 = into_u8(path);
|
||||
wxBusyCursor wait;
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
bool full_pathnames = wxGetApp().app_config->get("export_sources_full_pathnames") == "1";
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
ThumbnailData thumbnail_data;
|
||||
p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false, true, true, true);
|
||||
if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames, &thumbnail_data)) {
|
||||
#else
|
||||
if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames)) {
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#else
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
ThumbnailData thumbnail_data;
|
||||
p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false, true, true, true);
|
||||
@ -4931,6 +4891,7 @@ void Plater::export_3mf(const boost::filesystem::path& output_path)
|
||||
#else
|
||||
if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) {
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
// Success
|
||||
p->statusbar()->set_status_text(wxString::Format(_(L("3MF file exported to %s")), path));
|
||||
p->set_project_filename(path);
|
||||
@ -5158,7 +5119,7 @@ void Plater::on_extruders_change(size_t num_extruders)
|
||||
choices.push_back(choice);
|
||||
|
||||
// initialize selection
|
||||
wxGetApp().preset_bundle->update_platter_filament_ui(i, choice);
|
||||
wxGetApp().preset_bundle->update_plater_filament_ui(i, choice);
|
||||
++i;
|
||||
}
|
||||
|
||||
@ -5325,9 +5286,9 @@ std::vector<std::string> Plater::get_extruder_colors_from_plater_config() const
|
||||
std::vector<std::string> Plater::get_colors_for_color_print() const
|
||||
{
|
||||
std::vector<std::string> colors = get_extruder_colors_from_plater_config();
|
||||
colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.size());
|
||||
colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.gcodes.size());
|
||||
|
||||
for (const Model::CustomGCode& code : p->model.custom_gcode_per_print_z)
|
||||
for (const Model::CustomGCode& code : p->model.custom_gcode_per_print_z.gcodes)
|
||||
if (code.gcode == ColorChangeCode)
|
||||
colors.emplace_back(code.color);
|
||||
|
||||
@ -5491,12 +5452,10 @@ void Plater::msw_rescale()
|
||||
GetParent()->Layout();
|
||||
}
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
bool Plater::init_view_toolbar()
|
||||
{
|
||||
return p->init_view_toolbar();
|
||||
}
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
const Camera& Plater::get_camera() const
|
||||
{
|
||||
|
@ -267,9 +267,7 @@ public:
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
bool init_view_toolbar();
|
||||
#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
|
||||
|
||||
const Camera& get_camera() const;
|
||||
const Mouse3DController& get_mouse3d_controller() const;
|
||||
|
@ -19,16 +19,11 @@ PreferencesDialog::PreferencesDialog(wxWindow* parent) :
|
||||
void PreferencesDialog::build()
|
||||
{
|
||||
auto app_config = get_app_config();
|
||||
m_optgroup = std::make_shared<ConfigOptionsGroup>(this, _(L("General")));
|
||||
m_optgroup->label_width = 40;
|
||||
m_optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||
m_optgroup_general = std::make_shared<ConfigOptionsGroup>(this, _(L("General")));
|
||||
m_optgroup_general->label_width = 40;
|
||||
m_optgroup_general->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||
m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0";
|
||||
|
||||
if (opt_key == "use_custom_toolbar_size") {
|
||||
m_icon_size_sizer->ShowItems(boost::any_cast<bool>(value));
|
||||
this->layout();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// TODO
|
||||
// $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
|
||||
@ -47,7 +42,7 @@ void PreferencesDialog::build()
|
||||
"instead of the one containing the input files.");
|
||||
def.set_default_value(new ConfigOptionBool{ app_config->has("remember_output_path") ? app_config->get("remember_output_path") == "1" : true });
|
||||
Option option(def, "remember_output_path");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
|
||||
def.label = L("Auto-center parts");
|
||||
def.type = coBool;
|
||||
@ -55,7 +50,7 @@ void PreferencesDialog::build()
|
||||
"around the print bed center.");
|
||||
def.set_default_value(new ConfigOptionBool{ app_config->get("autocenter") == "1" });
|
||||
option = Option (def,"autocenter");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
|
||||
def.label = L("Background processing");
|
||||
def.type = coBool;
|
||||
@ -63,7 +58,7 @@ void PreferencesDialog::build()
|
||||
"as they\'re loaded in order to save time when exporting G-code.");
|
||||
def.set_default_value(new ConfigOptionBool{ app_config->get("background_processing") == "1" });
|
||||
option = Option (def,"background_processing");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
|
||||
// Please keep in sync with ConfigWizard
|
||||
def.label = L("Check for application updates");
|
||||
@ -71,7 +66,17 @@ void PreferencesDialog::build()
|
||||
def.tooltip = L("If enabled, PrusaSlicer will check for the new versions of itself online. When a new version becomes available a notification is displayed at the next application startup (never during program usage). This is only a notification mechanisms, no automatic installation is done.");
|
||||
def.set_default_value(new ConfigOptionBool(app_config->get("version_check") == "1"));
|
||||
option = Option (def, "version_check");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
// Please keep in sync with ConfigWizard
|
||||
def.label = L("Export sources full pathnames to 3mf and amf");
|
||||
def.type = coBool;
|
||||
def.tooltip = L("If enabled, allows the Reload from disk command to automatically find and load the files when invoked.");
|
||||
def.set_default_value(new ConfigOptionBool(app_config->get("export_sources_full_pathnames") == "1"));
|
||||
option = Option(def, "export_sources_full_pathnames");
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
|
||||
// Please keep in sync with ConfigWizard
|
||||
def.label = L("Update built-in Presets automatically");
|
||||
@ -79,7 +84,7 @@ void PreferencesDialog::build()
|
||||
def.tooltip = L("If enabled, Slic3r downloads updates of built-in system presets in the background. These updates are downloaded into a separate temporary location. When a new preset version becomes available it is offered at application startup.");
|
||||
def.set_default_value(new ConfigOptionBool(app_config->get("preset_update") == "1"));
|
||||
option = Option (def, "preset_update");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
|
||||
def.label = L("Suppress \" - default - \" presets");
|
||||
def.type = coBool;
|
||||
@ -87,7 +92,7 @@ void PreferencesDialog::build()
|
||||
"selections once there are any other valid presets available.");
|
||||
def.set_default_value(new ConfigOptionBool{ app_config->get("no_defaults") == "1" });
|
||||
option = Option (def,"no_defaults");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
|
||||
def.label = L("Show incompatible print and filament presets");
|
||||
def.type = coBool;
|
||||
@ -95,7 +100,7 @@ void PreferencesDialog::build()
|
||||
"even if they are marked as incompatible with the active printer");
|
||||
def.set_default_value(new ConfigOptionBool{ app_config->get("show_incompatible_presets") == "1" });
|
||||
option = Option (def,"show_incompatible_presets");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
|
||||
#if __APPLE__
|
||||
def.label = L("Use Retina resolution for the 3D scene");
|
||||
@ -104,28 +109,55 @@ void PreferencesDialog::build()
|
||||
"If you are experiencing 3D performance problems, disabling this option may help.");
|
||||
def.set_default_value(new ConfigOptionBool{ app_config->get("use_retina_opengl") == "1" });
|
||||
option = Option (def, "use_retina_opengl");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
#endif
|
||||
|
||||
def.label = L("Use perspective camera");
|
||||
def.type = coBool;
|
||||
def.tooltip = L("If enabled, use perspective camera. If not enabled, use orthographic camera.");
|
||||
def.set_default_value(new ConfigOptionBool{ app_config->get("use_perspective_camera") == "1" });
|
||||
option = Option(def, "use_perspective_camera");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
m_optgroup_camera = std::make_shared<ConfigOptionsGroup>(this, _(L("Camera")));
|
||||
m_optgroup_camera->label_width = 40;
|
||||
m_optgroup_camera->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||
m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0";
|
||||
};
|
||||
|
||||
def.label = L("Use perspective camera");
|
||||
def.type = coBool;
|
||||
def.tooltip = L("If enabled, use perspective camera. If not enabled, use orthographic camera.");
|
||||
def.set_default_value(new ConfigOptionBool{ app_config->get("use_perspective_camera") == "1" });
|
||||
option = Option(def, "use_perspective_camera");
|
||||
m_optgroup_camera->append_single_option_line(option);
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
def.label = L("Use free camera");
|
||||
def.type = coBool;
|
||||
def.tooltip = L("If enabled, use free camera. If not enabled, use constrained camera.");
|
||||
def.set_default_value(new ConfigOptionBool(app_config->get("use_free_camera") == "1"));
|
||||
option = Option(def, "use_free_camera");
|
||||
m_optgroup_camera->append_single_option_line(option);
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
m_optgroup_gui = std::make_shared<ConfigOptionsGroup>(this, _(L("GUI")));
|
||||
m_optgroup_gui->label_width = 40;
|
||||
m_optgroup_gui->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||
m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0";
|
||||
if (opt_key == "use_custom_toolbar_size") {
|
||||
m_icon_size_sizer->ShowItems(boost::any_cast<bool>(value));
|
||||
this->layout();
|
||||
}
|
||||
};
|
||||
|
||||
def.label = L("Use custom size for toolbar icons");
|
||||
def.type = coBool;
|
||||
def.tooltip = L("If enabled, you can change size of toolbar icons manually.");
|
||||
def.set_default_value(new ConfigOptionBool{ app_config->get("use_custom_toolbar_size") == "1" });
|
||||
option = Option (def,"use_custom_toolbar_size");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
option = Option(def, "use_custom_toolbar_size");
|
||||
m_optgroup_gui->append_single_option_line(option);
|
||||
|
||||
create_icon_size_slider();
|
||||
m_icon_size_sizer->ShowItems(app_config->get("use_custom_toolbar_size") == "1");
|
||||
create_icon_size_slider();
|
||||
m_icon_size_sizer->ShowItems(app_config->get("use_custom_toolbar_size") == "1");
|
||||
|
||||
auto sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(m_optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
||||
sizer->Add(m_optgroup_general->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
||||
sizer->Add(m_optgroup_camera->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
||||
sizer->Add(m_optgroup_gui->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
||||
|
||||
SetFont(wxGetApp().normal_font());
|
||||
|
||||
@ -157,7 +189,9 @@ void PreferencesDialog::accept()
|
||||
|
||||
void PreferencesDialog::on_dpi_changed(const wxRect &suggested_rect)
|
||||
{
|
||||
m_optgroup->msw_rescale();
|
||||
m_optgroup_general->msw_rescale();
|
||||
m_optgroup_camera->msw_rescale();
|
||||
m_optgroup_gui->msw_rescale();
|
||||
|
||||
msw_buttons_rescale(this, em_unit(), { wxID_OK, wxID_CANCEL });
|
||||
|
||||
@ -182,7 +216,7 @@ void PreferencesDialog::create_icon_size_slider()
|
||||
|
||||
m_icon_size_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
wxWindow* parent = m_optgroup->ctrl_parent();
|
||||
wxWindow* parent = m_optgroup_gui->ctrl_parent();
|
||||
|
||||
if (isOSX)
|
||||
// For correct rendering of the slider and value label under OSX
|
||||
@ -230,8 +264,9 @@ void PreferencesDialog::create_icon_size_slider()
|
||||
win->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
}
|
||||
|
||||
m_optgroup->sizer->Add(m_icon_size_sizer, 0, wxEXPAND | wxALL, em);
|
||||
m_optgroup_gui->sizer->Add(m_icon_size_sizer, 0, wxEXPAND | wxALL, em);
|
||||
}
|
||||
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
@ -15,8 +15,10 @@ class ConfigOptionsGroup;
|
||||
class PreferencesDialog : public DPIDialog
|
||||
{
|
||||
std::map<std::string, std::string> m_values;
|
||||
std::shared_ptr<ConfigOptionsGroup> m_optgroup;
|
||||
wxSizer* m_icon_size_sizer;
|
||||
std::shared_ptr<ConfigOptionsGroup> m_optgroup_general;
|
||||
std::shared_ptr<ConfigOptionsGroup> m_optgroup_camera;
|
||||
std::shared_ptr<ConfigOptionsGroup> m_optgroup_gui;
|
||||
wxSizer* m_icon_size_sizer;
|
||||
bool isOSX {false};
|
||||
public:
|
||||
PreferencesDialog(wxWindow* parent);
|
||||
|
@ -184,6 +184,16 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: Malformed variants field: `%2%`") % id % variants_field;
|
||||
}
|
||||
auto default_materials_field = section.second.get<std::string>("default_materials", "");
|
||||
if (default_materials_field.empty())
|
||||
default_materials_field = section.second.get<std::string>("default_filaments", "");
|
||||
if (Slic3r::unescape_strings_cstyle(default_materials_field, model.default_materials)) {
|
||||
Slic3r::sort_remove_duplicates(model.default_materials);
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: Malformed default_materials field: `%2%`") % id % default_materials_field;
|
||||
}
|
||||
model.bed_model = section.second.get<std::string>("bed_model", "");
|
||||
model.bed_texture = section.second.get<std::string>("bed_texture", "");
|
||||
if (! model.id.empty() && ! model.variants.empty())
|
||||
res.models.push_back(std::move(model));
|
||||
}
|
||||
@ -1020,7 +1030,7 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil
|
||||
|
||||
// Update the wxChoice UI component from this list of presets.
|
||||
// Hide the
|
||||
void PresetCollection::update_platter_ui(GUI::PresetComboBox *ui)
|
||||
void PresetCollection::update_plater_ui(GUI::PresetComboBox *ui)
|
||||
{
|
||||
if (ui == nullptr)
|
||||
return;
|
||||
@ -1504,4 +1514,20 @@ const Preset* PrinterPresetCollection::find_by_model_id(const std::string &model
|
||||
return it != cend() ? &*it : nullptr;
|
||||
}
|
||||
|
||||
namespace PresetUtils {
|
||||
const VendorProfile::PrinterModel* system_printer_model(const Preset &preset)
|
||||
{
|
||||
const VendorProfile::PrinterModel *out = nullptr;
|
||||
if (preset.vendor != nullptr) {
|
||||
auto *printer_model = preset.config.opt<ConfigOptionString>("printer_model");
|
||||
if (printer_model != nullptr && ! printer_model->value.empty()) {
|
||||
auto it = std::find_if(preset.vendor->models.begin(), preset.vendor->models.end(), [printer_model](const VendorProfile::PrinterModel &pm) { return pm.id == printer_model->value; });
|
||||
if (it != preset.vendor->models.end())
|
||||
out = &(*it);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
} // namespace PresetUtils
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -61,6 +61,10 @@ public:
|
||||
PrinterTechnology technology;
|
||||
std::string family;
|
||||
std::vector<PrinterVariant> variants;
|
||||
std::vector<std::string> default_materials;
|
||||
// Vendor & Printer Model specific print bed model & texture.
|
||||
std::string bed_model;
|
||||
std::string bed_texture;
|
||||
|
||||
PrinterVariant* variant(const std::string &name) {
|
||||
for (auto &v : this->variants)
|
||||
@ -380,7 +384,8 @@ public:
|
||||
size_t n = this->m_presets.size();
|
||||
size_t i_compatible = n;
|
||||
for (; i < n; ++ i)
|
||||
if (m_presets[i].is_compatible) {
|
||||
// Since we use the filament selection from Wizard, it's needed to control the preset visibility too
|
||||
if (m_presets[i].is_compatible && m_presets[i].is_visible) {
|
||||
if (prefered_condition(m_presets[i].name))
|
||||
return i;
|
||||
if (i_compatible == n)
|
||||
@ -437,7 +442,7 @@ public:
|
||||
// Update the choice UI from the list of presets.
|
||||
// Only the compatible presets are shown.
|
||||
// If an incompatible preset is selected, it is shown as well.
|
||||
void update_platter_ui(GUI::PresetComboBox *ui);
|
||||
void update_plater_ui(GUI::PresetComboBox *ui);
|
||||
|
||||
// Update a dirty floag of the current preset, update the labels of the UI component accordingly.
|
||||
// Return true if the dirty flag changed.
|
||||
@ -526,7 +531,7 @@ private:
|
||||
// Is the "- default -" preset suppressed?
|
||||
bool m_default_suppressed = true;
|
||||
size_t m_num_default_presets = 0;
|
||||
// Compatible & incompatible marks, to be placed at the wxBitmapComboBox items of a Platter.
|
||||
// Compatible & incompatible marks, to be placed at the wxBitmapComboBox items of a Plater.
|
||||
// These bitmaps are not owned by PresetCollection, but by a PresetBundle.
|
||||
const wxBitmap *m_bitmap_compatible = nullptr;
|
||||
const wxBitmap *m_bitmap_incompatible = nullptr;
|
||||
@ -559,6 +564,11 @@ public:
|
||||
const Preset* find_by_model_id(const std::string &model_id) const;
|
||||
};
|
||||
|
||||
namespace PresetUtils {
|
||||
// PrinterModel of a system profile, from which this preset is derived, or null if it is not derived from a system profile.
|
||||
const VendorProfile::PrinterModel* system_printer_model(const Preset &preset);
|
||||
} // namespace PresetUtils
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_Preset_hpp_ */
|
||||
|
@ -877,7 +877,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
// 4) Load the project config values (the per extruder wipe matrix etc).
|
||||
this->project_config.apply_only(config, s_project_options);
|
||||
|
||||
update_custom_gcode_per_print_z_from_config(GUI::wxGetApp().plater()->model().custom_gcode_per_print_z, &this->project_config);
|
||||
update_custom_gcode_per_print_z_from_config(GUI::wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes, &this->project_config);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1572,7 +1572,7 @@ void PresetBundle::load_default_preset_bitmaps(wxWindow *window)
|
||||
this->load_compatible_bitmaps(window);
|
||||
}
|
||||
|
||||
void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui)
|
||||
void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui)
|
||||
{
|
||||
if (ui == nullptr || this->printers.get_edited_preset().printer_technology() == ptSLA ||
|
||||
this->filament_presets.size() <= idx_extruder )
|
||||
|
@ -109,8 +109,8 @@ public:
|
||||
// Export a config bundle file containing all the presets and the names of the active presets.
|
||||
void export_configbundle(const std::string &path, bool export_system_settings = false);
|
||||
|
||||
// Update a filament selection combo box on the platter for an idx_extruder.
|
||||
void update_platter_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui);
|
||||
// Update a filament selection combo box on the plater for an idx_extruder.
|
||||
void update_plater_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui);
|
||||
|
||||
// Enable / disable the "- default -" preset.
|
||||
void set_default_suppressed(bool default_suppressed);
|
||||
|
@ -2004,7 +2004,11 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
|
||||
const float max_y = box.max(1) + Margin;
|
||||
|
||||
// view dependend order of rendering to keep correct transparency
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
bool camera_on_top = wxGetApp().plater()->get_camera().is_looking_downward();
|
||||
#else
|
||||
bool camera_on_top = wxGetApp().plater()->get_camera().get_theta() <= 90.0f;
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
float z1 = camera_on_top ? min_z : max_z;
|
||||
float z2 = camera_on_top ? max_z : min_z;
|
||||
|
||||
|
@ -905,7 +905,7 @@ void Tab::update_wiping_button_visibility() {
|
||||
}
|
||||
|
||||
|
||||
// Call a callback to update the selection of presets on the platter:
|
||||
// Call a callback to update the selection of presets on the plater:
|
||||
// To update the content of the selection boxes,
|
||||
// to update the filament colors of the selection boxes,
|
||||
// to update the "dirty" flags of the selection boxes,
|
||||
@ -2825,7 +2825,7 @@ void Tab::select_preset(std::string preset_name, bool delete_current)
|
||||
if (canceled) {
|
||||
update_tab_ui();
|
||||
// Trigger the on_presets_changed event so that we also restore the previous value in the plater selector,
|
||||
// if this action was initiated from the platter.
|
||||
// if this action was initiated from the plater.
|
||||
on_presets_changed();
|
||||
} else {
|
||||
if (current_dirty)
|
||||
@ -3053,7 +3053,7 @@ void Tab::save_preset(std::string name /*= ""*/)
|
||||
m_preset_bundle->update_compatible(false);
|
||||
// Add the new item into the UI component, remove dirty flags and activate the saved item.
|
||||
update_tab_ui();
|
||||
// Update the selection boxes at the platter.
|
||||
// Update the selection boxes at the plater.
|
||||
on_presets_changed();
|
||||
// If current profile is saved, "delete preset" button have to be enabled
|
||||
m_btn_delete_preset->Enable(true);
|
||||
@ -3444,27 +3444,25 @@ void TabSLAMaterial::build()
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
|
||||
if (opt_key == "bottle_volume") {
|
||||
double new_bottle_weight = boost::any_cast<double>(value)/(new_conf.option("material_density")->getFloat() * 1000);
|
||||
double new_bottle_weight = boost::any_cast<double>(value)*(new_conf.option("material_density")->getFloat() / 1000);
|
||||
new_conf.set_key_value("bottle_weight", new ConfigOptionFloat(new_bottle_weight));
|
||||
}
|
||||
if (opt_key == "bottle_weight") {
|
||||
double new_bottle_volume = boost::any_cast<double>(value)*(new_conf.option("material_density")->getFloat() * 1000);
|
||||
double new_bottle_volume = boost::any_cast<double>(value)/new_conf.option("material_density")->getFloat() * 1000;
|
||||
new_conf.set_key_value("bottle_volume", new ConfigOptionFloat(new_bottle_volume));
|
||||
}
|
||||
if (opt_key == "material_density") {
|
||||
double new_bottle_volume = new_conf.option("bottle_weight")->getFloat() * boost::any_cast<double>(value) * 1000;
|
||||
double new_bottle_volume = new_conf.option("bottle_weight")->getFloat() / boost::any_cast<double>(value) * 1000;
|
||||
new_conf.set_key_value("bottle_volume", new ConfigOptionFloat(new_bottle_volume));
|
||||
}
|
||||
|
||||
load_config(new_conf);
|
||||
|
||||
update_dirty();
|
||||
on_value_change(opt_key, value);
|
||||
|
||||
if (opt_key == "bottle_volume" || opt_key == "bottle_cost") {
|
||||
wxGetApp().sidebar().update_sliced_info_sizer();
|
||||
wxGetApp().sidebar().Layout();
|
||||
}
|
||||
// Change of any from those options influences for an update of "Sliced Info"
|
||||
wxGetApp().sidebar().update_sliced_info_sizer();
|
||||
wxGetApp().sidebar().Layout();
|
||||
};
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Layers")));
|
||||
|
@ -231,7 +231,7 @@ public:
|
||||
// Counter for the updating (because of an update() function can have a recursive behavior):
|
||||
// 1. increase value from the very beginning of an update() function
|
||||
// 2. decrease value at the end of an update() function
|
||||
// 3. propagate changed configuration to the Platter when (m_update_cnt == 0) only
|
||||
// 3. propagate changed configuration to the Plater when (m_update_cnt == 0) only
|
||||
int m_update_cnt = 0;
|
||||
|
||||
public:
|
||||
|
@ -782,6 +782,8 @@ public:
|
||||
const wxString& name = wxEmptyString);
|
||||
~DoubleSlider() {}
|
||||
|
||||
using t_mode = Slic3r::Model::CustomGCodeInfo::MODE;
|
||||
|
||||
/* For exporting GCode in GCodeWriter is used XYZF_NUM(val) = PRECISION(val, 3) for XYZ values.
|
||||
* So, let use same value as a permissible error for layer height.
|
||||
*/
|
||||
@ -805,33 +807,24 @@ public:
|
||||
// Set low and high slider position. If the span is non-empty, disable the "one layer" mode.
|
||||
void SetSelectionSpan(const int lower_val, const int higher_val);
|
||||
void SetMaxValue(const int max_value);
|
||||
void SetKoefForLabels(const double koef) {
|
||||
m_label_koef = koef;
|
||||
}
|
||||
void SetSliderValues(const std::vector<double>& values) {
|
||||
m_values = values;
|
||||
}
|
||||
void SetKoefForLabels(const double koef) { m_label_koef = koef; }
|
||||
void SetSliderValues(const std::vector<double>& values) { m_values = values; }
|
||||
void ChangeOneLayerLock();
|
||||
std::vector<Slic3r::Model::CustomGCode> GetTicksValues() const;
|
||||
void SetTicksValues(const std::vector<Slic3r::Model::CustomGCode> &heights);
|
||||
void EnableTickManipulation(bool enable = true) {
|
||||
m_is_enabled_tick_manipulation = enable;
|
||||
}
|
||||
void DisableTickManipulation() {
|
||||
EnableTickManipulation(false);
|
||||
}
|
||||
Slic3r::Model::CustomGCodeInfo GetTicksValues() const;
|
||||
void SetTicksValues(const Slic3r::Model::CustomGCodeInfo &custom_gcode_per_print_z);
|
||||
void EnableTickManipulation(bool enable = true) { m_is_enabled_tick_manipulation = enable; }
|
||||
void DisableTickManipulation() { EnableTickManipulation(false); }
|
||||
|
||||
enum ManipulationState {
|
||||
msSingleExtruder, // single extruder printer preset is selected
|
||||
msMultiExtruder // multiple extruder printer preset is selected, and "Whole print" is selected
|
||||
};
|
||||
void SetManipulationState(ManipulationState state) {
|
||||
m_state = state;
|
||||
void SetManipulationMode(t_mode mode) { m_mode = mode; }
|
||||
t_mode GetManipulationMode() const { return m_mode; }
|
||||
|
||||
void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder)
|
||||
{
|
||||
m_mode = !is_one_extruder_printed_model ? t_mode::MultiExtruder :
|
||||
only_extruder < 0 ? t_mode::SingleExtruder :
|
||||
t_mode::MultiAsSingle;
|
||||
m_only_extruder = only_extruder;
|
||||
}
|
||||
void SetManipulationState(int extruders_cnt) {
|
||||
m_state = extruders_cnt ==1 ? msSingleExtruder : msMultiExtruder;
|
||||
}
|
||||
ManipulationState GetManipulationState() const { return m_state; }
|
||||
|
||||
bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; }
|
||||
bool is_one_layer() const { return m_is_one_layer; }
|
||||
@ -850,13 +843,27 @@ public:
|
||||
void OnKeyUp(wxKeyEvent &event);
|
||||
void OnChar(wxKeyEvent &event);
|
||||
void OnRightDown(wxMouseEvent& event);
|
||||
int get_extruder_for_tick(int tick);
|
||||
void OnRightUp(wxMouseEvent& event);
|
||||
void add_code(std::string code, int selected_extruder = -1);
|
||||
|
||||
void add_code_as_tick(std::string code, int selected_extruder = -1);
|
||||
// add default action for tick, when press "+"
|
||||
void add_current_tick(bool call_from_keyboard = false);
|
||||
// delete current tick, when press "-"
|
||||
void delete_current_tick();
|
||||
void edit_tick();
|
||||
void change_extruder(int extruder);
|
||||
void edit_extruder_sequence();
|
||||
|
||||
struct TICK_CODE
|
||||
{
|
||||
bool operator<(const TICK_CODE& other) const { return other.tick > this->tick; }
|
||||
bool operator>(const TICK_CODE& other) const { return other.tick < this->tick; }
|
||||
|
||||
int tick = 0;
|
||||
std::string gcode = Slic3r::ColorChangeCode;
|
||||
int extruder = 0;
|
||||
std::string color;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
void render();
|
||||
@ -878,11 +885,11 @@ protected:
|
||||
void detect_selected_slider(const wxPoint& pt);
|
||||
void correct_lower_value();
|
||||
void correct_higher_value();
|
||||
wxString get_tooltip(IconFocus icon_focus);
|
||||
void move_current_thumb(const bool condition);
|
||||
void action_tick(const TicksAction action);
|
||||
void enter_window(wxMouseEvent& event, const bool enter);
|
||||
|
||||
private:
|
||||
|
||||
bool is_point_in_rect(const wxPoint& pt, const wxRect& rect);
|
||||
int is_point_near_tick(const wxPoint& pt);
|
||||
|
||||
@ -894,8 +901,18 @@ protected:
|
||||
wxSize get_size();
|
||||
void get_size(int *w, int *h);
|
||||
double get_double_value(const SelectedSlider& selection);
|
||||
wxString get_tooltip(IconFocus icon_focus);
|
||||
|
||||
std::string get_color_for_tool_change_tick(std::set<TICK_CODE>::const_iterator it) const;
|
||||
std::string get_color_for_color_change_tick(std::set<TICK_CODE>::const_iterator it) const;
|
||||
int get_extruder_for_tick(int tick);
|
||||
std::set<int> get_used_extruders_for_tick(int tick);
|
||||
|
||||
void post_ticks_changed_event(const std::string& gcode = "");
|
||||
bool check_ticks_changed_event(const std::string& gcode);
|
||||
void append_change_extruder_menu_item(wxMenu*);
|
||||
void append_add_color_change_menu_item(wxMenu*);
|
||||
|
||||
private:
|
||||
bool is_osx { false };
|
||||
wxFont m_font;
|
||||
int m_min_value;
|
||||
@ -914,7 +931,7 @@ private:
|
||||
ScalableBitmap m_bmp_one_layer_unlock_off;
|
||||
ScalableBitmap m_bmp_revert;
|
||||
ScalableBitmap m_bmp_cog;
|
||||
SelectedSlider m_selection;
|
||||
SelectedSlider m_selection;
|
||||
bool m_is_left_down = false;
|
||||
bool m_is_right_down = false;
|
||||
bool m_is_one_layer = false;
|
||||
@ -924,11 +941,12 @@ private:
|
||||
bool m_is_enabled_tick_manipulation = true;
|
||||
bool m_show_context_menu = false;
|
||||
bool m_show_edit_menu = false;
|
||||
bool m_edit_extruder_sequence = false;
|
||||
bool m_suppress_add_code = false;
|
||||
ManipulationState m_state = msSingleExtruder;
|
||||
std::string m_custom_gcode = "";
|
||||
std::string m_pause_print_msg;
|
||||
bool m_force_edit_extruder_sequence = false;
|
||||
bool m_force_mode_apply = true;
|
||||
bool m_force_add_tick = false;
|
||||
bool m_force_delete_tick = false;
|
||||
t_mode m_mode = t_mode::SingleExtruder;
|
||||
int m_only_extruder = -1;
|
||||
|
||||
wxRect m_rect_lower_thumb;
|
||||
wxRect m_rect_higher_thumb;
|
||||
@ -957,50 +975,44 @@ private:
|
||||
|
||||
std::vector<wxPen*> m_line_pens;
|
||||
std::vector<wxPen*> m_segm_pens;
|
||||
std::set<int> m_ticks;
|
||||
std::vector<double> m_values;
|
||||
|
||||
struct TICK_CODE
|
||||
struct TICK_CODE_INFO
|
||||
{
|
||||
bool operator<(const TICK_CODE& other) const { return other.tick > this->tick; }
|
||||
bool operator>(const TICK_CODE& other) const { return other.tick < this->tick; }
|
||||
std::set<TICK_CODE> ticks;
|
||||
t_mode mode = t_mode::SingleExtruder;
|
||||
|
||||
int tick = 0;
|
||||
std::string gcode = Slic3r::ColorChangeCode;
|
||||
int extruder = 0;
|
||||
std::string color;
|
||||
};
|
||||
bool empty() const { return ticks.empty(); }
|
||||
void set_pause_print_msg(const std::string& message) { pause_print_msg = message; }
|
||||
|
||||
std::set<TICK_CODE> m_ticks_;
|
||||
bool add_tick (const int tick, std::string &code, int extruder, double print_z);
|
||||
bool edit_tick (std::set<TICK_CODE>::iterator it, double print_z);
|
||||
void switch_code(const std::string& code_from, const std::string& code_to);
|
||||
void erase_all_ticks_with_code (const std::string& gcode);
|
||||
bool has_tick_with_code (const std::string& gcode);
|
||||
|
||||
void suppress_plus (bool suppress) { m_suppress_plus = suppress;}
|
||||
void suppress_minus(bool suppress) { m_suppress_minus = suppress;}
|
||||
bool suppressed_plus () { return m_suppress_plus ; }
|
||||
bool suppressed_minus() { return m_suppress_minus; }
|
||||
|
||||
private:
|
||||
|
||||
std::string custom_gcode = "";
|
||||
std::string pause_print_msg = "";
|
||||
bool m_suppress_plus = false;
|
||||
bool m_suppress_minus = false;
|
||||
}
|
||||
m_ticks;
|
||||
|
||||
public:
|
||||
struct ExtrudersSequence
|
||||
{
|
||||
bool is_mm_intervals;
|
||||
double interval_by_mm;
|
||||
int interval_by_layers;
|
||||
std::vector<size_t> extruders;
|
||||
bool is_mm_intervals = true;
|
||||
double interval_by_mm = 3.0;
|
||||
int interval_by_layers = 10;
|
||||
std::vector<size_t> extruders = { 0 };
|
||||
|
||||
ExtrudersSequence() :
|
||||
is_mm_intervals(true),
|
||||
interval_by_mm(3.0),
|
||||
interval_by_layers(10),
|
||||
extruders({ 0 }) {}
|
||||
|
||||
ExtrudersSequence(const ExtrudersSequence& other) :
|
||||
is_mm_intervals(other.is_mm_intervals),
|
||||
interval_by_mm(other.interval_by_mm),
|
||||
interval_by_layers(other.interval_by_layers),
|
||||
extruders(other.extruders) {}
|
||||
|
||||
ExtrudersSequence& operator=(const ExtrudersSequence& other) {
|
||||
this->is_mm_intervals = other.is_mm_intervals;
|
||||
this->interval_by_mm = other.interval_by_mm;
|
||||
this->interval_by_layers= other.interval_by_layers;
|
||||
this->extruders = other.extruders;
|
||||
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const ExtrudersSequence& other) const
|
||||
{
|
||||
return (other.is_mm_intervals == this->is_mm_intervals ) &&
|
||||
|
@ -363,10 +363,17 @@ void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx)
|
||||
ModelObject *model_object = model.add_object();
|
||||
model_object->add_volume(*volumes[ivolume]);
|
||||
model_object->add_instance();
|
||||
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
if (!Slic3r::store_3mf(path_src.string().c_str(), &model, nullptr, false)) {
|
||||
boost::filesystem::remove(path_src);
|
||||
throw std::runtime_error(L("Export of a temporary 3mf file failed"));
|
||||
}
|
||||
#else
|
||||
if (! Slic3r::store_3mf(path_src.string().c_str(), &model, nullptr)) {
|
||||
boost::filesystem::remove(path_src);
|
||||
throw std::runtime_error(L("Export of a temporary 3mf file failed"));
|
||||
}
|
||||
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
|
||||
model.clear_objects();
|
||||
model.clear_materials();
|
||||
boost::filesystem::path path_dst = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
|
@ -79,7 +79,6 @@ bool FlashAir::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error
|
||||
|
||||
const auto upload_filename = upload_data.upload_path.filename();
|
||||
const auto upload_parent_path = upload_data.upload_path.parent_path();
|
||||
|
||||
wxString test_msg;
|
||||
if (! test(test_msg)) {
|
||||
error_fn(std::move(test_msg));
|
||||
@ -88,7 +87,14 @@ bool FlashAir::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error
|
||||
|
||||
bool res = false;
|
||||
|
||||
std::string strDest = upload_parent_path.string();
|
||||
if (strDest.front()!='/') // Needs a leading / else root uploads fail.
|
||||
{
|
||||
strDest.insert(0,"/");
|
||||
}
|
||||
|
||||
auto urlPrepare = make_url("upload.cgi", "WRITEPROTECT=ON&FTIME", timestamp_str());
|
||||
auto urlSetDir = make_url("upload.cgi","UPDIR",strDest);
|
||||
auto urlUpload = make_url("upload.cgi");
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Uploading file %2% at %3% / %4%, filename: %5%")
|
||||
@ -101,7 +107,7 @@ bool FlashAir::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error
|
||||
// set filetime for upload and make card writeprotect to prevent filesystem damage
|
||||
auto httpPrepare = Http::get(std::move(urlPrepare));
|
||||
httpPrepare.on_error([&](std::string body, std::string error, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error prepareing upload: %2%, HTTP %3%, body: `%4%`") % name % error % status % body;
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error preparing upload: %2%, HTTP %3%, body: `%4%`") % name % error % status % body;
|
||||
error_fn(format_error(body, error, status));
|
||||
res = false;
|
||||
})
|
||||
@ -120,6 +126,26 @@ bool FlashAir::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error
|
||||
}
|
||||
|
||||
// start file upload
|
||||
auto httpDir = Http::get(std::move(urlSetDir));
|
||||
httpDir.on_error([&](std::string body, std::string error, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error setting upload dir: %2%, HTTP %3%, body: `%4%`") % name % error % status % body;
|
||||
error_fn(format_error(body, error, status));
|
||||
res = false;
|
||||
})
|
||||
.on_complete([&, this](std::string body, unsigned) {
|
||||
BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got dir select result: %2%") % name % body;
|
||||
res = boost::icontains(body, "SUCCESS");
|
||||
if (! res) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Request completed but no SUCCESS message was received.") % name;
|
||||
error_fn(format_error(body, L("Unknown error occured"), 0));
|
||||
}
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
if(! res ) {
|
||||
return res;
|
||||
}
|
||||
|
||||
auto http = Http::post(std::move(urlUpload));
|
||||
http.form_add_file("file", upload_data.source_path.string(), upload_filename.string())
|
||||
.on_complete([&](std::string body, unsigned status) {
|
||||
|