mirror of
https://github.com/FULU-Foundation/OrcaSlicer-bambulab.git
synced 2026-10-12 18:31:59 +02:00
Merge branch 'master' into lm_tm_hollowing
This commit is contained in:
commit
63b0eec5a9
104 files changed
+3378
-2140
No files matched your search
@@ -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)
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -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.
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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_);
|
||||
|
||||
+11
-11
@@ -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
|
||||
|
||||
|
||||
+622
-534
File diff suppressed because it is too large.
Load diff
+37
-30
@@ -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;
|
||||
|
||||
+16
-18
@@ -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)
|
||||
|
||||
+30
-11
@@ -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.
|
||||
|
||||
+48
-67
@@ -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).
|
||||
|
||||
+44
-16
@@ -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>
|
||||
|
||||
+74
-81
@@ -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
|
||||
|
||||
+14
-13
@@ -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); }
|
||||
|
||||
+164
-3
@@ -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);
|
||||
|
||||
+64
-180
@@ -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();
|
||||
|
||||
+36
-77
@@ -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;
|
||||
|
||||
|
||||
+9
-11
@@ -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:
|
||||
|
||||
+560
-324
File diff suppressed because it is too large.
Load diff
@@ -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) {
|
||||
|
||||
Loaded 100 of 104 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user