Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_custom_bed
This commit is contained in:
commit
ba7df2a64e
106 changed files with 4200 additions and 1928 deletions
|
@ -169,8 +169,19 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STRE
|
|||
# On GCC and Clang, no return from a non-void function is a warning only. Here, we make it an error.
|
||||
add_compile_options(-Werror=return-type)
|
||||
|
||||
#removes LOTS of extraneous Eigen warnings
|
||||
#removes LOTS of extraneous Eigen warnings (GCC only supports it since 6.1)
|
||||
#if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6.1)
|
||||
# add_compile_options(-Wno-ignored-attributes) # Tamas: Eigen include dirs are marked as SYSTEM
|
||||
#endif()
|
||||
|
||||
#GCC generates loads of -Wunknown-pragmas when compiling igl. The fix is not easy due to a bug in gcc, see
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66943 or
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431
|
||||
# We will turn the warning of for GCC for now:
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
add_compile_options(-Wno-unknown-pragmas)
|
||||
endif()
|
||||
|
||||
|
||||
if (SLIC3R_ASAN)
|
||||
add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
|
||||
|
@ -344,6 +355,10 @@ if (NOT GLEW_FOUND)
|
|||
endif ()
|
||||
include_directories(${GLEW_INCLUDE_DIRS})
|
||||
|
||||
# Find the Cereal serialization library
|
||||
add_library(cereal INTERFACE)
|
||||
target_include_directories(cereal INTERFACE include)
|
||||
|
||||
# l10n
|
||||
set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization")
|
||||
add_custom_target(pot
|
||||
|
|
2
deps/CMakeLists.txt
vendored
2
deps/CMakeLists.txt
vendored
|
@ -89,6 +89,7 @@ if (MSVC)
|
|||
dep_libcurl
|
||||
dep_wxwidgets
|
||||
dep_gtest
|
||||
dep_cereal
|
||||
dep_nlopt
|
||||
# dep_qhull # Experimental
|
||||
dep_zlib # on Windows we still need zlib
|
||||
|
@ -103,6 +104,7 @@ else()
|
|||
dep_libcurl
|
||||
dep_wxwidgets
|
||||
dep_gtest
|
||||
dep_cereal
|
||||
dep_nlopt
|
||||
dep_qhull
|
||||
# dep_libigl # Not working, static build has different Eigen
|
||||
|
|
10
deps/deps-unix-common.cmake
vendored
10
deps/deps-unix-common.cmake
vendored
|
@ -19,6 +19,16 @@ ExternalProject_Add(dep_gtest
|
|||
CMAKE_ARGS -DBUILD_GMOCK=OFF ${DEP_CMAKE_OPTS} -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local
|
||||
)
|
||||
|
||||
ExternalProject_Add(dep_cereal
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://github.com/USCiLab/cereal/archive/v1.2.2.tar.gz"
|
||||
# URL_HASH SHA256=c6dd7a5701fff8ad5ebb45a3dc8e757e61d52658de3918e38bab233e7fd3b4ae
|
||||
CMAKE_ARGS
|
||||
-DJUST_INSTALL_CEREAL=on
|
||||
-DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local
|
||||
${DEP_CMAKE_OPTS}
|
||||
)
|
||||
|
||||
ExternalProject_Add(dep_nlopt
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://github.com/stevengj/nlopt/archive/v2.5.0.tar.gz"
|
||||
|
|
14
deps/deps-windows.cmake
vendored
14
deps/deps-windows.cmake
vendored
|
@ -115,6 +115,20 @@ if (${DEP_DEBUG})
|
|||
endif ()
|
||||
|
||||
|
||||
ExternalProject_Add(dep_cereal
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://github.com/USCiLab/cereal/archive/v1.2.2.tar.gz"
|
||||
# URL_HASH SHA256=c6dd7a5701fff8ad5ebb45a3dc8e757e61d52658de3918e38bab233e7fd3b4ae
|
||||
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
|
||||
CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
|
||||
CMAKE_ARGS
|
||||
-DJUST_INSTALL_CEREAL=on
|
||||
"-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local"
|
||||
BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
|
||||
|
||||
ExternalProject_Add(dep_nlopt
|
||||
EXCLUDE_FROM_ALL 1
|
||||
URL "https://github.com/stevengj/nlopt/archive/v2.5.0.tar.gz"
|
||||
|
|
|
@ -20,6 +20,9 @@ You can also customize the bundle output path using the `-DDESTDIR=<some path>`
|
|||
**Warning**: Once the dependency bundle is installed in a destdir, the destdir cannot be moved elsewhere.
|
||||
(This is because wxWidgets hardcodes the installation path.)
|
||||
|
||||
FIXME The Cereal serialization library needs a tiny patch on some old OSX clang installations
|
||||
https://github.com/USCiLab/cereal/issues/339#issuecomment-246166717
|
||||
|
||||
|
||||
### Building PrusaSlicer
|
||||
|
||||
|
|
12
resources/icons/redo.svg
Normal file
12
resources/icons/redo.svg
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.4, 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="redo">
|
||||
<path fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" d="M13.39,11
|
||||
c-0.91,1.78-2.76,3-4.89,3C5.46,14,3,11.54,3,8.5C3,5.46,5.46,3,8.5,3C8.67,3,8.84,3.01,9,3.03"/>
|
||||
|
||||
<polygon fill="#ED6B21" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
|
||||
9,1 9,5 12,3 "/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 734 B |
12
resources/icons/redo_toolbar.svg
Normal file
12
resources/icons/redo_toolbar.svg
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.4, 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="redo">
|
||||
<path fill="none" stroke="#ED6B21" stroke-width="1" stroke-linecap="round" stroke-miterlimit="10" d="M13.39,11
|
||||
c-0.91,1.78-2.76,3-4.89,3C5.46,14,3,11.54,3,8.5C3,5.46,5.46,3,8.5,3C8.67,3,8.84,3.01,9,3.03"/>
|
||||
|
||||
<polygon fill="#ED6B21" stroke="#ED6B21" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
|
||||
9,1 9,5 12,3 "/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 734 B |
12
resources/icons/undo_toolbar.svg
Normal file
12
resources/icons/undo_toolbar.svg
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.3, 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="undo">
|
||||
<path fill="none" stroke="#ED6B21" stroke-width="1" stroke-linecap="round" stroke-miterlimit="10" d="M3,11
|
||||
c0.91,1.78,2.76,3,4.89,3c3.04,0,5.5-2.46,5.5-5.5c0-3.04-2.46-5.5-5.5-5.5c-0.17,0-0.34,0.01-0.5,0.03"/>
|
||||
|
||||
<polygon fill="#ED6B21" stroke="#ED6B21" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
|
||||
7.39,1 7.39,5 4.39,3 "/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 746 B |
|
@ -75,7 +75,7 @@ if (NOT MSVC)
|
|||
set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(PrusaSlicer libslic3r)
|
||||
target_link_libraries(PrusaSlicer libslic3r cereal)
|
||||
if (APPLE)
|
||||
# add_compile_options(-stdlib=libc++)
|
||||
# add_definitions(-DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_NO_CXX11_RVALUE_REFERENCES -DBOOST_THREAD_USES_MOVE)
|
||||
|
|
|
@ -132,7 +132,7 @@ struct HashTableEdges {
|
|||
~HashTableEdges() {
|
||||
#ifndef NDEBUG
|
||||
for (int i = 0; i < this->M; ++ i)
|
||||
for (HashEdge *temp = this->heads[i]; this->heads[i] != this->tail; temp = this->heads[i])
|
||||
for (HashEdge *temp = this->heads[i]; temp != this->tail; temp = temp->next)
|
||||
++ this->freed;
|
||||
this->tail = nullptr;
|
||||
#endif /* NDEBUG */
|
||||
|
|
|
@ -161,4 +161,12 @@ inline bool empty(const BoundingBox3Base<VT> &bb)
|
|||
|
||||
} // namespace Slic3r
|
||||
|
||||
// Serialization through the Cereal library
|
||||
namespace cereal {
|
||||
template<class Archive> void serialize(Archive& archive, Slic3r::BoundingBox &bb) { archive(bb.min, bb.max, bb.defined); }
|
||||
template<class Archive> void serialize(Archive& archive, Slic3r::BoundingBox3 &bb) { archive(bb.min, bb.max, bb.defined); }
|
||||
template<class Archive> void serialize(Archive& archive, Slic3r::BoundingBoxf &bb) { archive(bb.min, bb.max, bb.defined); }
|
||||
template<class Archive> void serialize(Archive& archive, Slic3r::BoundingBoxf3 &bb) { archive(bb.min, bb.max, bb.defined); }
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -81,9 +81,8 @@ add_library(libslic3r STATIC
|
|||
GCode/SpiralVase.hpp
|
||||
GCode/ToolOrdering.cpp
|
||||
GCode/ToolOrdering.hpp
|
||||
GCode/WipeTower.cpp
|
||||
GCode/WipeTower.hpp
|
||||
GCode/WipeTowerPrusaMM.cpp
|
||||
GCode/WipeTowerPrusaMM.hpp
|
||||
GCode.cpp
|
||||
GCode.hpp
|
||||
GCodeReader.cpp
|
||||
|
@ -114,6 +113,8 @@ add_library(libslic3r STATIC
|
|||
MultiPoint.cpp
|
||||
MultiPoint.hpp
|
||||
MutablePriorityQueue.hpp
|
||||
ObjectID.cpp
|
||||
ObjectID.hpp
|
||||
PerimeterGenerator.cpp
|
||||
PerimeterGenerator.hpp
|
||||
PlaceholderParser.cpp
|
||||
|
@ -189,6 +190,7 @@ target_include_directories(libslic3r PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${LIBNE
|
|||
target_link_libraries(libslic3r
|
||||
libnest2d
|
||||
admesh
|
||||
cereal
|
||||
libigl
|
||||
miniz
|
||||
boost_libs
|
||||
|
|
|
@ -209,6 +209,51 @@ std::vector<std::string> ConfigOptionDef::cli_args(const std::string &key) const
|
|||
return args;
|
||||
}
|
||||
|
||||
ConfigOption* ConfigOptionDef::create_empty_option() const
|
||||
{
|
||||
switch (this->type) {
|
||||
case coFloat: return new ConfigOptionFloat();
|
||||
case coFloats: return new ConfigOptionFloats();
|
||||
case coInt: return new ConfigOptionInt();
|
||||
case coInts: return new ConfigOptionInts();
|
||||
case coString: return new ConfigOptionString();
|
||||
case coStrings: return new ConfigOptionStrings();
|
||||
case coPercent: return new ConfigOptionPercent();
|
||||
case coPercents: return new ConfigOptionPercents();
|
||||
case coFloatOrPercent: return new ConfigOptionFloatOrPercent();
|
||||
case coPoint: return new ConfigOptionPoint();
|
||||
case coPoints: return new ConfigOptionPoints();
|
||||
case coPoint3: return new ConfigOptionPoint3();
|
||||
// case coPoint3s: return new ConfigOptionPoint3s();
|
||||
case coBool: return new ConfigOptionBool();
|
||||
case coBools: return new ConfigOptionBools();
|
||||
case coEnum: return new ConfigOptionEnumGeneric(this->enum_keys_map);
|
||||
default: throw std::runtime_error(std::string("Unknown option type for option ") + this->label);
|
||||
}
|
||||
}
|
||||
|
||||
ConfigOption* ConfigOptionDef::create_default_option() const
|
||||
{
|
||||
if (this->default_value)
|
||||
return (this->default_value->type() == coEnum) ?
|
||||
// Special case: For a DynamicConfig, convert a templated enum to a generic enum.
|
||||
new ConfigOptionEnumGeneric(this->enum_keys_map, this->default_value->getInt()) :
|
||||
this->default_value->clone();
|
||||
return this->create_empty_option();
|
||||
}
|
||||
|
||||
// Assignment of the serialization IDs is not thread safe. The Defs shall be initialized from the main thread!
|
||||
ConfigOptionDef* ConfigDef::add(const t_config_option_key &opt_key, ConfigOptionType type)
|
||||
{
|
||||
static size_t serialization_key_ordinal_last = 0;
|
||||
ConfigOptionDef *opt = &this->options[opt_key];
|
||||
opt->opt_key = opt_key;
|
||||
opt->type = type;
|
||||
opt->serialization_key_ordinal = ++ serialization_key_ordinal_last;
|
||||
this->by_serialization_key_ordinal[opt->serialization_key_ordinal] = opt;
|
||||
return opt;
|
||||
}
|
||||
|
||||
std::string ConfigOptionDef::nocli = "~~~noCLI";
|
||||
|
||||
std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, std::function<bool(const ConfigOptionDef &)> filter) const
|
||||
|
@ -358,7 +403,7 @@ t_config_option_keys ConfigBase::equal(const ConfigBase &other) const
|
|||
return equal;
|
||||
}
|
||||
|
||||
std::string ConfigBase::serialize(const t_config_option_key &opt_key) const
|
||||
std::string ConfigBase::opt_serialize(const t_config_option_key &opt_key) const
|
||||
{
|
||||
const ConfigOption* opt = this->option(opt_key);
|
||||
assert(opt != nullptr);
|
||||
|
@ -469,7 +514,7 @@ void ConfigBase::setenv_() const
|
|||
for (size_t i = 0; i < envname.size(); ++i)
|
||||
envname[i] = (envname[i] <= 'z' && envname[i] >= 'a') ? envname[i]-('a'-'A') : envname[i];
|
||||
|
||||
boost::nowide::setenv(envname.c_str(), this->serialize(*it).c_str(), 1);
|
||||
boost::nowide::setenv(envname.c_str(), this->opt_serialize(*it).c_str(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -593,16 +638,16 @@ void ConfigBase::save(const std::string &file) const
|
|||
c.open(file, std::ios::out | std::ios::trunc);
|
||||
c << "# " << Slic3r::header_slic3r_generated() << std::endl;
|
||||
for (const std::string &opt_key : this->keys())
|
||||
c << opt_key << " = " << this->serialize(opt_key) << std::endl;
|
||||
c << opt_key << " = " << this->opt_serialize(opt_key) << std::endl;
|
||||
c.close();
|
||||
}
|
||||
|
||||
bool DynamicConfig::operator==(const DynamicConfig &rhs) const
|
||||
{
|
||||
t_options_map::const_iterator it1 = this->options.begin();
|
||||
t_options_map::const_iterator it1_end = this->options.end();
|
||||
t_options_map::const_iterator it2 = rhs.options.begin();
|
||||
t_options_map::const_iterator it2_end = rhs.options.end();
|
||||
auto it1 = this->options.begin();
|
||||
auto it1_end = this->options.end();
|
||||
auto it2 = rhs.options.begin();
|
||||
auto it2_end = rhs.options.end();
|
||||
for (; it1 != it1_end && it2 != it2_end; ++ it1, ++ it2)
|
||||
if (it1->first != it2->first || *it1->second != *it2->second)
|
||||
// key or value differ
|
||||
|
@ -612,10 +657,10 @@ bool DynamicConfig::operator==(const DynamicConfig &rhs) const
|
|||
|
||||
ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool create)
|
||||
{
|
||||
t_options_map::iterator it = options.find(opt_key);
|
||||
auto it = options.find(opt_key);
|
||||
if (it != options.end())
|
||||
// Option was found.
|
||||
return it->second;
|
||||
return it->second.get();
|
||||
if (! create)
|
||||
// Option was not found and a new option shall not be created.
|
||||
return nullptr;
|
||||
|
@ -628,34 +673,8 @@ ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool cre
|
|||
// throw std::runtime_error(std::string("Invalid option name: ") + opt_key);
|
||||
// Let the parent decide what to do if the opt_key is not defined by this->def().
|
||||
return nullptr;
|
||||
ConfigOption *opt = nullptr;
|
||||
if (optdef->default_value) {
|
||||
opt = (optdef->default_value->type() == coEnum) ?
|
||||
// Special case: For a DynamicConfig, convert a templated enum to a generic enum.
|
||||
new ConfigOptionEnumGeneric(optdef->enum_keys_map, optdef->default_value->getInt()) :
|
||||
optdef->default_value->clone();
|
||||
} else {
|
||||
switch (optdef->type) {
|
||||
case coFloat: opt = new ConfigOptionFloat(); break;
|
||||
case coFloats: opt = new ConfigOptionFloats(); break;
|
||||
case coInt: opt = new ConfigOptionInt(); break;
|
||||
case coInts: opt = new ConfigOptionInts(); break;
|
||||
case coString: opt = new ConfigOptionString(); break;
|
||||
case coStrings: opt = new ConfigOptionStrings(); break;
|
||||
case coPercent: opt = new ConfigOptionPercent(); break;
|
||||
case coPercents: opt = new ConfigOptionPercents(); break;
|
||||
case coFloatOrPercent: opt = new ConfigOptionFloatOrPercent(); break;
|
||||
case coPoint: opt = new ConfigOptionPoint(); break;
|
||||
case coPoints: opt = new ConfigOptionPoints(); break;
|
||||
case coPoint3: opt = new ConfigOptionPoint3(); break;
|
||||
// case coPoint3s: opt = new ConfigOptionPoint3s(); break;
|
||||
case coBool: opt = new ConfigOptionBool(); break;
|
||||
case coBools: opt = new ConfigOptionBools(); break;
|
||||
case coEnum: opt = new ConfigOptionEnumGeneric(optdef->enum_keys_map); break;
|
||||
default: throw std::runtime_error(std::string("Unknown option type for option ") + opt_key);
|
||||
}
|
||||
}
|
||||
this->options[opt_key] = opt;
|
||||
ConfigOption *opt = optdef->create_default_option();
|
||||
this->options.emplace_hint(it, opt_key, std::unique_ptr<ConfigOption>(opt));
|
||||
return opt;
|
||||
}
|
||||
|
||||
|
@ -802,3 +821,64 @@ t_config_option_keys StaticConfig::keys() const
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
#include <cereal/types/polymorphic.hpp>
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOption)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionSingle<double>)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionSingle<int>)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionSingle<std::string>)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionSingle<Slic3r::Vec2d>)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionSingle<Slic3r::Vec3d>)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionSingle<bool>)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionVectorBase)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionVector<double>)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionVector<int>)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionVector<std::string>)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionVector<Slic3r::Vec2d>)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionVector<unsigned char>)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloat)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloats)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionInt)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionInts)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionString)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionStrings)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercent)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercents)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloatOrPercent)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoint)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoints)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoint3)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBool)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBools)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionEnumGeneric)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ConfigBase)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::DynamicConfig)
|
||||
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOption, Slic3r::ConfigOptionSingle<double>)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOption, Slic3r::ConfigOptionSingle<int>)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOption, Slic3r::ConfigOptionSingle<std::string>)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOption, Slic3r::ConfigOptionSingle<Slic3r::Vec2d>)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOption, Slic3r::ConfigOptionSingle<Slic3r::Vec3d>)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOption, Slic3r::ConfigOptionSingle<bool>)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOption, Slic3r::ConfigOptionVectorBase)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVectorBase, Slic3r::ConfigOptionVector<double>)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVectorBase, Slic3r::ConfigOptionVector<int>)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVectorBase, Slic3r::ConfigOptionVector<std::string>)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVectorBase, Slic3r::ConfigOptionVector<Slic3r::Vec2d>)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVectorBase, Slic3r::ConfigOptionVector<unsigned char>)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<double>, Slic3r::ConfigOptionFloat)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<double>, Slic3r::ConfigOptionFloats)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<int>, Slic3r::ConfigOptionInt)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<int>, Slic3r::ConfigOptionInts)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<std::string>, Slic3r::ConfigOptionString)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<std::string>, Slic3r::ConfigOptionStrings)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloat, Slic3r::ConfigOptionPercent)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloats, Slic3r::ConfigOptionPercents)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionPercent, Slic3r::ConfigOptionFloatOrPercent)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<Slic3r::Vec2d>, Slic3r::ConfigOptionPoint)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<Slic3r::Vec2d>, Slic3r::ConfigOptionPoints)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<Slic3r::Vec3d>, Slic3r::ConfigOptionPoint3)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<bool>, Slic3r::ConfigOptionBool)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<unsigned char>, Slic3r::ConfigOptionBools)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionInt, Slic3r::ConfigOptionEnumGeneric)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigBase, Slic3r::DynamicConfig)
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
#include <boost/format.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <cereal/access.hpp>
|
||||
#include <cereal/types/base_class.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Name of the configuration option.
|
||||
|
@ -152,6 +155,10 @@ public:
|
|||
|
||||
bool operator==(const T &rhs) const { return this->value == rhs; }
|
||||
bool operator!=(const T &rhs) const { return this->value != rhs; }
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive & ar) { ar(this->value); }
|
||||
};
|
||||
|
||||
// Value of a vector valued option (bools, ints, floats, strings, points)
|
||||
|
@ -294,6 +301,10 @@ public:
|
|||
|
||||
bool operator==(const std::vector<T> &rhs) const { return this->values == rhs; }
|
||||
bool operator!=(const std::vector<T> &rhs) const { return this->values != rhs; }
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive & ar) { ar(this->values); }
|
||||
};
|
||||
|
||||
class ConfigOptionFloat : public ConfigOptionSingle<double>
|
||||
|
@ -328,6 +339,10 @@ public:
|
|||
this->set(opt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<double>>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionFloats : public ConfigOptionVector<double>
|
||||
|
@ -386,6 +401,10 @@ public:
|
|||
this->set(opt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<double>>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionInt : public ConfigOptionSingle<int>
|
||||
|
@ -422,6 +441,10 @@ public:
|
|||
this->set(opt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<int>>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionInts : public ConfigOptionVector<int>
|
||||
|
@ -472,6 +495,10 @@ public:
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<int>>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionString : public ConfigOptionSingle<std::string>
|
||||
|
@ -496,6 +523,10 @@ public:
|
|||
UNUSED(append);
|
||||
return unescape_string_cstyle(str, this->value);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<std::string>>(this)); }
|
||||
};
|
||||
|
||||
// semicolon-separated strings
|
||||
|
@ -530,6 +561,10 @@ public:
|
|||
this->values.clear();
|
||||
return unescape_strings_cstyle(str, this->values);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<std::string>>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionPercent : public ConfigOptionFloat
|
||||
|
@ -562,6 +597,10 @@ public:
|
|||
iss >> this->value;
|
||||
return !iss.fail();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloat>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionPercents : public ConfigOptionFloats
|
||||
|
@ -616,6 +655,10 @@ public:
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloats>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionFloatOrPercent : public ConfigOptionPercent
|
||||
|
@ -665,6 +708,10 @@ public:
|
|||
iss >> this->value;
|
||||
return !iss.fail();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionPercent>(this), percent); }
|
||||
};
|
||||
|
||||
class ConfigOptionPoint : public ConfigOptionSingle<Vec2d>
|
||||
|
@ -695,6 +742,10 @@ public:
|
|||
return sscanf(str.data(), " %lf , %lf %c", &this->value(0), &this->value(1), &dummy) == 2 ||
|
||||
sscanf(str.data(), " %lf x %lf %c", &this->value(0), &this->value(1), &dummy) == 2;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<Vec2d>>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionPoints : public ConfigOptionVector<Vec2d>
|
||||
|
@ -754,8 +805,21 @@ public:
|
|||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void save(Archive& archive) const {
|
||||
size_t cnt = this->values.size();
|
||||
archive(cnt);
|
||||
archive.saveBinary((const char*)this->values.data(), sizeof(Vec2d) * cnt);
|
||||
}
|
||||
template<class Archive> void load(Archive& archive) {
|
||||
size_t cnt;
|
||||
archive(cnt);
|
||||
this->values.assign(cnt, Vec2d());
|
||||
archive.loadBinary((char*)this->values.data(), sizeof(Vec2d) * cnt);
|
||||
}
|
||||
};
|
||||
|
||||
class ConfigOptionPoint3 : public ConfigOptionSingle<Vec3d>
|
||||
{
|
||||
|
@ -787,6 +851,10 @@ public:
|
|||
return sscanf(str.data(), " %lf , %lf , %lf %c", &this->value(0), &this->value(1), &this->value(2), &dummy) == 2 ||
|
||||
sscanf(str.data(), " %lf x %lf x %lf %c", &this->value(0), &this->value(1), &this->value(2), &dummy) == 2;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<Vec3d>>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionBool : public ConfigOptionSingle<bool>
|
||||
|
@ -813,6 +881,10 @@ public:
|
|||
this->value = (str.compare("1") == 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<bool>>(this)); }
|
||||
};
|
||||
|
||||
class ConfigOptionBools : public ConfigOptionVector<unsigned char>
|
||||
|
@ -868,6 +940,10 @@ public:
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<unsigned char>>(this)); }
|
||||
};
|
||||
|
||||
// Map from an enum integer value to an enum name.
|
||||
|
@ -1006,19 +1082,73 @@ public:
|
|||
this->value = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive& ar) { ar(cereal::base_class<ConfigOptionInt>(this)); }
|
||||
};
|
||||
|
||||
// Definition of a configuration value for the purpose of GUI presentation, editing, value mapping and config file handling.
|
||||
class ConfigOptionDef
|
||||
{
|
||||
public:
|
||||
// Identifier of this option. It is stored here so that it is accessible through the by_serialization_key_ordinal map.
|
||||
t_config_option_key opt_key;
|
||||
// What type? bool, int, string etc.
|
||||
ConfigOptionType type = coNone;
|
||||
// Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor.
|
||||
Slic3r::clonable_ptr<const ConfigOption> default_value;
|
||||
void set_default_value(const ConfigOption* ptr) { this->default_value = Slic3r::clonable_ptr<const ConfigOption>(ptr); }
|
||||
template<typename T>
|
||||
const T* get_default_value() const { return static_cast<const T*>(this->default_value.get()); }
|
||||
template<typename T> const T* get_default_value() const { return static_cast<const T*>(this->default_value.get()); }
|
||||
|
||||
// Create an empty option to be used as a base for deserialization of DynamicConfig.
|
||||
ConfigOption* create_empty_option() const;
|
||||
// Create a default option to be inserted into a DynamicConfig.
|
||||
ConfigOption* create_default_option() const;
|
||||
|
||||
template<class Archive> ConfigOption* load_option_from_archive(Archive &archive) const {
|
||||
switch (this->type) {
|
||||
case coFloat: { auto opt = new ConfigOptionFloat(); archive(*opt); return opt; }
|
||||
case coFloats: { auto opt = new ConfigOptionFloats(); archive(*opt); return opt; }
|
||||
case coInt: { auto opt = new ConfigOptionInt(); archive(*opt); return opt; }
|
||||
case coInts: { auto opt = new ConfigOptionInts(); archive(*opt); return opt; }
|
||||
case coString: { auto opt = new ConfigOptionString(); archive(*opt); return opt; }
|
||||
case coStrings: { auto opt = new ConfigOptionStrings(); archive(*opt); return opt; }
|
||||
case coPercent: { auto opt = new ConfigOptionPercent(); archive(*opt); return opt; }
|
||||
case coPercents: { auto opt = new ConfigOptionPercents(); archive(*opt); return opt; }
|
||||
case coFloatOrPercent: { auto opt = new ConfigOptionFloatOrPercent(); archive(*opt); return opt; }
|
||||
case coPoint: { auto opt = new ConfigOptionPoint(); archive(*opt); return opt; }
|
||||
case coPoints: { auto opt = new ConfigOptionPoints(); archive(*opt); return opt; }
|
||||
case coPoint3: { auto opt = new ConfigOptionPoint3(); archive(*opt); return opt; }
|
||||
case coBool: { auto opt = new ConfigOptionBool(); archive(*opt); return opt; }
|
||||
case coBools: { auto opt = new ConfigOptionBools(); archive(*opt); return opt; }
|
||||
case coEnum: { auto opt = new ConfigOptionEnumGeneric(this->enum_keys_map); archive(*opt); return opt; }
|
||||
default: throw std::runtime_error(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Archive> ConfigOption* save_option_to_archive(Archive &archive, const ConfigOption *opt) const {
|
||||
switch (this->type) {
|
||||
case coFloat: archive(*static_cast<const ConfigOptionFloat*>(opt)); break;
|
||||
case coFloats: archive(*static_cast<const ConfigOptionFloats*>(opt)); break;
|
||||
case coInt: archive(*static_cast<const ConfigOptionInt*>(opt)); break;
|
||||
case coInts: archive(*static_cast<const ConfigOptionInts*>(opt)); break;
|
||||
case coString: archive(*static_cast<const ConfigOptionString*>(opt)); break;
|
||||
case coStrings: archive(*static_cast<const ConfigOptionStrings*>(opt)); break;
|
||||
case coPercent: archive(*static_cast<const ConfigOptionPercent*>(opt)); break;
|
||||
case coPercents: archive(*static_cast<const ConfigOptionPercents*>(opt)); break;
|
||||
case coFloatOrPercent: archive(*static_cast<const ConfigOptionFloatOrPercent*>(opt)); break;
|
||||
case coPoint: archive(*static_cast<const ConfigOptionPoint*>(opt)); break;
|
||||
case coPoints: archive(*static_cast<const ConfigOptionPoints*>(opt)); break;
|
||||
case coPoint3: archive(*static_cast<const ConfigOptionPoint3*>(opt)); break;
|
||||
case coBool: archive(*static_cast<const ConfigOptionBool*>(opt)); break;
|
||||
case coBools: archive(*static_cast<const ConfigOptionBools*>(opt)); break;
|
||||
case coEnum: archive(*static_cast<const ConfigOptionEnumGeneric*>(opt)); break;
|
||||
default: throw std::runtime_error(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key);
|
||||
}
|
||||
// Make the compiler happy, shut up the warnings.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Usually empty.
|
||||
// Special values - "i_enum_open", "f_enum_open" to provide combo box for int or float selection,
|
||||
|
@ -1088,6 +1218,9 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
// 0 is an invalid key.
|
||||
size_t serialization_key_ordinal = 0;
|
||||
|
||||
// Returns the alternative CLI arguments for the given option.
|
||||
// If there are no cli arguments defined, use the key and replace underscores with dashes.
|
||||
std::vector<std::string> cli_args(const std::string &key) const;
|
||||
|
@ -1108,6 +1241,7 @@ class ConfigDef
|
|||
{
|
||||
public:
|
||||
t_optiondef_map options;
|
||||
std::map<size_t, const ConfigOptionDef*> by_serialization_key_ordinal;
|
||||
|
||||
bool has(const t_config_option_key &opt_key) const { return this->options.count(opt_key) > 0; }
|
||||
const ConfigOptionDef* get(const t_config_option_key &opt_key) const {
|
||||
|
@ -1128,11 +1262,7 @@ public:
|
|||
std::function<bool(const ConfigOptionDef &)> filter = [](const ConfigOptionDef &){ return true; }) const;
|
||||
|
||||
protected:
|
||||
ConfigOptionDef* add(const t_config_option_key &opt_key, ConfigOptionType type) {
|
||||
ConfigOptionDef* opt = &this->options[opt_key];
|
||||
opt->type = type;
|
||||
return opt;
|
||||
}
|
||||
ConfigOptionDef* add(const t_config_option_key &opt_key, ConfigOptionType type);
|
||||
};
|
||||
|
||||
// An abstract configuration store.
|
||||
|
@ -1201,7 +1331,7 @@ public:
|
|||
bool equals(const ConfigBase &other) const { return this->diff(other).empty(); }
|
||||
t_config_option_keys diff(const ConfigBase &other) const;
|
||||
t_config_option_keys equal(const ConfigBase &other) const;
|
||||
std::string serialize(const t_config_option_key &opt_key) const;
|
||||
std::string opt_serialize(const t_config_option_key &opt_key) const;
|
||||
// Set a configuration value from a string, it will call an overridable handle_legacy()
|
||||
// to resolve renamed and removed configuration keys.
|
||||
bool set_deserialize(const t_config_option_key &opt_key, const std::string &str, bool append = false);
|
||||
|
@ -1239,7 +1369,7 @@ public:
|
|||
assert(this->def() == nullptr || this->def() == rhs.def());
|
||||
this->clear();
|
||||
for (const auto &kvp : rhs.options)
|
||||
this->options[kvp.first] = kvp.second->clone();
|
||||
this->options[kvp.first].reset(kvp.second->clone());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1262,15 +1392,13 @@ public:
|
|||
for (const auto &kvp : rhs.options) {
|
||||
auto it = this->options.find(kvp.first);
|
||||
if (it == this->options.end())
|
||||
this->options[kvp.first] = kvp.second->clone();
|
||||
this->options[kvp.first].reset(kvp.second->clone());
|
||||
else {
|
||||
assert(it->second->type() == kvp.second->type());
|
||||
if (it->second->type() == kvp.second->type())
|
||||
*it->second = *kvp.second;
|
||||
else {
|
||||
delete it->second;
|
||||
it->second = kvp.second->clone();
|
||||
}
|
||||
else
|
||||
it->second.reset(kvp.second->clone());
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
|
@ -1281,14 +1409,13 @@ public:
|
|||
DynamicConfig& operator+=(DynamicConfig &&rhs)
|
||||
{
|
||||
assert(this->def() == nullptr || this->def() == rhs.def());
|
||||
for (const auto &kvp : rhs.options) {
|
||||
for (auto &kvp : rhs.options) {
|
||||
auto it = this->options.find(kvp.first);
|
||||
if (it == this->options.end()) {
|
||||
this->options[kvp.first] = kvp.second;
|
||||
this->options.insert(std::make_pair(kvp.first, std::move(kvp.second)));
|
||||
} else {
|
||||
assert(it->second->type() == kvp.second->type());
|
||||
delete it->second;
|
||||
it->second = kvp.second;
|
||||
it->second = std::move(kvp.second);
|
||||
}
|
||||
}
|
||||
rhs.options.clear();
|
||||
|
@ -1305,8 +1432,6 @@ public:
|
|||
|
||||
void clear()
|
||||
{
|
||||
for (auto &opt : this->options)
|
||||
delete opt.second;
|
||||
this->options.clear();
|
||||
}
|
||||
|
||||
|
@ -1315,7 +1440,6 @@ public:
|
|||
auto it = this->options.find(opt_key);
|
||||
if (it == this->options.end())
|
||||
return false;
|
||||
delete it->second;
|
||||
this->options.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
@ -1340,11 +1464,10 @@ public:
|
|||
{
|
||||
auto it = this->options.find(opt_key);
|
||||
if (it == this->options.end()) {
|
||||
this->options[opt_key] = opt;
|
||||
this->options[opt_key].reset(opt);
|
||||
return true;
|
||||
} else {
|
||||
delete it->second;
|
||||
it->second = opt;
|
||||
it->second.reset(opt);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1374,12 +1497,15 @@ public:
|
|||
void read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra, t_config_option_keys* keys = nullptr);
|
||||
bool read_cli(int argc, char** argv, t_config_option_keys* extra, t_config_option_keys* keys = nullptr);
|
||||
|
||||
typedef std::map<t_config_option_key,ConfigOption*> t_options_map;
|
||||
t_options_map::const_iterator cbegin() const { return options.cbegin(); }
|
||||
t_options_map::const_iterator cend() const { return options.cend(); }
|
||||
std::map<t_config_option_key, std::unique_ptr<ConfigOption>>::const_iterator cbegin() const { return options.cbegin(); }
|
||||
std::map<t_config_option_key, std::unique_ptr<ConfigOption>>::const_iterator cend() const { return options.cend(); }
|
||||
size_t size() const { return options.size(); }
|
||||
|
||||
private:
|
||||
t_options_map options;
|
||||
std::map<t_config_option_key, std::unique_ptr<ConfigOption>> options;
|
||||
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(options); }
|
||||
};
|
||||
|
||||
/// Configuration store with a static definition of configuration values.
|
||||
|
|
|
@ -146,10 +146,10 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
|
|||
coord_t iy = p1(1) / m_resolution;
|
||||
coord_t ixb = p2(0) / m_resolution;
|
||||
coord_t iyb = p2(1) / m_resolution;
|
||||
assert(ix >= 0 && ix < m_cols);
|
||||
assert(iy >= 0 && iy < m_rows);
|
||||
assert(ixb >= 0 && ixb < m_cols);
|
||||
assert(iyb >= 0 && iyb < m_rows);
|
||||
assert(ix >= 0 && size_t(ix) < m_cols);
|
||||
assert(iy >= 0 && size_t(iy) < m_rows);
|
||||
assert(ixb >= 0 && size_t(ixb) < m_cols);
|
||||
assert(iyb >= 0 && size_t(iyb) < m_rows);
|
||||
// Account for the end points.
|
||||
++ m_cells[iy*m_cols+ix].end;
|
||||
if (ix == ixb && iy == iyb)
|
||||
|
@ -290,10 +290,10 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
|
|||
coord_t iy = p1(1) / m_resolution;
|
||||
coord_t ixb = p2(0) / m_resolution;
|
||||
coord_t iyb = p2(1) / m_resolution;
|
||||
assert(ix >= 0 && ix < m_cols);
|
||||
assert(iy >= 0 && iy < m_rows);
|
||||
assert(ixb >= 0 && ixb < m_cols);
|
||||
assert(iyb >= 0 && iyb < m_rows);
|
||||
assert(ix >= 0 && size_t(ix) < m_cols);
|
||||
assert(iy >= 0 && size_t(iy) < m_rows);
|
||||
assert(ixb >= 0 && size_t(ixb) < m_cols);
|
||||
assert(iyb >= 0 && size_t(iyb) < m_rows);
|
||||
// Account for the end points.
|
||||
m_cell_data[m_cells[iy*m_cols + ix].end++] = std::pair<size_t, size_t>(i, j);
|
||||
if (ix == ixb && iy == iyb)
|
||||
|
@ -775,11 +775,11 @@ void EdgeGrid::Grid::calculate_sdf()
|
|||
// For each corner of this cell and its 1 ring neighbours:
|
||||
for (int corner_y = -1; corner_y < 3; ++ corner_y) {
|
||||
coord_t corner_r = r + corner_y;
|
||||
if (corner_r < 0 || corner_r >= nrows)
|
||||
if (corner_r < 0 || (size_t)corner_r >= nrows)
|
||||
continue;
|
||||
for (int corner_x = -1; corner_x < 3; ++ corner_x) {
|
||||
coord_t corner_c = c + corner_x;
|
||||
if (corner_c < 0 || corner_c >= ncols)
|
||||
if (corner_c < 0 || (size_t)corner_c >= ncols)
|
||||
continue;
|
||||
float &d_min = m_signed_distance_field[corner_r * ncols + corner_c];
|
||||
Slic3r::Point pt(m_bbox.min(0) + corner_c * m_resolution, m_bbox.min(1) + corner_r * m_resolution);
|
||||
|
@ -1137,9 +1137,9 @@ bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radiu
|
|||
return false;
|
||||
bbox.max(0) /= m_resolution;
|
||||
bbox.max(1) /= m_resolution;
|
||||
if (bbox.max(0) >= m_cols)
|
||||
if ((size_t)bbox.max(0) >= m_cols)
|
||||
bbox.max(0) = m_cols - 1;
|
||||
if (bbox.max(1) >= m_rows)
|
||||
if ((size_t)bbox.max(1) >= m_rows)
|
||||
bbox.max(1) = m_rows - 1;
|
||||
// Lower boundary, round to grid and test validity.
|
||||
bbox.min(0) -= search_radius;
|
||||
|
|
|
@ -78,8 +78,8 @@ protected:
|
|||
#endif
|
||||
bool cell_inside_or_crossing(int r, int c) const
|
||||
{
|
||||
if (r < 0 || r >= m_rows ||
|
||||
c < 0 || c >= m_cols)
|
||||
if (r < 0 || (size_t)r >= m_rows ||
|
||||
c < 0 || (size_t)c >= m_cols)
|
||||
// The cell is outside the domain. Hoping that the contours were correctly oriented, so
|
||||
// there is a CCW outmost contour so the out of domain cells are outside.
|
||||
return false;
|
||||
|
|
|
@ -660,7 +660,7 @@ void gcode_spread_points(
|
|||
for (ExtrusionPoints::const_iterator it = points.begin(); it != points.end(); ++ it) {
|
||||
const V2f ¢er = it->center;
|
||||
const float radius = it->radius;
|
||||
const float radius2 = radius * radius;
|
||||
//const float radius2 = radius * radius;
|
||||
const float height_target = it->height;
|
||||
B2f bbox(center - V2f(radius, radius), center + V2f(radius, radius));
|
||||
B2i bboxi(
|
||||
|
@ -774,8 +774,8 @@ void gcode_spread_points(
|
|||
}
|
||||
}
|
||||
#endif
|
||||
float area_circle_total2 = float(M_PI) * sqr(radius);
|
||||
float area_err = fabs(area_circle_total2 - area_circle_total) / area_circle_total2;
|
||||
// float area_circle_total2 = float(M_PI) * sqr(radius);
|
||||
// float area_err = fabs(area_circle_total2 - area_circle_total) / area_circle_total2;
|
||||
// printf("area_circle_total: %f, %f, %f\n", area_circle_total, area_circle_total2, area_err);
|
||||
float volume_full = float(M_PI) * sqr(radius) * height_target;
|
||||
// if (true) {
|
||||
|
@ -905,8 +905,8 @@ void ExtrusionSimulator::set_image_size(const Point &image_size)
|
|||
// printf("Allocating image data, allocated\n");
|
||||
|
||||
//FIXME fill the image with red vertical lines.
|
||||
for (size_t r = 0; r < image_size.y(); ++ r) {
|
||||
for (size_t c = 0; c < image_size.x(); c += 2) {
|
||||
for (size_t r = 0; r < size_t(image_size.y()); ++ r) {
|
||||
for (size_t c = 0; c < size_t(image_size.x()); c += 2) {
|
||||
// Color red
|
||||
pimpl->image_data[r * image_size.x() * 4 + c * 4] = 255;
|
||||
// Opacity full
|
||||
|
@ -958,7 +958,7 @@ void ExtrusionSimulator::extrude_to_accumulator(const ExtrusionPath &path, const
|
|||
float scalex = float(viewport.size().x()) / float(bbox.size().x());
|
||||
float scaley = float(viewport.size().y()) / float(bbox.size().y());
|
||||
float w = scale_(path.width) * scalex;
|
||||
float h = scale_(path.height) * scalex;
|
||||
//float h = scale_(path.height) * scalex;
|
||||
w = scale_(path.mm3_per_mm / path.height) * scalex;
|
||||
// printf("scalex: %f, scaley: %f\n", scalex, scaley);
|
||||
// printf("bbox: %d,%d %d,%d\n", bbox.min.x(), bbox.min.y, bbox.max.x(), bbox.max.y);
|
||||
|
@ -993,8 +993,8 @@ void ExtrusionSimulator::evaluate_accumulator(ExtrusionSimulationType simulation
|
|||
for (int r = 0; r < sz.y(); ++r) {
|
||||
for (int c = 0; c < sz.x(); ++c) {
|
||||
float p = 0;
|
||||
for (int j = 0; j < pimpl->bitmap_oversampled; ++ j) {
|
||||
for (int i = 0; i < pimpl->bitmap_oversampled; ++ i) {
|
||||
for (unsigned int j = 0; j < pimpl->bitmap_oversampled; ++ j) {
|
||||
for (unsigned int i = 0; i < pimpl->bitmap_oversampled; ++ i) {
|
||||
if (pimpl->bitmap[r * pimpl->bitmap_oversampled + j][c * pimpl->bitmap_oversampled + i])
|
||||
p += 1.f;
|
||||
}
|
||||
|
|
|
@ -130,14 +130,14 @@ static inline Point hilbert_n_to_xy(const size_t n)
|
|||
}
|
||||
}
|
||||
int state = (ndigits & 1) ? 4 : 0;
|
||||
int dirstate = (ndigits & 1) ? 0 : 4;
|
||||
// int dirstate = (ndigits & 1) ? 0 : 4;
|
||||
coord_t x = 0;
|
||||
coord_t y = 0;
|
||||
for (int i = (int)ndigits - 1; i >= 0; -- i) {
|
||||
int digit = (n >> (i * 2)) & 3;
|
||||
state += digit;
|
||||
if (digit != 3)
|
||||
dirstate = state; // lowest non-3 digit
|
||||
// if (digit != 3)
|
||||
// dirstate = state; // lowest non-3 digit
|
||||
x |= digit_to_x[state] << i;
|
||||
y |= digit_to_y[state] << i;
|
||||
state = next_state[state];
|
||||
|
|
|
@ -287,7 +287,8 @@ public:
|
|||
assert(aoffset1 < 0);
|
||||
assert(aoffset2 < 0);
|
||||
assert(aoffset2 < aoffset1);
|
||||
bool sticks_removed = remove_sticks(polygons_src);
|
||||
// bool sticks_removed =
|
||||
remove_sticks(polygons_src);
|
||||
// if (sticks_removed) printf("Sticks removed!\n");
|
||||
polygons_outer = offset(polygons_src, aoffset1,
|
||||
ClipperLib::jtMiter,
|
||||
|
@ -481,7 +482,7 @@ static inline IntersectionTypeOtherVLine intersection_type_on_prev_next_vertical
|
|||
{
|
||||
// This routine will propose a connecting line even if the connecting perimeter segment intersects
|
||||
// iVertical line multiple times before reaching iIntersectionOther.
|
||||
if (iIntersectionOther == -1)
|
||||
if (iIntersectionOther == size_t(-1))
|
||||
return INTERSECTION_TYPE_OTHER_VLINE_UNDEFINED;
|
||||
assert(dir_is_next ? (iVerticalLine + 1 < segs.size()) : (iVerticalLine > 0));
|
||||
const SegmentedIntersectionLine &il_this = segs[iVerticalLine];
|
||||
|
@ -858,8 +859,8 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||
if (il > ir)
|
||||
// No vertical line intersects this segment.
|
||||
continue;
|
||||
assert(il >= 0 && il < segs.size());
|
||||
assert(ir >= 0 && ir < segs.size());
|
||||
assert(il >= 0 && size_t(il) < segs.size());
|
||||
assert(ir >= 0 && size_t(ir) < segs.size());
|
||||
for (int i = il; i <= ir; ++ i) {
|
||||
coord_t this_x = segs[i].pos;
|
||||
assert(this_x == i * line_spacing + x0);
|
||||
|
@ -1159,8 +1160,8 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||
int iSegAbove = -1;
|
||||
int iSegBelow = -1;
|
||||
{
|
||||
SegmentIntersection::SegmentIntersectionType type_crossing = (intrsctn->type == SegmentIntersection::INNER_LOW) ?
|
||||
SegmentIntersection::INNER_HIGH : SegmentIntersection::INNER_LOW;
|
||||
// SegmentIntersection::SegmentIntersectionType type_crossing = (intrsctn->type == SegmentIntersection::INNER_LOW) ?
|
||||
// SegmentIntersection::INNER_HIGH : SegmentIntersection::INNER_LOW;
|
||||
// Does the perimeter intersect the current vertical line above intrsctn?
|
||||
for (size_t i = i_intersection + 1; i + 1 < seg.intersections.size(); ++ i)
|
||||
// if (seg.intersections[i].iContour == intrsctn->iContour && seg.intersections[i].type == type_crossing) {
|
||||
|
|
|
@ -849,7 +849,7 @@ static inline IntersectionTypeOtherVLine intersection_type_on_prev_next_vertical
|
|||
{
|
||||
// This routine will propose a connecting line even if the connecting perimeter segment intersects
|
||||
// iVertical line multiple times before reaching iIntersectionOther.
|
||||
if (iIntersectionOther == -1)
|
||||
if (iIntersectionOther == size_t(-1))
|
||||
return INTERSECTION_TYPE_OTHER_VLINE_UNDEFINED;
|
||||
assert(dir_is_next ? (iVerticalLine + 1 < segs.size()) : (iVerticalLine > 0));
|
||||
const SegmentedIntersectionLine &il_this = segs[iVerticalLine];
|
||||
|
@ -1284,8 +1284,8 @@ static bool fill_hatching_segments_legacy(
|
|||
int iSegAbove = -1;
|
||||
int iSegBelow = -1;
|
||||
{
|
||||
SegmentIntersection::SegmentIntersectionType type_crossing = (intrsctn->type == SegmentIntersection::INNER_LOW) ?
|
||||
SegmentIntersection::INNER_HIGH : SegmentIntersection::INNER_LOW;
|
||||
// SegmentIntersection::SegmentIntersectionType type_crossing = (intrsctn->type == SegmentIntersection::INNER_LOW) ?
|
||||
// SegmentIntersection::INNER_HIGH : SegmentIntersection::INNER_LOW;
|
||||
// Does the perimeter intersect the current vertical line above intrsctn?
|
||||
for (size_t i = i_intersection + 1; i + 1 < seg.intersections.size(); ++ i)
|
||||
// if (seg.intersections[i].iContour == intrsctn->iContour && seg.intersections[i].type == type_crossing) {
|
||||
|
|
|
@ -696,7 +696,7 @@ namespace Slic3r {
|
|||
if (!XML_ParseBuffer(m_xml_parser, (int)stat.m_uncomp_size, 1))
|
||||
{
|
||||
char error_buf[1024];
|
||||
::sprintf(error_buf, "Error (%s) while parsing xml file at line %d", XML_ErrorString(XML_GetErrorCode(m_xml_parser)), XML_GetCurrentLineNumber(m_xml_parser));
|
||||
::sprintf(error_buf, "Error (%s) while parsing xml file at line %d", XML_ErrorString(XML_GetErrorCode(m_xml_parser)), (int)XML_GetCurrentLineNumber(m_xml_parser));
|
||||
add_error(error_buf);
|
||||
return false;
|
||||
}
|
||||
|
@ -976,7 +976,7 @@ namespace Slic3r {
|
|||
if (!XML_ParseBuffer(m_xml_parser, (int)stat.m_uncomp_size, 1))
|
||||
{
|
||||
char error_buf[1024];
|
||||
::sprintf(error_buf, "Error (%s) while parsing xml file at line %d", XML_ErrorString(XML_GetErrorCode(m_xml_parser)), XML_GetCurrentLineNumber(m_xml_parser));
|
||||
::sprintf(error_buf, "Error (%s) while parsing xml file at line %d", XML_ErrorString(XML_GetErrorCode(m_xml_parser)), (int)XML_GetCurrentLineNumber(m_xml_parser));
|
||||
add_error(error_buf);
|
||||
return false;
|
||||
}
|
||||
|
@ -1533,7 +1533,7 @@ namespace Slic3r {
|
|||
object->second.metadata.emplace_back(key, value);
|
||||
else if (type == VOLUME_TYPE)
|
||||
{
|
||||
if (m_curr_config.volume_id < object->second.volumes.size())
|
||||
if (size_t(m_curr_config.volume_id) < object->second.volumes.size())
|
||||
object->second.volumes[m_curr_config.volume_id].metadata.emplace_back(key, value);
|
||||
}
|
||||
else
|
||||
|
@ -2134,7 +2134,7 @@ namespace Slic3r {
|
|||
const DynamicPrintConfig& config = range.second;
|
||||
for (const std::string& opt_key : config.keys())
|
||||
{
|
||||
pt::ptree& opt_tree = range_tree.add("option", config.serialize(opt_key));
|
||||
pt::ptree& opt_tree = range_tree.add("option", config.opt_serialize(opt_key));
|
||||
opt_tree.put("<xmlattr>.opt_key", opt_key);
|
||||
}
|
||||
}
|
||||
|
@ -2216,7 +2216,7 @@ namespace Slic3r {
|
|||
|
||||
for (const std::string &key : config.keys())
|
||||
if (key != "compatible_printers")
|
||||
out += "; " + key + " = " + config.serialize(key) + "\n";
|
||||
out += "; " + key + " = " + config.opt_serialize(key) + "\n";
|
||||
|
||||
if (!out.empty())
|
||||
{
|
||||
|
@ -2250,7 +2250,7 @@ namespace Slic3r {
|
|||
// stores object's config data
|
||||
for (const std::string& key : obj->config.keys())
|
||||
{
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << obj->config.serialize(key) << "\"/>\n";
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << obj->config.opt_serialize(key) << "\"/>\n";
|
||||
}
|
||||
|
||||
for (const ModelVolume* volume : obj_metadata.second.object->volumes)
|
||||
|
@ -2280,7 +2280,7 @@ namespace Slic3r {
|
|||
// stores volume's config data
|
||||
for (const std::string& key : volume->config.keys())
|
||||
{
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.serialize(key) << "\"/>\n";
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n";
|
||||
}
|
||||
|
||||
stream << " </" << VOLUME_TAG << ">\n";
|
||||
|
|
|
@ -722,8 +722,8 @@ bool load_amf_file(const char *path, DynamicPrintConfig *config, Model *model)
|
|||
}
|
||||
int done = feof(pFile);
|
||||
if (XML_Parse(parser, buff, len, done) == XML_STATUS_ERROR) {
|
||||
printf("AMF parser: Parse error at line %ul:\n%s\n",
|
||||
XML_GetCurrentLineNumber(parser),
|
||||
printf("AMF parser: Parse error at line %d:\n%s\n",
|
||||
(int)XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
break;
|
||||
}
|
||||
|
@ -781,7 +781,7 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
|
|||
|
||||
if (!XML_ParseBuffer(parser, (int)stat.m_uncomp_size, 1))
|
||||
{
|
||||
printf("Error (%s) while parsing xml file at line %d\n", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));
|
||||
printf("Error (%s) while parsing xml file at line %d\n", XML_ErrorString(XML_GetErrorCode(parser)), (int)XML_GetCurrentLineNumber(parser));
|
||||
close_zip_reader(&archive);
|
||||
return false;
|
||||
}
|
||||
|
@ -901,7 +901,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||
std::string str_config = "\n";
|
||||
for (const std::string &key : config->keys())
|
||||
if (key != "compatible_printers")
|
||||
str_config += "; " + key + " = " + config->serialize(key) + "\n";
|
||||
str_config += "; " + key + " = " + config->opt_serialize(key) + "\n";
|
||||
stream << "<metadata type=\"" << SLIC3R_CONFIG_TYPE << "\">" << xml_escape(str_config) << "</metadata>\n";
|
||||
}
|
||||
|
||||
|
@ -913,7 +913,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||
for (const auto &attr : material.second->attributes)
|
||||
stream << " <metadata type=\"" << attr.first << "\">" << attr.second << "</metadata>\n";
|
||||
for (const std::string &key : material.second->config.keys())
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << material.second->config.serialize(key) << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << material.second->config.opt_serialize(key) << "</metadata>\n";
|
||||
stream << " </material>\n";
|
||||
}
|
||||
std::string instances;
|
||||
|
@ -921,7 +921,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||
ModelObject *object = model->objects[object_id];
|
||||
stream << " <object id=\"" << object_id << "\">\n";
|
||||
for (const std::string &key : object->config.keys())
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << object->config.serialize(key) << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << object->config.opt_serialize(key) << "</metadata>\n";
|
||||
if (!object->name.empty())
|
||||
stream << " <metadata type=\"name\">" << xml_escape(object->name) << "</metadata>\n";
|
||||
const std::vector<double> &layer_height_profile = object->layer_height_profile;
|
||||
|
@ -933,10 +933,8 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||
stream << ";" << layer_height_profile[i];
|
||||
stream << "\n </metadata>\n";
|
||||
}
|
||||
//FIXME Store the layer height ranges (ModelObject::layer_height_ranges)
|
||||
|
||||
|
||||
// #ys_FIXME_experiment : Try to export layer config range
|
||||
// Export layer height ranges including the layer range specific config overrides.
|
||||
const t_layer_config_ranges& config_ranges = object->layer_config_ranges;
|
||||
if (!config_ranges.empty())
|
||||
{
|
||||
|
@ -950,7 +948,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||
stream << range.first.first << ";" << range.first.second << "</metadata>\n";
|
||||
|
||||
for (const std::string& key : range.second.keys())
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << range.second.serialize(key) << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << range.second.opt_serialize(key) << "</metadata>\n";
|
||||
|
||||
stream << " </range>\n";
|
||||
layer_counter++;
|
||||
|
@ -1005,14 +1003,14 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||
else
|
||||
stream << " <volume materialid=\"" << volume->material_id() << "\">\n";
|
||||
for (const std::string &key : volume->config.keys())
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << volume->config.serialize(key) << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << volume->config.opt_serialize(key) << "</metadata>\n";
|
||||
if (!volume->name.empty())
|
||||
stream << " <metadata type=\"name\">" << xml_escape(volume->name) << "</metadata>\n";
|
||||
if (volume->is_modifier())
|
||||
stream << " <metadata type=\"slic3r.modifier\">1</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.volume_type\">" << ModelVolume::type_to_string(volume->type()) << "</metadata>\n";
|
||||
const indexed_triangle_set &its = volume->mesh().its;
|
||||
for (size_t i = 0; i < (int)its.indices.size(); ++i) {
|
||||
for (size_t i = 0; i < its.indices.size(); ++i) {
|
||||
stream << " <triangle>\n";
|
||||
for (int j = 0; j < 3; ++j)
|
||||
stream << " <v" << j + 1 << ">" << its.indices[i][j] + vertices_offset << "</v" << j + 1 << ">\n";
|
||||
|
|
|
@ -176,8 +176,7 @@ static bool obj_parseline(const char *line, ObjData &data)
|
|||
EATWS();
|
||||
if (*line == 0)
|
||||
return false;
|
||||
// number of vertices of this face
|
||||
int n = 0;
|
||||
|
||||
// current vertex to be parsed
|
||||
ObjVertex vertex;
|
||||
char *endptr = 0;
|
||||
|
@ -266,7 +265,6 @@ static bool obj_parseline(const char *line, ObjData &data)
|
|||
{
|
||||
// o [object name]
|
||||
EATWS();
|
||||
const char *name = line;
|
||||
while (*line != ' ' && *line != '\t' && *line != 0)
|
||||
++ line;
|
||||
// copy name to line.
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "EdgeGrid.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "GCode/PrintExtents.hpp"
|
||||
#include "GCode/WipeTowerPrusaMM.hpp"
|
||||
#include "GCode/WipeTower.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -162,9 +162,9 @@ std::string Wipe::wipe(GCode &gcodegen, bool toolchange)
|
|||
return gcode;
|
||||
}
|
||||
|
||||
static inline Point wipe_tower_point_to_object_point(GCode &gcodegen, const WipeTower::xy &wipe_tower_pt)
|
||||
static inline Point wipe_tower_point_to_object_point(GCode &gcodegen, const Vec2f &wipe_tower_pt)
|
||||
{
|
||||
return Point(scale_(wipe_tower_pt.x - gcodegen.origin()(0)), scale_(wipe_tower_pt.y - gcodegen.origin()(1)));
|
||||
return Point(scale_(wipe_tower_pt.x() - gcodegen.origin()(0)), scale_(wipe_tower_pt.y() - gcodegen.origin()(1)));
|
||||
}
|
||||
|
||||
std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id) const
|
||||
|
@ -174,17 +174,21 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
|
|||
// Toolchangeresult.gcode assumes the wipe tower corner is at the origin
|
||||
// We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position
|
||||
float alpha = m_wipe_tower_rotation/180.f * float(M_PI);
|
||||
WipeTower::xy start_pos = tcr.start_pos;
|
||||
WipeTower::xy end_pos = tcr.end_pos;
|
||||
start_pos.rotate(alpha);
|
||||
start_pos.translate(m_wipe_tower_pos);
|
||||
end_pos.rotate(alpha);
|
||||
end_pos.translate(m_wipe_tower_pos);
|
||||
std::string tcr_rotated_gcode = rotate_wipe_tower_moves(tcr.gcode, tcr.start_pos, m_wipe_tower_pos, alpha);
|
||||
Vec2f start_pos = tcr.start_pos;
|
||||
Vec2f end_pos = tcr.end_pos;
|
||||
if (!tcr.priming) {
|
||||
start_pos = Eigen::Rotation2Df(alpha) * start_pos;
|
||||
start_pos += m_wipe_tower_pos;
|
||||
end_pos = Eigen::Rotation2Df(alpha) * end_pos;
|
||||
end_pos += m_wipe_tower_pos;
|
||||
}
|
||||
std::string tcr_rotated_gcode = tcr.priming ? tcr.gcode : rotate_wipe_tower_moves(tcr.gcode, tcr.start_pos, m_wipe_tower_pos, alpha);
|
||||
|
||||
|
||||
// Disable linear advance for the wipe tower operations.
|
||||
gcode += (gcodegen.config().gcode_flavor == gcfRepRap ? std::string("M572 D0 S0\n") : std::string("M900 K0\n"));
|
||||
|
||||
if (!tcr.priming) {
|
||||
// Move over the wipe tower.
|
||||
// Retract for a tool change, using the toolchange retract value and setting the priming extra length.
|
||||
gcode += gcodegen.retract(true);
|
||||
|
@ -194,27 +198,73 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
|
|||
erMixed,
|
||||
"Travel to a Wipe Tower");
|
||||
gcode += gcodegen.unretract();
|
||||
}
|
||||
|
||||
|
||||
// Process the end filament gcode.
|
||||
std::string end_filament_gcode_str;
|
||||
if (gcodegen.writer().extruder() != nullptr) {
|
||||
// Process the custom end_filament_gcode in case of single_extruder_multi_material.
|
||||
unsigned int old_extruder_id = gcodegen.writer().extruder()->id();
|
||||
const std::string &end_filament_gcode = gcodegen.config().end_filament_gcode.get_at(old_extruder_id);
|
||||
if (gcodegen.writer().extruder() != nullptr && ! end_filament_gcode.empty()) {
|
||||
end_filament_gcode_str = gcodegen.placeholder_parser_process("end_filament_gcode", end_filament_gcode, old_extruder_id);
|
||||
check_add_eol(end_filament_gcode_str);
|
||||
}
|
||||
}
|
||||
|
||||
// Process the custom toolchange_gcode. If it is empty, provide a simple Tn command to change the filament.
|
||||
// Otherwise, leave control to the user completely.
|
||||
std::string toolchange_gcode_str;
|
||||
if (true /*gcodegen.writer().extruder() != nullptr*/) {
|
||||
const std::string& toolchange_gcode = gcodegen.config().toolchange_gcode.value;
|
||||
if (!toolchange_gcode.empty()) {
|
||||
DynamicConfig config;
|
||||
int previous_extruder_id = gcodegen.writer().extruder() ? (int)gcodegen.writer().extruder()->id() : -1;
|
||||
config.set_key_value("previous_extruder", new ConfigOptionInt(previous_extruder_id));
|
||||
config.set_key_value("next_extruder", new ConfigOptionInt((int)new_extruder_id));
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z));
|
||||
toolchange_gcode_str = gcodegen.placeholder_parser_process("toolchange_gcode", toolchange_gcode, new_extruder_id, &config);
|
||||
check_add_eol(toolchange_gcode_str);
|
||||
}
|
||||
|
||||
std::string toolchange_command;
|
||||
if (tcr.priming || (new_extruder_id >= 0 && gcodegen.writer().need_toolchange(new_extruder_id)))
|
||||
toolchange_command = gcodegen.writer().toolchange(new_extruder_id);
|
||||
if (toolchange_gcode.empty())
|
||||
toolchange_gcode_str = toolchange_command;
|
||||
else {
|
||||
// We have informed the m_writer about the current extruder_id, we can ignore the generated G-code.
|
||||
}
|
||||
}
|
||||
|
||||
// Let the tool change be executed by the wipe tower class.
|
||||
// Inform the G-code writer about the changes done behind its back.
|
||||
gcode += tcr_rotated_gcode;
|
||||
// Let the m_writer know the current extruder_id, but ignore the generated G-code.
|
||||
if (new_extruder_id >= 0 && gcodegen.writer().need_toolchange(new_extruder_id))
|
||||
gcodegen.writer().toolchange(new_extruder_id);
|
||||
gcodegen.placeholder_parser().set("current_extruder", new_extruder_id);
|
||||
|
||||
// Always append the filament start G-code even if the extruder did not switch,
|
||||
// because the wipe tower resets the linear advance and we want it to be re-enabled.
|
||||
// Process the start filament gcode.
|
||||
std::string start_filament_gcode_str;
|
||||
const std::string &start_filament_gcode = gcodegen.config().start_filament_gcode.get_at(new_extruder_id);
|
||||
if (! start_filament_gcode.empty()) {
|
||||
// Process the start_filament_gcode for the active filament only.
|
||||
DynamicConfig config;
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(new_extruder_id));
|
||||
gcode += gcodegen.placeholder_parser_process("start_filament_gcode", start_filament_gcode, new_extruder_id, &config);
|
||||
check_add_eol(gcode);
|
||||
start_filament_gcode_str = gcodegen.placeholder_parser_process("start_filament_gcode", start_filament_gcode, new_extruder_id, &config);
|
||||
check_add_eol(start_filament_gcode_str);
|
||||
}
|
||||
|
||||
// Insert the end filament, toolchange, and start filament gcode into the generated gcode.
|
||||
DynamicConfig config;
|
||||
config.set_key_value("end_filament_gcode", new ConfigOptionString(end_filament_gcode_str));
|
||||
config.set_key_value("toolchange_gcode", new ConfigOptionString(toolchange_gcode_str));
|
||||
config.set_key_value("start_filament_gcode", new ConfigOptionString(start_filament_gcode_str));
|
||||
std::string tcr_gcode, tcr_escaped_gcode = gcodegen.placeholder_parser_process("tcr_rotated_gcode", tcr_rotated_gcode, new_extruder_id, &config);
|
||||
unescape_string_cstyle(tcr_escaped_gcode, tcr_gcode);
|
||||
gcode += tcr_gcode;
|
||||
check_add_eol(toolchange_gcode_str);
|
||||
|
||||
|
||||
// A phony move to the end position at the wipe tower.
|
||||
gcodegen.writer().travel_to_xy(Vec2d(end_pos.x, end_pos.y));
|
||||
gcodegen.writer().travel_to_xy(end_pos.cast<double>());
|
||||
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos));
|
||||
|
||||
// Prepare a future wipe.
|
||||
|
@ -224,8 +274,8 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
|
|||
gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, end_pos));
|
||||
// Wipe end point: Wipe direction away from the closer tower edge to the further tower edge.
|
||||
gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen,
|
||||
WipeTower::xy((std::abs(m_left - end_pos.x) < std::abs(m_right - end_pos.x)) ? m_right : m_left,
|
||||
end_pos.y)));
|
||||
Vec2f((std::abs(m_left - end_pos.x()) < std::abs(m_right - end_pos.x())) ? m_right : m_left,
|
||||
end_pos.y())));
|
||||
}
|
||||
|
||||
// Let the planner know we are traveling between objects.
|
||||
|
@ -235,14 +285,14 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
|
|||
|
||||
// This function postprocesses gcode_original, rotates and moves all G1 extrusions and returns resulting gcode
|
||||
// Starting position has to be supplied explicitely (otherwise it would fail in case first G1 command only contained one coordinate)
|
||||
std::string WipeTowerIntegration::rotate_wipe_tower_moves(const std::string& gcode_original, const WipeTower::xy& start_pos, const WipeTower::xy& translation, float angle) const
|
||||
std::string WipeTowerIntegration::rotate_wipe_tower_moves(const std::string& gcode_original, const Vec2f& start_pos, const Vec2f& translation, float angle) const
|
||||
{
|
||||
std::istringstream gcode_str(gcode_original);
|
||||
std::string gcode_out;
|
||||
std::string line;
|
||||
WipeTower::xy pos = start_pos;
|
||||
WipeTower::xy transformed_pos;
|
||||
WipeTower::xy old_pos(-1000.1f, -1000.1f);
|
||||
Vec2f pos = start_pos;
|
||||
Vec2f transformed_pos;
|
||||
Vec2f old_pos(-1000.1f, -1000.1f);
|
||||
|
||||
while (gcode_str) {
|
||||
std::getline(gcode_str, line); // we read the gcode line by line
|
||||
|
@ -253,25 +303,25 @@ std::string WipeTowerIntegration::rotate_wipe_tower_moves(const std::string& gco
|
|||
char ch = 0;
|
||||
while (line_str >> ch) {
|
||||
if (ch == 'X')
|
||||
line_str >> pos.x;
|
||||
line_str >> pos.x();
|
||||
else
|
||||
if (ch == 'Y')
|
||||
line_str >> pos.y;
|
||||
line_str >> pos.y();
|
||||
else
|
||||
line_out << ch;
|
||||
}
|
||||
|
||||
transformed_pos = pos;
|
||||
transformed_pos.rotate(angle);
|
||||
transformed_pos.translate(translation);
|
||||
transformed_pos = Eigen::Rotation2Df(angle) * transformed_pos;
|
||||
transformed_pos += translation;
|
||||
|
||||
if (transformed_pos != old_pos) {
|
||||
line = line_out.str();
|
||||
char buf[2048] = "G1";
|
||||
if (transformed_pos.x != old_pos.x)
|
||||
sprintf(buf + strlen(buf), " X%.3f", transformed_pos.x);
|
||||
if (transformed_pos.y != old_pos.y)
|
||||
sprintf(buf + strlen(buf), " Y%.3f", transformed_pos.y);
|
||||
if (transformed_pos.x() != old_pos.x())
|
||||
sprintf(buf + strlen(buf), " X%.3f", transformed_pos.x());
|
||||
if (transformed_pos.y() != old_pos.y())
|
||||
sprintf(buf + strlen(buf), " Y%.3f", transformed_pos.y());
|
||||
|
||||
line.replace(line.find("G1 "), 3, buf);
|
||||
old_pos = transformed_pos;
|
||||
|
@ -288,27 +338,36 @@ std::string WipeTowerIntegration::prime(GCode &gcodegen)
|
|||
assert(m_layer_idx == 0);
|
||||
std::string gcode;
|
||||
|
||||
if (&m_priming != nullptr && ! m_priming.extrusions.empty()) {
|
||||
if (&m_priming != nullptr) {
|
||||
// Disable linear advance for the wipe tower operations.
|
||||
gcode += (gcodegen.config().gcode_flavor == gcfRepRap ? std::string("M572 D0 S0\n") : std::string("M900 K0\n"));
|
||||
//gcode += (gcodegen.config().gcode_flavor == gcfRepRap ? std::string("M572 D0 S0\n") : std::string("M900 K0\n"));
|
||||
|
||||
for (const WipeTower::ToolChangeResult& tcr : m_priming) {
|
||||
if (!tcr.extrusions.empty())
|
||||
gcode += append_tcr(gcodegen, tcr, tcr.new_tool);
|
||||
|
||||
|
||||
// Let the tool change be executed by the wipe tower class.
|
||||
// Inform the G-code writer about the changes done behind its back.
|
||||
gcode += m_priming.gcode;
|
||||
//gcode += tcr.gcode;
|
||||
// Let the m_writer know the current extruder_id, but ignore the generated G-code.
|
||||
unsigned int current_extruder_id = m_priming.extrusions.back().tool;
|
||||
gcodegen.writer().toolchange(current_extruder_id);
|
||||
gcodegen.placeholder_parser().set("current_extruder", current_extruder_id);
|
||||
// unsigned int current_extruder_id = tcr.extrusions.back().tool;
|
||||
// gcodegen.writer().toolchange(current_extruder_id);
|
||||
// gcodegen.placeholder_parser().set("current_extruder", current_extruder_id);
|
||||
|
||||
}
|
||||
|
||||
// A phony move to the end position at the wipe tower.
|
||||
gcodegen.writer().travel_to_xy(Vec2d(m_priming.end_pos.x, m_priming.end_pos.y));
|
||||
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, m_priming.end_pos));
|
||||
/* gcodegen.writer().travel_to_xy(Vec2d(m_priming.back().end_pos.x, m_priming.back().end_pos.y));
|
||||
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, m_priming.back().end_pos));
|
||||
// Prepare a future wipe.
|
||||
gcodegen.m_wipe.path.points.clear();
|
||||
// Start the wipe at the current position.
|
||||
gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, m_priming.end_pos));
|
||||
gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, m_priming.back().end_pos));
|
||||
// Wipe end point: Wipe direction away from the closer tower edge to the further tower edge.
|
||||
gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen,
|
||||
WipeTower::xy((std::abs(m_left - m_priming.end_pos.x) < std::abs(m_right - m_priming.end_pos.x)) ? m_right : m_left,
|
||||
m_priming.end_pos.y)));
|
||||
WipeTower::xy((std::abs(m_left - m_priming.back().end_pos.x) < std::abs(m_right - m_priming.back().end_pos.x)) ? m_right : m_left,
|
||||
m_priming.back().end_pos.y)));*/
|
||||
}
|
||||
return gcode;
|
||||
}
|
||||
|
@ -316,10 +375,10 @@ std::string WipeTowerIntegration::prime(GCode &gcodegen)
|
|||
std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id, bool finish_layer)
|
||||
{
|
||||
std::string gcode;
|
||||
assert(m_layer_idx >= 0 && m_layer_idx <= m_tool_changes.size());
|
||||
assert(m_layer_idx >= 0 && size_t(m_layer_idx) <= m_tool_changes.size());
|
||||
if (! m_brim_done || gcodegen.writer().need_toolchange(extruder_id) || finish_layer) {
|
||||
if (m_layer_idx < m_tool_changes.size()) {
|
||||
assert(m_tool_change_idx < m_tool_changes[m_layer_idx].size());
|
||||
if (m_layer_idx < (int)m_tool_changes.size()) {
|
||||
assert(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size());
|
||||
gcode += append_tcr(gcodegen, m_tool_changes[m_layer_idx][m_tool_change_idx++], extruder_id);
|
||||
}
|
||||
m_brim_done = true;
|
||||
|
@ -807,24 +866,16 @@ void GCode::_do_export(Print &print, FILE *file)
|
|||
|
||||
// Write the custom start G-code
|
||||
_writeln(file, start_gcode);
|
||||
// Process filament-specific gcode in extruder order.
|
||||
if (print.config().single_extruder_multi_material) {
|
||||
if (has_wipe_tower) {
|
||||
|
||||
// Process filament-specific gcode.
|
||||
/* if (has_wipe_tower) {
|
||||
// Wipe tower will control the extruder switching, it will call the start_filament_gcode.
|
||||
} else {
|
||||
// Only initialize the initial extruder.
|
||||
DynamicConfig config;
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(initial_extruder_id)));
|
||||
_writeln(file, this->placeholder_parser_process("start_filament_gcode", print.config().start_filament_gcode.values[initial_extruder_id], initial_extruder_id, &config));
|
||||
}
|
||||
} else {
|
||||
DynamicConfig config;
|
||||
for (const std::string &start_gcode : print.config().start_filament_gcode.values) {
|
||||
int extruder_id = (unsigned int)(&start_gcode - &print.config().start_filament_gcode.values.front());
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
|
||||
_writeln(file, this->placeholder_parser_process("start_filament_gcode", start_gcode, extruder_id, &config));
|
||||
}
|
||||
}
|
||||
*/
|
||||
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
|
||||
print.throw_if_canceled();
|
||||
|
||||
|
@ -1260,7 +1311,7 @@ void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, c
|
|||
int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
|
||||
if (temp_by_gcode >= 0 && temp_by_gcode < 1000)
|
||||
temp = temp_by_gcode;
|
||||
m_writer.set_temperature(temp_by_gcode, wait, first_printing_extruder_id);
|
||||
m_writer.set_temperature(temp, wait, first_printing_extruder_id);
|
||||
} else {
|
||||
// Custom G-code does not set the extruder temperature. Do it now.
|
||||
if (print.config().single_extruder_multi_material.value) {
|
||||
|
@ -1351,11 +1402,11 @@ void GCode::process_layer(
|
|||
// Check whether it is possible to apply the spiral vase logic for this layer.
|
||||
// Just a reminder: A spiral vase mode is allowed for a single object, single material print only.
|
||||
if (m_spiral_vase && layers.size() == 1 && support_layer == nullptr) {
|
||||
bool enable = (layer.id() > 0 || print.config().brim_width.value == 0.) && (layer.id() >= print.config().skirt_height.value && ! print.has_infinite_skirt());
|
||||
bool enable = (layer.id() > 0 || print.config().brim_width.value == 0.) && (layer.id() >= (size_t)print.config().skirt_height.value && ! print.has_infinite_skirt());
|
||||
if (enable) {
|
||||
for (const LayerRegion *layer_region : layer.regions())
|
||||
if (layer_region->region()->config().bottom_solid_layers.value > layer.id() ||
|
||||
layer_region->perimeters.items_count() > 1 ||
|
||||
if (size_t(layer_region->region()->config().bottom_solid_layers.value) > layer.id() ||
|
||||
layer_region->perimeters.items_count() > 1u ||
|
||||
layer_region->fills.items_count() > 0) {
|
||||
enable = false;
|
||||
break;
|
||||
|
@ -1423,11 +1474,11 @@ void GCode::process_layer(
|
|||
bool extrude_skirt =
|
||||
! print.skirt().entities.empty() &&
|
||||
// Not enough skirt layers printed yet.
|
||||
(m_skirt_done.size() < print.config().skirt_height.value || print.has_infinite_skirt()) &&
|
||||
(m_skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt()) &&
|
||||
// This print_z has not been extruded yet
|
||||
(m_skirt_done.empty() ? 0. : m_skirt_done.back()) < print_z - EPSILON &&
|
||||
// and this layer is the 1st layer, or it is an object layer, or it is a raft layer.
|
||||
(first_layer || object_layer != nullptr || support_layer->id() < m_config.raft_layers.value);
|
||||
(first_layer || object_layer != nullptr || support_layer->id() < (size_t)m_config.raft_layers.value);
|
||||
std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder;
|
||||
coordf_t skirt_height = 0.;
|
||||
if (extrude_skirt) {
|
||||
|
@ -1758,7 +1809,7 @@ void GCode::append_full_config(const Print& print, std::string& str)
|
|||
const StaticPrintConfig *cfg = configs[i];
|
||||
for (const std::string &key : cfg->keys())
|
||||
if (key != "compatible_printers")
|
||||
str += "; " + key + " = " + cfg->serialize(key) + "\n";
|
||||
str += "; " + key + " = " + cfg->opt_serialize(key) + "\n";
|
||||
}
|
||||
const DynamicConfig &full_config = print.placeholder_parser().config();
|
||||
for (const char *key : {
|
||||
|
@ -2076,19 +2127,18 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
|||
|
||||
// Retrieve the last start position for this object.
|
||||
float last_pos_weight = 1.f;
|
||||
switch (seam_position) {
|
||||
case spAligned:
|
||||
|
||||
if (seam_position == spAligned) {
|
||||
// Seam is aligned to the seam at the preceding layer.
|
||||
if (m_layer != NULL && m_seam_position.count(m_layer->object()) > 0) {
|
||||
last_pos = m_seam_position[m_layer->object()];
|
||||
last_pos_weight = 1.f;
|
||||
}
|
||||
break;
|
||||
case spRear:
|
||||
}
|
||||
else if (seam_position == spRear) {
|
||||
last_pos = m_layer->object()->bounding_box().center();
|
||||
last_pos(1) += coord_t(3. * m_layer->object()->bounding_box().radius());
|
||||
last_pos_weight = 5.f;
|
||||
break;
|
||||
}
|
||||
|
||||
// Insert a projection of last_pos into the polygon.
|
||||
|
@ -2097,7 +2147,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
|||
Points::iterator it = project_point_to_polygon_and_insert(polygon, last_pos, 0.1 * nozzle_r);
|
||||
last_pos_proj_idx = it - polygon.points.begin();
|
||||
}
|
||||
Point last_pos_proj = polygon.points[last_pos_proj_idx];
|
||||
|
||||
// Parametrize the polygon by its length.
|
||||
std::vector<float> lengths = polygon_parameter_by_length(polygon);
|
||||
|
||||
|
@ -2107,7 +2157,6 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
|||
// No penalty for reflex points, slight penalty for convex points, high penalty for flat surfaces.
|
||||
const float penaltyConvexVertex = 1.f;
|
||||
const float penaltyFlatSurface = 5.f;
|
||||
const float penaltySeam = 1.3f;
|
||||
const float penaltyOverhangHalf = 10.f;
|
||||
// Penalty for visible seams.
|
||||
for (size_t i = 0; i < polygon.points.size(); ++ i) {
|
||||
|
@ -2152,7 +2201,11 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
|
|||
// Signed distance is positive outside the object, negative inside the object.
|
||||
// The point is considered at an overhang, if it is more than nozzle radius
|
||||
// outside of the lower layer contour.
|
||||
#ifdef NDEBUG // to suppress unused variable warning in release mode
|
||||
(*lower_layer_edge_grid)->signed_distance(p, search_r, dist);
|
||||
#else
|
||||
bool found = (*lower_layer_edge_grid)->signed_distance(p, search_r, dist);
|
||||
#endif
|
||||
// If the approximate Signed Distance Field was initialized over lower_layer_edge_grid,
|
||||
// then the signed distnace shall always be known.
|
||||
assert(found);
|
||||
|
@ -2563,7 +2616,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||
gcode += buf;
|
||||
}
|
||||
|
||||
if (m_last_mm3_per_mm != path.mm3_per_mm)
|
||||
if (last_was_wipe_tower || (m_last_mm3_per_mm != path.mm3_per_mm))
|
||||
{
|
||||
m_last_mm3_per_mm = path.mm3_per_mm;
|
||||
|
||||
|
@ -2741,38 +2794,57 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
|||
m_wipe.reset_path();
|
||||
|
||||
if (m_writer.extruder() != nullptr) {
|
||||
// Process the custom end_filament_gcode in case of single_extruder_multi_material.
|
||||
// Process the custom end_filament_gcode. set_extruder() is only called if there is no wipe tower
|
||||
// so it should not be injected twice.
|
||||
unsigned int old_extruder_id = m_writer.extruder()->id();
|
||||
const std::string &end_filament_gcode = m_config.end_filament_gcode.get_at(old_extruder_id);
|
||||
if (m_config.single_extruder_multi_material && ! end_filament_gcode.empty()) {
|
||||
if (! end_filament_gcode.empty()) {
|
||||
gcode += placeholder_parser_process("end_filament_gcode", end_filament_gcode, old_extruder_id);
|
||||
check_add_eol(gcode);
|
||||
}
|
||||
}
|
||||
|
||||
m_placeholder_parser.set("current_extruder", extruder_id);
|
||||
|
||||
if (m_writer.extruder() != nullptr && ! m_config.toolchange_gcode.value.empty()) {
|
||||
// Process the custom toolchange_gcode.
|
||||
DynamicConfig config;
|
||||
config.set_key_value("previous_extruder", new ConfigOptionInt((int)m_writer.extruder()->id()));
|
||||
config.set_key_value("next_extruder", new ConfigOptionInt((int)extruder_id));
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
|
||||
gcode += placeholder_parser_process("toolchange_gcode", m_config.toolchange_gcode.value, extruder_id, &config);
|
||||
check_add_eol(gcode);
|
||||
}
|
||||
|
||||
// If ooze prevention is enabled, park current extruder in the nearest
|
||||
// standby point and set it to the standby temperature.
|
||||
if (m_ooze_prevention.enable && m_writer.extruder() != nullptr)
|
||||
gcode += m_ooze_prevention.pre_toolchange(*this);
|
||||
// Append the toolchange command.
|
||||
gcode += m_writer.toolchange(extruder_id);
|
||||
// Append the filament start G-code for single_extruder_multi_material.
|
||||
|
||||
const std::string& toolchange_gcode = m_config.toolchange_gcode.value;
|
||||
|
||||
// Process the custom toolchange_gcode. If it is empty, insert just a Tn command.
|
||||
if (!toolchange_gcode.empty()) {
|
||||
DynamicConfig config;
|
||||
config.set_key_value("previous_extruder", new ConfigOptionInt((int)(m_writer.extruder() != nullptr ? m_writer.extruder()->id() : -1 )));
|
||||
config.set_key_value("next_extruder", new ConfigOptionInt((int)extruder_id));
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
|
||||
gcode += placeholder_parser_process("toolchange_gcode", toolchange_gcode, extruder_id, &config);
|
||||
check_add_eol(gcode);
|
||||
}
|
||||
|
||||
// We inform the writer about what is happening, but we may not use the resulting gcode.
|
||||
std::string toolchange_command = m_writer.toolchange(extruder_id);
|
||||
if (toolchange_gcode.empty())
|
||||
gcode += toolchange_command;
|
||||
else {
|
||||
// user provided his own toolchange gcode, no need to do anything
|
||||
}
|
||||
|
||||
// Set the temperature if the wipe tower didn't (not needed for non-single extruder MM)
|
||||
if (m_config.single_extruder_multi_material && !m_config.wipe_tower) {
|
||||
int temp = (m_layer_index == 0 ? m_config.first_layer_temperature.get_at(extruder_id) :
|
||||
m_config.temperature.get_at(extruder_id));
|
||||
|
||||
gcode += m_writer.set_temperature(temp, false);
|
||||
}
|
||||
|
||||
m_placeholder_parser.set("current_extruder", extruder_id);
|
||||
|
||||
// Append the filament start G-code.
|
||||
const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id);
|
||||
if (m_config.single_extruder_multi_material && ! start_filament_gcode.empty()) {
|
||||
// Process the start_filament_gcode for the active filament only.
|
||||
if (! start_filament_gcode.empty()) {
|
||||
// Process the start_filament_gcode for the new filament.
|
||||
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id);
|
||||
check_add_eol(gcode);
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ class WipeTowerIntegration {
|
|||
public:
|
||||
WipeTowerIntegration(
|
||||
const PrintConfig &print_config,
|
||||
const WipeTower::ToolChangeResult &priming,
|
||||
const std::vector<WipeTower::ToolChangeResult> &priming,
|
||||
const std::vector<std::vector<WipeTower::ToolChangeResult>> &tool_changes,
|
||||
const WipeTower::ToolChangeResult &final_purge) :
|
||||
m_left(/*float(print_config.wipe_tower_x.value)*/ 0.f),
|
||||
|
@ -108,15 +108,15 @@ private:
|
|||
std::string append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id) const;
|
||||
|
||||
// Postprocesses gcode: rotates and moves all G1 extrusions and returns result
|
||||
std::string rotate_wipe_tower_moves(const std::string& gcode_original, const WipeTower::xy& start_pos, const WipeTower::xy& translation, float angle) const;
|
||||
std::string rotate_wipe_tower_moves(const std::string& gcode_original, const Vec2f& start_pos, const Vec2f& translation, float angle) const;
|
||||
|
||||
// Left / right edges of the wipe tower, for the planning of wipe moves.
|
||||
const float m_left;
|
||||
const float m_right;
|
||||
const WipeTower::xy m_wipe_tower_pos;
|
||||
const Vec2f m_wipe_tower_pos;
|
||||
const float m_wipe_tower_rotation;
|
||||
// Reference to cached values at the Printer class.
|
||||
const WipeTower::ToolChangeResult &m_priming;
|
||||
const std::vector<WipeTower::ToolChangeResult> &m_priming;
|
||||
const std::vector<std::vector<WipeTower::ToolChangeResult>> &m_tool_changes;
|
||||
const WipeTower::ToolChangeResult &m_final_purge;
|
||||
// Current layer index.
|
||||
|
|
|
@ -672,7 +672,7 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
|||
#define EXTRUDER_CONFIG(OPT) config.OPT.get_at(m_current_extruder)
|
||||
int min_fan_speed = EXTRUDER_CONFIG(min_fan_speed);
|
||||
int fan_speed_new = EXTRUDER_CONFIG(fan_always_on) ? min_fan_speed : 0;
|
||||
if (layer_id >= EXTRUDER_CONFIG(disable_fan_first_layers)) {
|
||||
if (layer_id >= (size_t)EXTRUDER_CONFIG(disable_fan_first_layers)) {
|
||||
int max_fan_speed = EXTRUDER_CONFIG(max_fan_speed);
|
||||
float slowdown_below_layer_time = float(EXTRUDER_CONFIG(slowdown_below_layer_time));
|
||||
float fan_below_layer_time = float(EXTRUDER_CONFIG(fan_below_layer_time));
|
||||
|
|
|
@ -404,6 +404,8 @@ std::string GCodePreviewData::get_legend_title() const
|
|||
return L("Tool");
|
||||
case Extrusion::ColorPrint:
|
||||
return L("Color Print");
|
||||
case Extrusion::Num_View_Types:
|
||||
break; // just to supress warning about non-handled value
|
||||
}
|
||||
|
||||
return "";
|
||||
|
@ -508,6 +510,8 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
|
|||
}
|
||||
break;
|
||||
}
|
||||
case Extrusion::Num_View_Types:
|
||||
break; // just to supress warning about non-handled value
|
||||
}
|
||||
|
||||
return items;
|
||||
|
|
|
@ -149,8 +149,8 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_
|
|||
const WipeTower::Extrusion &e = tcr.extrusions[i];
|
||||
if (e.width > 0) {
|
||||
Vec2d delta = 0.5 * Vec2d(e.width, e.width);
|
||||
Vec2d p1 = trafo * Vec2d((&e - 1)->pos.x, (&e - 1)->pos.y);
|
||||
Vec2d p2 = trafo * Vec2d(e.pos.x, e.pos.y);
|
||||
Vec2d p1 = trafo * (&e - 1)->pos.cast<double>();
|
||||
Vec2d p2 = trafo * e.pos.cast<double>();
|
||||
bbox.merge(p1.cwiseMin(p2) - delta);
|
||||
bbox.merge(p1.cwiseMax(p2) + delta);
|
||||
}
|
||||
|
@ -165,12 +165,12 @@ BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print)
|
|||
{
|
||||
BoundingBoxf bbox;
|
||||
if (print.wipe_tower_data().priming != nullptr) {
|
||||
const WipeTower::ToolChangeResult &tcr = *print.wipe_tower_data().priming;
|
||||
for (const WipeTower::ToolChangeResult &tcr : *print.wipe_tower_data().priming) {
|
||||
for (size_t i = 1; i < tcr.extrusions.size(); ++ i) {
|
||||
const WipeTower::Extrusion &e = tcr.extrusions[i];
|
||||
if (e.width > 0) {
|
||||
Vec2d p1((&e - 1)->pos.x, (&e - 1)->pos.y);
|
||||
Vec2d p2(e.pos.x, e.pos.y);
|
||||
const Vec2d& p1 = (&e - 1)->pos.cast<double>();
|
||||
const Vec2d& p2 = e.pos.cast<double>();
|
||||
bbox.merge(p1);
|
||||
coordf_t radius = 0.5 * e.width;
|
||||
bbox.min(0) = std::min(bbox.min(0), std::min(p1(0), p2(0)) - radius);
|
||||
|
@ -180,6 +180,7 @@ BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bbox;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ std::string SpiralVase::process_layer(const std::string &gcode)
|
|||
// Get total XY length for this layer by summing all extrusion moves.
|
||||
float total_layer_length = 0;
|
||||
float layer_height = 0;
|
||||
float z;
|
||||
float z = 0.f;
|
||||
bool set_z = false;
|
||||
|
||||
{
|
||||
|
|
|
@ -324,9 +324,8 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
|
|||
m_layer_tools[j].has_wipe_tower = true;
|
||||
} else {
|
||||
LayerTools <_extra = *m_layer_tools.insert(m_layer_tools.begin() + j, lt_new);
|
||||
LayerTools <_prev = m_layer_tools[j - 1];
|
||||
LayerTools <_next = m_layer_tools[j + 1];
|
||||
assert(! lt_prev.extruders.empty() && ! lt_next.extruders.empty());
|
||||
assert(! m_layer_tools[j - 1].extruders.empty() && ! lt_next.extruders.empty());
|
||||
// FIXME: Following assert tripped when running combine_infill.t. I decided to comment it out for now.
|
||||
// If it is a bug, it's likely not critical, because this code is unchanged for a long time. It might
|
||||
// still be worth looking into it more and decide if it is a bug or an obsolete assert.
|
||||
|
@ -495,9 +494,6 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
|||
if (!is_overriddable(*fill, print.config(), *object, region))
|
||||
continue;
|
||||
|
||||
// What extruder would this normally be printed with?
|
||||
unsigned int correct_extruder = Print::get_extruder(*fill, region);
|
||||
|
||||
if (volume_to_wipe<=0)
|
||||
continue;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,95 +1,30 @@
|
|||
#ifndef slic3r_WipeTower_hpp_
|
||||
#define slic3r_WipeTower_hpp_
|
||||
#ifndef WipeTower_
|
||||
#define WipeTower_
|
||||
|
||||
#include <math.h>
|
||||
#include <utility>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
// A pure virtual WipeTower definition.
|
||||
class WipeTowerWriter;
|
||||
|
||||
|
||||
|
||||
class WipeTower
|
||||
{
|
||||
public:
|
||||
// Internal point class, to make the wipe tower independent from other slic3r modules.
|
||||
// This is important for Prusa Research as we want to build the wipe tower post-processor independently from slic3r.
|
||||
struct xy
|
||||
{
|
||||
xy(float x = 0.f, float y = 0.f) : x(x), y(y) {}
|
||||
xy(const xy& pos,float xp,float yp) : x(pos.x+xp), y(pos.y+yp) {}
|
||||
xy operator+(const xy &rhs) const { xy out(*this); out.x += rhs.x; out.y += rhs.y; return out; }
|
||||
xy operator-(const xy &rhs) const { xy out(*this); out.x -= rhs.x; out.y -= rhs.y; return out; }
|
||||
xy& operator+=(const xy &rhs) { x += rhs.x; y += rhs.y; return *this; }
|
||||
xy& operator-=(const xy &rhs) { x -= rhs.x; y -= rhs.y; return *this; }
|
||||
bool operator==(const xy &rhs) const { return x == rhs.x && y == rhs.y; }
|
||||
bool operator!=(const xy &rhs) const { return x != rhs.x || y != rhs.y; }
|
||||
|
||||
// Rotate the point around center of the wipe tower about given angle (in degrees)
|
||||
xy rotate(float width, float depth, float angle) const {
|
||||
xy out(0,0);
|
||||
float temp_x = x - width / 2.f;
|
||||
float temp_y = y - depth / 2.f;
|
||||
angle *= float(M_PI/180.);
|
||||
out.x += temp_x * cos(angle) - temp_y * sin(angle) + width / 2.f;
|
||||
out.y += temp_x * sin(angle) + temp_y * cos(angle) + depth / 2.f;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Rotate the point around origin about given angle in degrees
|
||||
void rotate(float angle) {
|
||||
float temp_x = x * cos(angle) - y * sin(angle);
|
||||
y = x * sin(angle) + y * cos(angle);
|
||||
x = temp_x;
|
||||
}
|
||||
|
||||
void translate(const xy& vect) {
|
||||
x += vect.x;
|
||||
y += vect.y;
|
||||
}
|
||||
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
WipeTower() {}
|
||||
virtual ~WipeTower() {}
|
||||
|
||||
// Return the wipe tower position.
|
||||
virtual const xy& position() const = 0;
|
||||
|
||||
// Return the wipe tower width.
|
||||
virtual float width() const = 0;
|
||||
|
||||
// The wipe tower is finished, there should be no more tool changes or wipe tower prints.
|
||||
virtual bool finished() const = 0;
|
||||
|
||||
// Switch to a next layer.
|
||||
virtual void set_layer(
|
||||
// Print height of this layer.
|
||||
float print_z,
|
||||
// Layer height, used to calculate extrusion the rate.
|
||||
float layer_height,
|
||||
// Maximum number of tool changes on this layer or the layers below.
|
||||
size_t max_tool_changes,
|
||||
// Is this the first layer of the print? In that case print the brim first.
|
||||
bool is_first_layer,
|
||||
// Is this the last layer of the wipe tower?
|
||||
bool is_last_layer) = 0;
|
||||
|
||||
enum Purpose {
|
||||
PURPOSE_MOVE_TO_TOWER,
|
||||
PURPOSE_EXTRUDE,
|
||||
PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE,
|
||||
};
|
||||
|
||||
// Extrusion path of the wipe tower, for 3D preview of the generated tool paths.
|
||||
struct Extrusion
|
||||
{
|
||||
Extrusion(const xy &pos, float width, unsigned int tool) : pos(pos), width(width), tool(tool) {}
|
||||
Extrusion(const Vec2f &pos, float width, unsigned int tool) : pos(pos), width(width), tool(tool) {}
|
||||
// End position of this extrusion.
|
||||
xy pos;
|
||||
Vec2f pos;
|
||||
// Width of a squished extrusion, corrected for the roundings of the squished extrusions.
|
||||
// This is left zero if it is a travel move.
|
||||
float width;
|
||||
|
@ -108,10 +43,10 @@ public:
|
|||
std::vector<Extrusion> extrusions;
|
||||
// Initial position, at which the wipe tower starts its action.
|
||||
// At this position the extruder is loaded and there is no Z-hop applied.
|
||||
xy start_pos;
|
||||
Vec2f start_pos;
|
||||
// Last point, at which the normal G-code generator of Slic3r shall continue.
|
||||
// At this position the extruder is loaded and there is no Z-hop applied.
|
||||
xy end_pos;
|
||||
Vec2f end_pos;
|
||||
// Time elapsed over this tool change.
|
||||
// This is useful not only for the print time estimation, but also for the control of layer cooling.
|
||||
float elapsed_time;
|
||||
|
@ -119,50 +54,375 @@ public:
|
|||
// Is this a priming extrusion? (If so, the wipe tower rotation & translation will not be applied later)
|
||||
bool priming;
|
||||
|
||||
// Initial tool
|
||||
int initial_tool;
|
||||
|
||||
// New tool
|
||||
int new_tool;
|
||||
|
||||
// Sum the total length of the extrusion.
|
||||
float total_extrusion_length_in_plane() {
|
||||
float e_length = 0.f;
|
||||
for (size_t i = 1; i < this->extrusions.size(); ++ i) {
|
||||
const Extrusion &e = this->extrusions[i];
|
||||
if (e.width > 0) {
|
||||
xy v = e.pos - (&e - 1)->pos;
|
||||
e_length += sqrt(v.x*v.x+v.y*v.y);
|
||||
Vec2f v = e.pos - (&e - 1)->pos;
|
||||
e_length += v.norm();
|
||||
}
|
||||
}
|
||||
return e_length;
|
||||
}
|
||||
};
|
||||
|
||||
// x -- x coordinates of wipe tower in mm ( left bottom corner )
|
||||
// y -- y coordinates of wipe tower in mm ( left bottom corner )
|
||||
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
|
||||
// wipe_area -- space available for one toolchange in mm
|
||||
WipeTower(bool semm, float x, float y, float width, float rotation_angle, float cooling_tube_retraction,
|
||||
float cooling_tube_length, float parking_pos_retraction, float extra_loading_move,
|
||||
float bridging, bool set_extruder_trimpot, GCodeFlavor flavor,
|
||||
const std::vector<std::vector<float>>& wiping_matrix, unsigned int initial_tool) :
|
||||
m_semm(semm),
|
||||
m_wipe_tower_pos(x, y),
|
||||
m_wipe_tower_width(width),
|
||||
m_wipe_tower_rotation_angle(rotation_angle),
|
||||
m_y_shift(0.f),
|
||||
m_z_pos(0.f),
|
||||
m_is_first_layer(false),
|
||||
m_gcode_flavor(flavor),
|
||||
m_bridging(bridging),
|
||||
m_current_tool(initial_tool),
|
||||
wipe_volumes(wiping_matrix)
|
||||
{
|
||||
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
||||
// Otherwise, the defaults will be used to turn off the SE stuff.
|
||||
if (m_semm) {
|
||||
m_cooling_tube_retraction = cooling_tube_retraction;
|
||||
m_cooling_tube_length = cooling_tube_length;
|
||||
m_parking_pos_retraction = parking_pos_retraction;
|
||||
m_extra_loading_move = extra_loading_move;
|
||||
m_set_extruder_trimpot = set_extruder_trimpot;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~WipeTower() {}
|
||||
|
||||
|
||||
// Set the extruder properties.
|
||||
void set_extruder(size_t idx, std::string material, int temp, int first_layer_temp, float loading_speed, float loading_speed_start,
|
||||
float unloading_speed, float unloading_speed_start, float delay, int cooling_moves,
|
||||
float cooling_initial_speed, float cooling_final_speed, std::string ramming_parameters, float max_volumetric_speed, float nozzle_diameter)
|
||||
{
|
||||
//while (m_filpar.size() < idx+1) // makes sure the required element is in the vector
|
||||
m_filpar.push_back(FilamentParameters());
|
||||
|
||||
m_filpar[idx].material = material;
|
||||
m_filpar[idx].temperature = temp;
|
||||
m_filpar[idx].first_layer_temperature = first_layer_temp;
|
||||
|
||||
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
||||
// Otherwise, the defaults will be used to turn off the SE stuff.
|
||||
if (m_semm) {
|
||||
m_filpar[idx].loading_speed = loading_speed;
|
||||
m_filpar[idx].loading_speed_start = loading_speed_start;
|
||||
m_filpar[idx].unloading_speed = unloading_speed;
|
||||
m_filpar[idx].unloading_speed_start = unloading_speed_start;
|
||||
m_filpar[idx].delay = delay;
|
||||
m_filpar[idx].cooling_moves = cooling_moves;
|
||||
m_filpar[idx].cooling_initial_speed = cooling_initial_speed;
|
||||
m_filpar[idx].cooling_final_speed = cooling_final_speed;
|
||||
}
|
||||
|
||||
if (max_volumetric_speed != 0.f)
|
||||
m_filpar[idx].max_e_speed = (max_volumetric_speed / Filament_Area);
|
||||
m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
|
||||
|
||||
m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter
|
||||
|
||||
std::stringstream stream{m_semm ? ramming_parameters : std::string()};
|
||||
float speed = 0.f;
|
||||
stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator;
|
||||
m_filpar[idx].ramming_line_width_multiplicator /= 100;
|
||||
m_filpar[idx].ramming_step_multiplicator /= 100;
|
||||
while (stream >> speed)
|
||||
m_filpar[idx].ramming_speed.push_back(speed);
|
||||
|
||||
m_used_filament_length.resize(std::max(m_used_filament_length.size(), idx + 1)); // makes sure that the vector is big enough so we don't have to check later
|
||||
}
|
||||
|
||||
|
||||
// Appends into internal structure m_plan containing info about the future wipe tower
|
||||
// to be used before building begins. The entries must be added ordered in z.
|
||||
void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim, float wipe_volume = 0.f);
|
||||
|
||||
// Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result"
|
||||
void generate(std::vector<std::vector<ToolChangeResult>> &result);
|
||||
|
||||
float get_depth() const { return m_wipe_tower_depth; }
|
||||
|
||||
|
||||
|
||||
// Switch to a next layer.
|
||||
void set_layer(
|
||||
// Print height of this layer.
|
||||
float print_z,
|
||||
// Layer height, used to calculate extrusion the rate.
|
||||
float layer_height,
|
||||
// Maximum number of tool changes on this layer or the layers below.
|
||||
size_t max_tool_changes,
|
||||
// Is this the first layer of the print? In that case print the brim first.
|
||||
bool is_first_layer,
|
||||
// Is this the last layer of the waste tower?
|
||||
bool is_last_layer)
|
||||
{
|
||||
m_z_pos = print_z;
|
||||
m_layer_height = layer_height;
|
||||
m_is_first_layer = is_first_layer;
|
||||
m_print_brim = is_first_layer;
|
||||
m_depth_traversed = 0.f;
|
||||
m_current_shape = (! is_first_layer && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL;
|
||||
if (is_first_layer) {
|
||||
this->m_num_layer_changes = 0;
|
||||
this->m_num_tool_changes = 0;
|
||||
}
|
||||
else
|
||||
++ m_num_layer_changes;
|
||||
|
||||
// Calculate extrusion flow from desired line width, nozzle diameter, filament diameter and layer_height:
|
||||
m_extrusion_flow = extrusion_flow(layer_height);
|
||||
|
||||
// Advance m_layer_info iterator, making sure we got it right
|
||||
while (!m_plan.empty() && m_layer_info->z < print_z - WT_EPSILON && m_layer_info+1 != m_plan.end())
|
||||
++m_layer_info;
|
||||
}
|
||||
|
||||
// Return the wipe tower position.
|
||||
const Vec2f& position() const { return m_wipe_tower_pos; }
|
||||
// Return the wipe tower width.
|
||||
float width() const { return m_wipe_tower_width; }
|
||||
// The wipe tower is finished, there should be no more tool changes or wipe tower prints.
|
||||
bool finished() const { return m_max_color_changes == 0; }
|
||||
|
||||
// Returns gcode to prime the nozzles at the front edge of the print bed.
|
||||
virtual ToolChangeResult prime(
|
||||
std::vector<ToolChangeResult> prime(
|
||||
// print_z of the first layer.
|
||||
float first_layer_height,
|
||||
// Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object.
|
||||
const std::vector<unsigned int> &tools,
|
||||
// If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower.
|
||||
// If false, the last priming are will be large enough to wipe the last extruder sufficiently.
|
||||
bool last_wipe_inside_wipe_tower) = 0;
|
||||
bool last_wipe_inside_wipe_tower);
|
||||
|
||||
// Returns gcode for toolchange and the end position.
|
||||
// if new_tool == -1, just unload the current filament over the wipe tower.
|
||||
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer) = 0;
|
||||
// Returns gcode for a toolchange and a final print head position.
|
||||
// On the first layer, extrude a brim around the future wipe tower first.
|
||||
ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer);
|
||||
|
||||
// Close the current wipe tower layer with a perimeter and possibly fill the unfilled space with a zig-zag.
|
||||
// Fill the unfilled space with a sparse infill.
|
||||
// Call this method only if layer_finished() is false.
|
||||
virtual ToolChangeResult finish_layer() = 0;
|
||||
ToolChangeResult finish_layer();
|
||||
|
||||
// Is the current layer finished? A layer is finished if either the wipe tower is finished, or
|
||||
// the wipe tower has been completely covered by the tool change extrusions,
|
||||
// or the rest of the tower has been filled by a sparse infill with the finish_layer() method.
|
||||
virtual bool layer_finished() const = 0;
|
||||
// Is the current layer finished?
|
||||
bool layer_finished() const {
|
||||
return ( (m_is_first_layer ? m_wipe_tower_depth - m_perimeter_width : m_layer_info->depth) - WT_EPSILON < m_depth_traversed);
|
||||
}
|
||||
|
||||
// Returns used filament length per extruder:
|
||||
virtual std::vector<float> get_used_filament() const = 0;
|
||||
std::vector<float> get_used_filament() const { return m_used_filament_length; }
|
||||
int get_number_of_toolchanges() const { return m_num_tool_changes; }
|
||||
|
||||
// Returns total number of toolchanges:
|
||||
virtual int get_number_of_toolchanges() const = 0;
|
||||
struct FilamentParameters {
|
||||
std::string material = "PLA";
|
||||
int temperature = 0;
|
||||
int first_layer_temperature = 0;
|
||||
float loading_speed = 0.f;
|
||||
float loading_speed_start = 0.f;
|
||||
float unloading_speed = 0.f;
|
||||
float unloading_speed_start = 0.f;
|
||||
float delay = 0.f ;
|
||||
int cooling_moves = 0;
|
||||
float cooling_initial_speed = 0.f;
|
||||
float cooling_final_speed = 0.f;
|
||||
float ramming_line_width_multiplicator = 0.f;
|
||||
float ramming_step_multiplicator = 0.f;
|
||||
float max_e_speed = std::numeric_limits<float>::max();
|
||||
std::vector<float> ramming_speed;
|
||||
float nozzle_diameter;
|
||||
};
|
||||
|
||||
private:
|
||||
WipeTower();
|
||||
|
||||
enum wipe_shape // A fill-in direction
|
||||
{
|
||||
SHAPE_NORMAL = 1,
|
||||
SHAPE_REVERSED = -1
|
||||
};
|
||||
|
||||
|
||||
const bool m_peters_wipe_tower = false; // sparse wipe tower inspired by Peter's post processor - not finished yet
|
||||
const float Filament_Area = float(M_PI * 1.75f * 1.75f / 4.f); // filament area in mm^2
|
||||
const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust
|
||||
const float WT_EPSILON = 1e-3f;
|
||||
|
||||
|
||||
bool m_semm = true; // Are we using a single extruder multimaterial printer?
|
||||
Vec2f m_wipe_tower_pos; // Left front corner of the wipe tower in mm.
|
||||
float m_wipe_tower_width; // Width of the wipe tower.
|
||||
float m_wipe_tower_depth = 0.f; // Depth of the wipe tower
|
||||
float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis)
|
||||
float m_internal_rotation = 0.f;
|
||||
float m_y_shift = 0.f; // y shift passed to writer
|
||||
float m_z_pos = 0.f; // Current Z position.
|
||||
float m_layer_height = 0.f; // Current layer height.
|
||||
size_t m_max_color_changes = 0; // Maximum number of color changes per layer.
|
||||
bool m_is_first_layer = false;// Is this the 1st layer of the print? If so, print the brim around the waste tower.
|
||||
int m_old_temperature = -1; // To keep track of what was the last temp that we set (so we don't issue the command when not neccessary)
|
||||
|
||||
// G-code generator parameters.
|
||||
float m_cooling_tube_retraction = 0.f;
|
||||
float m_cooling_tube_length = 0.f;
|
||||
float m_parking_pos_retraction = 0.f;
|
||||
float m_extra_loading_move = 0.f;
|
||||
float m_bridging = 0.f;
|
||||
bool m_set_extruder_trimpot = false;
|
||||
bool m_adhesion = true;
|
||||
GCodeFlavor m_gcode_flavor;
|
||||
|
||||
float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.
|
||||
float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
|
||||
|
||||
// Extruder specific parameters.
|
||||
std::vector<FilamentParameters> m_filpar;
|
||||
|
||||
|
||||
// State of the wipe tower generator.
|
||||
unsigned int m_num_layer_changes = 0; // Layer change counter for the output statistics.
|
||||
unsigned int m_num_tool_changes = 0; // Tool change change counter for the output statistics.
|
||||
///unsigned int m_idx_tool_change_in_layer = 0; // Layer change counter in this layer. Counting up to m_max_color_changes.
|
||||
bool m_print_brim = true;
|
||||
// A fill-in direction (positive Y, negative Y) alternates with each layer.
|
||||
wipe_shape m_current_shape = SHAPE_NORMAL;
|
||||
unsigned int m_current_tool = 0;
|
||||
const std::vector<std::vector<float>> wipe_volumes;
|
||||
|
||||
float m_depth_traversed = 0.f; // Current y position at the wipe tower.
|
||||
bool m_left_to_right = true;
|
||||
float m_extra_spacing = 1.f;
|
||||
|
||||
// Calculates extrusion flow needed to produce required line width for given layer height
|
||||
float extrusion_flow(float layer_height = -1.f) const // negative layer_height - return current m_extrusion_flow
|
||||
{
|
||||
if ( layer_height < 0 )
|
||||
return m_extrusion_flow;
|
||||
return layer_height * ( m_perimeter_width - layer_height * (1.f-float(M_PI)/4.f)) / Filament_Area;
|
||||
}
|
||||
|
||||
// Calculates length of extrusion line to extrude given volume
|
||||
float volume_to_length(float volume, float line_width, float layer_height) const {
|
||||
return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f))));
|
||||
}
|
||||
|
||||
// Calculates depth for all layers and propagates them downwards
|
||||
void plan_tower();
|
||||
|
||||
// Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental
|
||||
void make_wipe_tower_square();
|
||||
|
||||
// Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe
|
||||
void save_on_last_wipe();
|
||||
|
||||
|
||||
struct box_coordinates
|
||||
{
|
||||
box_coordinates(float left, float bottom, float width, float height) :
|
||||
ld(left , bottom ),
|
||||
lu(left , bottom + height),
|
||||
rd(left + width, bottom ),
|
||||
ru(left + width, bottom + height) {}
|
||||
box_coordinates(const Vec2f &pos, float width, float height) : box_coordinates(pos(0), pos(1), width, height) {}
|
||||
void translate(const Vec2f &shift) {
|
||||
ld += shift; lu += shift;
|
||||
rd += shift; ru += shift;
|
||||
}
|
||||
void translate(const float dx, const float dy) { translate(Vec2f(dx, dy)); }
|
||||
void expand(const float offset) {
|
||||
ld += Vec2f(- offset, - offset);
|
||||
lu += Vec2f(- offset, offset);
|
||||
rd += Vec2f( offset, - offset);
|
||||
ru += Vec2f( offset, offset);
|
||||
}
|
||||
void expand(const float offset_x, const float offset_y) {
|
||||
ld += Vec2f(- offset_x, - offset_y);
|
||||
lu += Vec2f(- offset_x, offset_y);
|
||||
rd += Vec2f( offset_x, - offset_y);
|
||||
ru += Vec2f( offset_x, offset_y);
|
||||
}
|
||||
Vec2f ld; // left down
|
||||
Vec2f lu; // left upper
|
||||
Vec2f rd; // right lower
|
||||
Vec2f ru; // right upper
|
||||
};
|
||||
|
||||
|
||||
// to store information about tool changes for a given layer
|
||||
struct WipeTowerInfo{
|
||||
struct ToolChange {
|
||||
unsigned int old_tool;
|
||||
unsigned int new_tool;
|
||||
float required_depth;
|
||||
float ramming_depth;
|
||||
float first_wipe_line;
|
||||
float wipe_volume;
|
||||
ToolChange(unsigned int old, unsigned int newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f)
|
||||
: old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth}, first_wipe_line{fwl}, wipe_volume{wv} {}
|
||||
};
|
||||
float z; // z position of the layer
|
||||
float height; // layer height
|
||||
float depth; // depth of the layer based on all layers above
|
||||
float extra_spacing;
|
||||
float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; }
|
||||
|
||||
std::vector<ToolChange> tool_changes;
|
||||
|
||||
WipeTowerInfo(float z_par, float layer_height_par)
|
||||
: z{z_par}, height{layer_height_par}, depth{0}, extra_spacing{1.f} {}
|
||||
};
|
||||
|
||||
std::vector<WipeTowerInfo> m_plan; // Stores information about all layers and toolchanges for the future wipe tower (filled by plan_toolchange(...))
|
||||
std::vector<WipeTowerInfo>::iterator m_layer_info = m_plan.end();
|
||||
|
||||
// Stores information about used filament length per extruder:
|
||||
std::vector<float> m_used_filament_length;
|
||||
|
||||
|
||||
// Returns gcode for wipe tower brim
|
||||
// sideOnly -- set to false -- experimental, draw brim on sides of wipe tower
|
||||
// offset -- set to 0 -- experimental, offset to replace brim in front / rear of wipe tower
|
||||
ToolChangeResult toolchange_Brim(bool sideOnly = false, float y_offset = 0.f);
|
||||
|
||||
void toolchange_Unload(
|
||||
WipeTowerWriter &writer,
|
||||
const box_coordinates &cleaning_box,
|
||||
const std::string& current_material,
|
||||
const int new_temperature);
|
||||
|
||||
void toolchange_Change(
|
||||
WipeTowerWriter &writer,
|
||||
const unsigned int new_tool,
|
||||
const std::string& new_material);
|
||||
|
||||
void toolchange_Load(
|
||||
WipeTowerWriter &writer,
|
||||
const box_coordinates &cleaning_box);
|
||||
|
||||
void toolchange_Wipe(
|
||||
WipeTowerWriter &writer,
|
||||
const box_coordinates &cleaning_box,
|
||||
float wipe_volume);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_WipeTower_hpp_ */
|
||||
#endif // WipeTowerPrusaMM_hpp_
|
||||
|
|
|
@ -1,388 +0,0 @@
|
|||
#ifndef WipeTowerPrusaMM_hpp_
|
||||
#define WipeTowerPrusaMM_hpp_
|
||||
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
|
||||
#include "WipeTower.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
namespace PrusaMultiMaterial {
|
||||
class Writer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class WipeTowerPrusaMM : public WipeTower
|
||||
{
|
||||
public:
|
||||
enum material_type
|
||||
{
|
||||
INVALID = -1,
|
||||
PLA = 0, // E:210C B:55C
|
||||
ABS = 1, // E:255C B:100C
|
||||
PET = 2, // E:240C B:90C
|
||||
HIPS = 3, // E:220C B:100C
|
||||
FLEX = 4, // E:245C B:80C
|
||||
SCAFF = 5, // E:215C B:55C
|
||||
EDGE = 6, // E:240C B:80C
|
||||
NGEN = 7, // E:230C B:80C
|
||||
PVA = 8, // E:210C B:80C
|
||||
PC = 9
|
||||
};
|
||||
|
||||
// Parse material name into material_type.
|
||||
static material_type parse_material(const char *name);
|
||||
static std::string to_string(material_type material);
|
||||
|
||||
// x -- x coordinates of wipe tower in mm ( left bottom corner )
|
||||
// y -- y coordinates of wipe tower in mm ( left bottom corner )
|
||||
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
|
||||
// wipe_area -- space available for one toolchange in mm
|
||||
WipeTowerPrusaMM(float x, float y, float width, float rotation_angle, float cooling_tube_retraction,
|
||||
float cooling_tube_length, float parking_pos_retraction, float extra_loading_move,
|
||||
float bridging, bool set_extruder_trimpot, GCodeFlavor flavor,
|
||||
const std::vector<std::vector<float>>& wiping_matrix, unsigned int initial_tool) :
|
||||
m_wipe_tower_pos(x, y),
|
||||
m_wipe_tower_width(width),
|
||||
m_wipe_tower_rotation_angle(rotation_angle),
|
||||
m_y_shift(0.f),
|
||||
m_z_pos(0.f),
|
||||
m_is_first_layer(false),
|
||||
m_cooling_tube_retraction(cooling_tube_retraction),
|
||||
m_cooling_tube_length(cooling_tube_length),
|
||||
m_parking_pos_retraction(parking_pos_retraction),
|
||||
m_extra_loading_move(extra_loading_move),
|
||||
m_bridging(bridging),
|
||||
m_set_extruder_trimpot(set_extruder_trimpot),
|
||||
m_gcode_flavor(flavor),
|
||||
m_current_tool(initial_tool),
|
||||
wipe_volumes(wiping_matrix)
|
||||
{}
|
||||
|
||||
virtual ~WipeTowerPrusaMM() {}
|
||||
|
||||
|
||||
// Set the extruder properties.
|
||||
void set_extruder(size_t idx, material_type material, int temp, int first_layer_temp, float loading_speed, float loading_speed_start,
|
||||
float unloading_speed, float unloading_speed_start, float delay, int cooling_moves,
|
||||
float cooling_initial_speed, float cooling_final_speed, std::string ramming_parameters, float nozzle_diameter)
|
||||
{
|
||||
//while (m_filpar.size() < idx+1) // makes sure the required element is in the vector
|
||||
m_filpar.push_back(FilamentParameters());
|
||||
|
||||
m_filpar[idx].material = material;
|
||||
if (material == FLEX || material == SCAFF || material == PVA) {
|
||||
// MMU2 lowers the print speed using the speed override (M220) for printing of soluble PVA/BVOH and flex materials.
|
||||
// Therefore it does not make sense to use the new M220 B and M220 R (backup / restore).
|
||||
m_retain_speed_override = false;
|
||||
}
|
||||
m_filpar[idx].temperature = temp;
|
||||
m_filpar[idx].first_layer_temperature = first_layer_temp;
|
||||
m_filpar[idx].loading_speed = loading_speed;
|
||||
m_filpar[idx].loading_speed_start = loading_speed_start;
|
||||
m_filpar[idx].unloading_speed = unloading_speed;
|
||||
m_filpar[idx].unloading_speed_start = unloading_speed_start;
|
||||
m_filpar[idx].delay = delay;
|
||||
m_filpar[idx].cooling_moves = cooling_moves;
|
||||
m_filpar[idx].cooling_initial_speed = cooling_initial_speed;
|
||||
m_filpar[idx].cooling_final_speed = cooling_final_speed;
|
||||
m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
|
||||
|
||||
m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter
|
||||
|
||||
std::stringstream stream{ramming_parameters};
|
||||
float speed = 0.f;
|
||||
stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator;
|
||||
m_filpar[idx].ramming_line_width_multiplicator /= 100;
|
||||
m_filpar[idx].ramming_step_multiplicator /= 100;
|
||||
while (stream >> speed)
|
||||
m_filpar[idx].ramming_speed.push_back(speed);
|
||||
|
||||
m_used_filament_length.resize(std::max(m_used_filament_length.size(), idx + 1)); // makes sure that the vector is big enough so we don't have to check later
|
||||
}
|
||||
|
||||
|
||||
// Appends into internal structure m_plan containing info about the future wipe tower
|
||||
// to be used before building begins. The entries must be added ordered in z.
|
||||
void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim, float wipe_volume = 0.f);
|
||||
|
||||
// Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result"
|
||||
void generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &result);
|
||||
|
||||
float get_depth() const { return m_wipe_tower_depth; }
|
||||
|
||||
|
||||
|
||||
// Switch to a next layer.
|
||||
virtual void set_layer(
|
||||
// Print height of this layer.
|
||||
float print_z,
|
||||
// Layer height, used to calculate extrusion the rate.
|
||||
float layer_height,
|
||||
// Maximum number of tool changes on this layer or the layers below.
|
||||
size_t max_tool_changes,
|
||||
// Is this the first layer of the print? In that case print the brim first.
|
||||
bool is_first_layer,
|
||||
// Is this the last layer of the waste tower?
|
||||
bool is_last_layer)
|
||||
{
|
||||
m_z_pos = print_z;
|
||||
m_layer_height = layer_height;
|
||||
m_is_first_layer = is_first_layer;
|
||||
m_print_brim = is_first_layer;
|
||||
m_depth_traversed = 0.f;
|
||||
m_current_shape = (! is_first_layer && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL;
|
||||
if (is_first_layer) {
|
||||
this->m_num_layer_changes = 0;
|
||||
this->m_num_tool_changes = 0;
|
||||
}
|
||||
else
|
||||
++ m_num_layer_changes;
|
||||
|
||||
// Calculate extrusion flow from desired line width, nozzle diameter, filament diameter and layer_height:
|
||||
m_extrusion_flow = extrusion_flow(layer_height);
|
||||
|
||||
// Advance m_layer_info iterator, making sure we got it right
|
||||
while (!m_plan.empty() && m_layer_info->z < print_z - WT_EPSILON && m_layer_info+1 != m_plan.end())
|
||||
++m_layer_info;
|
||||
}
|
||||
|
||||
// Return the wipe tower position.
|
||||
virtual const xy& position() const { return m_wipe_tower_pos; }
|
||||
// Return the wipe tower width.
|
||||
virtual float width() const { return m_wipe_tower_width; }
|
||||
// The wipe tower is finished, there should be no more tool changes or wipe tower prints.
|
||||
virtual bool finished() const { return m_max_color_changes == 0; }
|
||||
|
||||
// Returns gcode to prime the nozzles at the front edge of the print bed.
|
||||
virtual ToolChangeResult prime(
|
||||
// print_z of the first layer.
|
||||
float first_layer_height,
|
||||
// Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object.
|
||||
const std::vector<unsigned int> &tools,
|
||||
// If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower.
|
||||
// If false, the last priming are will be large enough to wipe the last extruder sufficiently.
|
||||
bool last_wipe_inside_wipe_tower);
|
||||
|
||||
// Returns gcode for a toolchange and a final print head position.
|
||||
// On the first layer, extrude a brim around the future wipe tower first.
|
||||
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer);
|
||||
|
||||
// Fill the unfilled space with a sparse infill.
|
||||
// Call this method only if layer_finished() is false.
|
||||
virtual ToolChangeResult finish_layer();
|
||||
|
||||
// Is the current layer finished?
|
||||
virtual bool layer_finished() const {
|
||||
return ( (m_is_first_layer ? m_wipe_tower_depth - m_perimeter_width : m_layer_info->depth) - WT_EPSILON < m_depth_traversed);
|
||||
}
|
||||
|
||||
virtual std::vector<float> get_used_filament() const override { return m_used_filament_length; }
|
||||
virtual int get_number_of_toolchanges() const override { return m_num_tool_changes; }
|
||||
|
||||
|
||||
private:
|
||||
WipeTowerPrusaMM();
|
||||
|
||||
enum wipe_shape // A fill-in direction
|
||||
{
|
||||
SHAPE_NORMAL = 1,
|
||||
SHAPE_REVERSED = -1
|
||||
};
|
||||
|
||||
|
||||
const bool m_peters_wipe_tower = false; // sparse wipe tower inspired by Peter's post processor - not finished yet
|
||||
const float Filament_Area = float(M_PI * 1.75f * 1.75f / 4.f); // filament area in mm^2
|
||||
const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust
|
||||
const float WT_EPSILON = 1e-3f;
|
||||
|
||||
|
||||
xy m_wipe_tower_pos; // Left front corner of the wipe tower in mm.
|
||||
float m_wipe_tower_width; // Width of the wipe tower.
|
||||
float m_wipe_tower_depth = 0.f; // Depth of the wipe tower
|
||||
float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis)
|
||||
float m_internal_rotation = 0.f;
|
||||
float m_y_shift = 0.f; // y shift passed to writer
|
||||
float m_z_pos = 0.f; // Current Z position.
|
||||
float m_layer_height = 0.f; // Current layer height.
|
||||
size_t m_max_color_changes = 0; // Maximum number of color changes per layer.
|
||||
bool m_is_first_layer = false;// Is this the 1st layer of the print? If so, print the brim around the waste tower.
|
||||
int m_old_temperature = -1; // To keep track of what was the last temp that we set (so we don't issue the command when not neccessary)
|
||||
|
||||
// G-code generator parameters.
|
||||
float m_cooling_tube_retraction = 0.f;
|
||||
float m_cooling_tube_length = 0.f;
|
||||
float m_parking_pos_retraction = 0.f;
|
||||
float m_extra_loading_move = 0.f;
|
||||
float m_bridging = 0.f;
|
||||
bool m_set_extruder_trimpot = false;
|
||||
bool m_retain_speed_override = true;
|
||||
bool m_adhesion = true;
|
||||
GCodeFlavor m_gcode_flavor;
|
||||
|
||||
float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.
|
||||
float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
|
||||
|
||||
|
||||
struct FilamentParameters {
|
||||
material_type material = PLA;
|
||||
int temperature = 0;
|
||||
int first_layer_temperature = 0;
|
||||
float loading_speed = 0.f;
|
||||
float loading_speed_start = 0.f;
|
||||
float unloading_speed = 0.f;
|
||||
float unloading_speed_start = 0.f;
|
||||
float delay = 0.f ;
|
||||
int cooling_moves = 0;
|
||||
float cooling_initial_speed = 0.f;
|
||||
float cooling_final_speed = 0.f;
|
||||
float ramming_line_width_multiplicator = 0.f;
|
||||
float ramming_step_multiplicator = 0.f;
|
||||
std::vector<float> ramming_speed;
|
||||
float nozzle_diameter;
|
||||
};
|
||||
|
||||
// Extruder specific parameters.
|
||||
std::vector<FilamentParameters> m_filpar;
|
||||
|
||||
|
||||
// State of the wipe tower generator.
|
||||
unsigned int m_num_layer_changes = 0; // Layer change counter for the output statistics.
|
||||
unsigned int m_num_tool_changes = 0; // Tool change change counter for the output statistics.
|
||||
///unsigned int m_idx_tool_change_in_layer = 0; // Layer change counter in this layer. Counting up to m_max_color_changes.
|
||||
bool m_print_brim = true;
|
||||
// A fill-in direction (positive Y, negative Y) alternates with each layer.
|
||||
wipe_shape m_current_shape = SHAPE_NORMAL;
|
||||
unsigned int m_current_tool = 0;
|
||||
const std::vector<std::vector<float>> wipe_volumes;
|
||||
|
||||
float m_depth_traversed = 0.f; // Current y position at the wipe tower.
|
||||
bool m_left_to_right = true;
|
||||
float m_extra_spacing = 1.f;
|
||||
|
||||
// Calculates extrusion flow needed to produce required line width for given layer height
|
||||
float extrusion_flow(float layer_height = -1.f) const // negative layer_height - return current m_extrusion_flow
|
||||
{
|
||||
if ( layer_height < 0 )
|
||||
return m_extrusion_flow;
|
||||
return layer_height * ( m_perimeter_width - layer_height * (1.f-float(M_PI)/4.f)) / Filament_Area;
|
||||
}
|
||||
|
||||
// Calculates length of extrusion line to extrude given volume
|
||||
float volume_to_length(float volume, float line_width, float layer_height) const {
|
||||
return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f))));
|
||||
}
|
||||
|
||||
// Calculates depth for all layers and propagates them downwards
|
||||
void plan_tower();
|
||||
|
||||
// Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental
|
||||
void make_wipe_tower_square();
|
||||
|
||||
// Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe
|
||||
void save_on_last_wipe();
|
||||
|
||||
|
||||
struct box_coordinates
|
||||
{
|
||||
box_coordinates(float left, float bottom, float width, float height) :
|
||||
ld(left , bottom ),
|
||||
lu(left , bottom + height),
|
||||
rd(left + width, bottom ),
|
||||
ru(left + width, bottom + height) {}
|
||||
box_coordinates(const xy &pos, float width, float height) : box_coordinates(pos.x, pos.y, width, height) {}
|
||||
void translate(const xy &shift) {
|
||||
ld += shift; lu += shift;
|
||||
rd += shift; ru += shift;
|
||||
}
|
||||
void translate(const float dx, const float dy) { translate(xy(dx, dy)); }
|
||||
void expand(const float offset) {
|
||||
ld += xy(- offset, - offset);
|
||||
lu += xy(- offset, offset);
|
||||
rd += xy( offset, - offset);
|
||||
ru += xy( offset, offset);
|
||||
}
|
||||
void expand(const float offset_x, const float offset_y) {
|
||||
ld += xy(- offset_x, - offset_y);
|
||||
lu += xy(- offset_x, offset_y);
|
||||
rd += xy( offset_x, - offset_y);
|
||||
ru += xy( offset_x, offset_y);
|
||||
}
|
||||
xy ld; // left down
|
||||
xy lu; // left upper
|
||||
xy rd; // right lower
|
||||
xy ru; // right upper
|
||||
};
|
||||
|
||||
|
||||
// to store information about tool changes for a given layer
|
||||
struct WipeTowerInfo{
|
||||
struct ToolChange {
|
||||
unsigned int old_tool;
|
||||
unsigned int new_tool;
|
||||
float required_depth;
|
||||
float ramming_depth;
|
||||
float first_wipe_line;
|
||||
float wipe_volume;
|
||||
ToolChange(unsigned int old, unsigned int newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f)
|
||||
: old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth}, first_wipe_line{fwl}, wipe_volume{wv} {}
|
||||
};
|
||||
float z; // z position of the layer
|
||||
float height; // layer height
|
||||
float depth; // depth of the layer based on all layers above
|
||||
float extra_spacing;
|
||||
float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; }
|
||||
|
||||
std::vector<ToolChange> tool_changes;
|
||||
|
||||
WipeTowerInfo(float z_par, float layer_height_par)
|
||||
: z{z_par}, height{layer_height_par}, depth{0}, extra_spacing{1.f} {}
|
||||
};
|
||||
|
||||
std::vector<WipeTowerInfo> m_plan; // Stores information about all layers and toolchanges for the future wipe tower (filled by plan_toolchange(...))
|
||||
std::vector<WipeTowerInfo>::iterator m_layer_info = m_plan.end();
|
||||
|
||||
// Stores information about used filament length per extruder:
|
||||
std::vector<float> m_used_filament_length;
|
||||
|
||||
|
||||
// Returns gcode for wipe tower brim
|
||||
// sideOnly -- set to false -- experimental, draw brim on sides of wipe tower
|
||||
// offset -- set to 0 -- experimental, offset to replace brim in front / rear of wipe tower
|
||||
ToolChangeResult toolchange_Brim(bool sideOnly = false, float y_offset = 0.f);
|
||||
|
||||
void toolchange_Unload(
|
||||
PrusaMultiMaterial::Writer &writer,
|
||||
const box_coordinates &cleaning_box,
|
||||
const material_type current_material,
|
||||
const int new_temperature);
|
||||
|
||||
void toolchange_Change(
|
||||
PrusaMultiMaterial::Writer &writer,
|
||||
const unsigned int new_tool,
|
||||
material_type new_material);
|
||||
|
||||
void toolchange_Load(
|
||||
PrusaMultiMaterial::Writer &writer,
|
||||
const box_coordinates &cleaning_box);
|
||||
|
||||
void toolchange_Wipe(
|
||||
PrusaMultiMaterial::Writer &writer,
|
||||
const box_coordinates &cleaning_box,
|
||||
float wipe_volume);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif /* WipeTowerPrusaMM_hpp_ */
|
|
@ -912,7 +912,7 @@ MedialAxis::build(ThickPolylines* polylines)
|
|||
}
|
||||
*/
|
||||
|
||||
typedef const VD::vertex_type vert_t;
|
||||
//typedef const VD::vertex_type vert_t;
|
||||
typedef const VD::edge_type edge_t;
|
||||
|
||||
// collect valid edges (i.e. prune those not belonging to MAT)
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
#include "Polygon.hpp"
|
||||
#include "Polyline.hpp"
|
||||
|
||||
// Serialization through the Cereal library
|
||||
#include <cereal/access.hpp>
|
||||
|
||||
#include "boost/polygon/voronoi.hpp"
|
||||
using boost::polygon::voronoi_builder;
|
||||
using boost::polygon::voronoi_diagram;
|
||||
|
@ -263,6 +266,17 @@ public:
|
|||
// as possible in least squares norm in regard to the 8 corners of bbox.
|
||||
// Bounding box is expected to be centered around zero in all axes.
|
||||
static Transformation volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox);
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive & ar) { ar(m_offset, m_rotation, m_scaling_factor, m_mirror); }
|
||||
explicit Transformation(int) : m_dirty(true) {}
|
||||
template <class Archive> static void load_and_construct(Archive &ar, cereal::construct<Transformation> &construct)
|
||||
{
|
||||
// Calling a private constructor with special "int" parameter to indicate that no construction is necessary.
|
||||
construct(1);
|
||||
ar(construct.ptr()->m_offset, construct.ptr()->m_rotation, construct.ptr()->m_scaling_factor, construct.ptr()->m_mirror);
|
||||
}
|
||||
};
|
||||
|
||||
// Rotation when going from the first coordinate system with rotation rot_xyz_from applied
|
||||
|
|
|
@ -128,7 +128,7 @@ void Layer::make_perimeters()
|
|||
&& config.external_perimeter_speed == other_config.external_perimeter_speed
|
||||
&& config.gap_fill_speed == other_config.gap_fill_speed
|
||||
&& config.overhangs == other_config.overhangs
|
||||
&& config.serialize("perimeter_extrusion_width").compare(other_config.serialize("perimeter_extrusion_width")) == 0
|
||||
&& config.opt_serialize("perimeter_extrusion_width") == other_config.opt_serialize("perimeter_extrusion_width")
|
||||
&& config.thin_walls == other_config.thin_walls
|
||||
&& config.external_perimeters_first == other_config.external_perimeters_first) {
|
||||
layerms.push_back(other_layerm);
|
||||
|
|
|
@ -201,7 +201,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer)
|
|||
size_t n_groups = 0;
|
||||
for (size_t i = 0; i < bridges.size(); ++ i) {
|
||||
// A grup id for this bridge.
|
||||
size_t group_id = (bridge_group[i] == -1) ? (n_groups ++) : bridge_group[i];
|
||||
size_t group_id = (bridge_group[i] == size_t(-1)) ? (n_groups ++) : bridge_group[i];
|
||||
bridge_group[i] = group_id;
|
||||
// For all possibly overlaping bridges:
|
||||
for (size_t j = i + 1; j < bridges.size(); ++ j) {
|
||||
|
@ -210,7 +210,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer)
|
|||
if (intersection(bridges_grown[i], bridges_grown[j], false).empty())
|
||||
continue;
|
||||
// The two bridge regions intersect. Give them the same group id.
|
||||
if (bridge_group[j] != -1) {
|
||||
if (bridge_group[j] != size_t(-1)) {
|
||||
// The j'th bridge has been merged with some other bridge before.
|
||||
size_t group_id_new = bridge_group[j];
|
||||
for (size_t k = 0; k < j; ++ k)
|
||||
|
|
|
@ -22,7 +22,6 @@ Linef3 transform(const Linef3& line, const Transform3d& t)
|
|||
bool Line::intersection_infinite(const Line &other, Point* point) const
|
||||
{
|
||||
Vec2d a1 = this->a.cast<double>();
|
||||
Vec2d a2 = other.a.cast<double>();
|
||||
Vec2d v12 = (other.a - this->a).cast<double>();
|
||||
Vec2d v1 = (this->b - this->a).cast<double>();
|
||||
Vec2d v2 = (other.b - other.a).cast<double>();
|
||||
|
|
|
@ -22,21 +22,6 @@ namespace Slic3r {
|
|||
|
||||
unsigned int Model::s_auto_extruder_id = 1;
|
||||
|
||||
size_t ModelBase::s_last_id = 0;
|
||||
|
||||
// Unique object / instance ID for the wipe tower.
|
||||
ModelID wipe_tower_object_id()
|
||||
{
|
||||
static ModelBase mine;
|
||||
return mine.id();
|
||||
}
|
||||
|
||||
ModelID wipe_tower_instance_id()
|
||||
{
|
||||
static ModelBase mine;
|
||||
return mine.id();
|
||||
}
|
||||
|
||||
Model& Model::assign_copy(const Model &rhs)
|
||||
{
|
||||
this->copy_id(rhs);
|
||||
|
@ -87,6 +72,19 @@ void Model::assign_new_unique_ids_recursive()
|
|||
model_object->assign_new_unique_ids_recursive();
|
||||
}
|
||||
|
||||
void Model::update_links_bottom_up_recursive()
|
||||
{
|
||||
for (std::pair<const t_model_material_id, ModelMaterial*> &kvp : this->materials)
|
||||
kvp.second->set_model(this);
|
||||
for (ModelObject *model_object : this->objects) {
|
||||
model_object->set_model(this);
|
||||
for (ModelInstance *model_instance : model_object->instances)
|
||||
model_instance->set_model_object(model_object);
|
||||
for (ModelVolume *model_volume : model_object->volumes)
|
||||
model_volume->set_model_object(model_object);
|
||||
}
|
||||
}
|
||||
|
||||
Model Model::read_from_file(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances)
|
||||
{
|
||||
Model model;
|
||||
|
@ -221,7 +219,7 @@ bool Model::delete_object(ModelObject* object)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Model::delete_object(ModelID id)
|
||||
bool Model::delete_object(ObjectID id)
|
||||
{
|
||||
if (id.id != 0) {
|
||||
size_t idx = 0;
|
||||
|
@ -622,11 +620,15 @@ ModelObject::~ModelObject()
|
|||
// maintains the m_model pointer
|
||||
ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
|
||||
{
|
||||
assert(this->id().invalid() || this->id() == rhs.id());
|
||||
assert(this->config.id().invalid() || this->config.id() == rhs.config.id());
|
||||
this->copy_id(rhs);
|
||||
|
||||
this->name = rhs.name;
|
||||
this->input_file = rhs.input_file;
|
||||
// Copies the config's ID
|
||||
this->config = rhs.config;
|
||||
assert(this->config.id() == rhs.config.id());
|
||||
this->sla_support_points = rhs.sla_support_points;
|
||||
this->sla_points_status = rhs.sla_points_status;
|
||||
this->layer_config_ranges = rhs.layer_config_ranges; // #ys_FIXME_experiment
|
||||
|
@ -658,11 +660,14 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
|
|||
// maintains the m_model pointer
|
||||
ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
|
||||
{
|
||||
assert(this->id().invalid());
|
||||
this->copy_id(rhs);
|
||||
|
||||
this->name = std::move(rhs.name);
|
||||
this->input_file = std::move(rhs.input_file);
|
||||
// Moves the config's ID
|
||||
this->config = std::move(rhs.config);
|
||||
assert(this->config.id() == rhs.config.id());
|
||||
this->sla_support_points = std::move(rhs.sla_support_points);
|
||||
this->sla_points_status = std::move(rhs.sla_points_status);
|
||||
this->layer_config_ranges = std::move(rhs.layer_config_ranges); // #ys_FIXME_experiment
|
||||
|
@ -1070,11 +1075,11 @@ void ModelObject::mirror(Axis axis)
|
|||
}
|
||||
|
||||
// This method could only be called before the meshes of this ModelVolumes are not shared!
|
||||
void ModelObject::scale_mesh(const Vec3d &versor)
|
||||
void ModelObject::scale_mesh_after_creation(const Vec3d &versor)
|
||||
{
|
||||
for (ModelVolume *v : this->volumes)
|
||||
{
|
||||
v->scale_geometry(versor);
|
||||
v->scale_geometry_after_creation(versor);
|
||||
v->set_offset(versor.cwiseProduct(v->get_offset()));
|
||||
}
|
||||
this->invalidate_bounding_box();
|
||||
|
@ -1191,13 +1196,19 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
|||
if (keep_upper && upper_mesh.facets_count() > 0) {
|
||||
ModelVolume* vol = upper->add_volume(upper_mesh);
|
||||
vol->name = volume->name;
|
||||
vol->config = volume->config;
|
||||
// Don't copy the config's ID.
|
||||
static_cast<DynamicPrintConfig&>(vol->config) = static_cast<const DynamicPrintConfig&>(volume->config);
|
||||
assert(vol->config.id().valid());
|
||||
assert(vol->config.id() != volume->config.id());
|
||||
vol->set_material(volume->material_id(), *volume->material());
|
||||
}
|
||||
if (keep_lower && lower_mesh.facets_count() > 0) {
|
||||
ModelVolume* vol = lower->add_volume(lower_mesh);
|
||||
vol->name = volume->name;
|
||||
vol->config = volume->config;
|
||||
// Don't copy the config's ID.
|
||||
static_cast<DynamicPrintConfig&>(vol->config) = static_cast<const DynamicPrintConfig&>(volume->config);
|
||||
assert(vol->config.id().valid());
|
||||
assert(vol->config.id() != volume->config.id());
|
||||
vol->set_material(volume->material_id(), *volume->material());
|
||||
|
||||
// Compute the lower part instances' bounding boxes to figure out where to place
|
||||
|
@ -1272,7 +1283,10 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
|||
// XXX: this seems to be the only real usage of m_model, maybe refactor this so that it's not needed?
|
||||
ModelObject* new_object = m_model->add_object();
|
||||
new_object->name = this->name;
|
||||
new_object->config = this->config;
|
||||
// Don't copy the config's ID.
|
||||
static_cast<DynamicPrintConfig&>(new_object->config) = static_cast<const DynamicPrintConfig&>(this->config);
|
||||
assert(new_object->config.id().valid());
|
||||
assert(new_object->config.id() != this->config.id());
|
||||
new_object->instances.reserve(this->instances.size());
|
||||
for (const ModelInstance *model_instance : this->instances)
|
||||
new_object->add_instance(*model_instance);
|
||||
|
@ -1565,9 +1579,9 @@ void ModelVolume::center_geometry_after_creation()
|
|||
if (!shift.isApprox(Vec3d::Zero()))
|
||||
{
|
||||
if (m_mesh)
|
||||
m_mesh->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
|
||||
const_cast<TriangleMesh*>(m_mesh.get())->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
|
||||
if (m_convex_hull)
|
||||
m_convex_hull->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
|
||||
const_cast<TriangleMesh*>(m_convex_hull.get())->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
|
||||
translate(shift);
|
||||
}
|
||||
}
|
||||
|
@ -1720,10 +1734,10 @@ void ModelVolume::mirror(Axis axis)
|
|||
}
|
||||
|
||||
// This method could only be called before the meshes of this ModelVolumes are not shared!
|
||||
void ModelVolume::scale_geometry(const Vec3d& versor)
|
||||
void ModelVolume::scale_geometry_after_creation(const Vec3d& versor)
|
||||
{
|
||||
m_mesh->scale(versor);
|
||||
m_convex_hull->scale(versor);
|
||||
const_cast<TriangleMesh*>(m_mesh.get())->scale(versor);
|
||||
const_cast<TriangleMesh*>(m_convex_hull.get())->scale(versor);
|
||||
}
|
||||
|
||||
void ModelVolume::transform_this_mesh(const Transform3d &mesh_trafo, bool fix_left_handed)
|
||||
|
@ -1867,21 +1881,26 @@ bool model_volume_list_changed(const ModelObject &model_object_old, const ModelO
|
|||
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
|
||||
void check_model_ids_validity(const Model &model)
|
||||
{
|
||||
std::set<ModelID> ids;
|
||||
auto check = [&ids](ModelID id) {
|
||||
assert(id.id > 0);
|
||||
std::set<ObjectID> ids;
|
||||
auto check = [&ids](ObjectID id) {
|
||||
assert(id.valid());
|
||||
assert(ids.find(id) == ids.end());
|
||||
ids.insert(id);
|
||||
};
|
||||
for (const ModelObject *model_object : model.objects) {
|
||||
check(model_object->id());
|
||||
for (const ModelVolume *model_volume : model_object->volumes)
|
||||
check(model_object->config.id());
|
||||
for (const ModelVolume *model_volume : model_object->volumes) {
|
||||
check(model_volume->id());
|
||||
check(model_volume->config.id());
|
||||
}
|
||||
for (const ModelInstance *model_instance : model_object->instances)
|
||||
check(model_instance->id());
|
||||
}
|
||||
for (const auto mm : model.materials)
|
||||
for (const auto mm : model.materials) {
|
||||
check(mm.second->id());
|
||||
check(mm.second->config.id());
|
||||
}
|
||||
}
|
||||
|
||||
void check_model_ids_equal(const Model &model1, const Model &model2)
|
||||
|
@ -1892,10 +1911,13 @@ void check_model_ids_equal(const Model &model1, const Model &model2)
|
|||
const ModelObject &model_object1 = *model1.objects[idx_model];
|
||||
const ModelObject &model_object2 = * model2.objects[idx_model];
|
||||
assert(model_object1.id() == model_object2.id());
|
||||
assert(model_object1.config.id() == model_object2.config.id());
|
||||
assert(model_object1.volumes.size() == model_object2.volumes.size());
|
||||
assert(model_object1.instances.size() == model_object2.instances.size());
|
||||
for (size_t i = 0; i < model_object1.volumes.size(); ++ i)
|
||||
for (size_t i = 0; i < model_object1.volumes.size(); ++ i) {
|
||||
assert(model_object1.volumes[i]->id() == model_object2.volumes[i]->id());
|
||||
assert(model_object1.volumes[i]->config.id() == model_object2.volumes[i]->config.id());
|
||||
}
|
||||
for (size_t i = 0; i < model_object1.instances.size(); ++ i)
|
||||
assert(model_object1.instances[i]->id() == model_object2.instances[i]->id());
|
||||
}
|
||||
|
@ -1906,9 +1928,22 @@ void check_model_ids_equal(const Model &model1, const Model &model2)
|
|||
for (; it1 != model1.materials.end(); ++ it1, ++ it2) {
|
||||
assert(it1->first == it2->first); // compare keys
|
||||
assert(it1->second->id() == it2->second->id());
|
||||
assert(it1->second->config.id() == it2->second->config.id());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* NDEBUG */
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ModelObject)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ModelVolume)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::ModelInstance)
|
||||
CEREAL_REGISTER_TYPE(Slic3r::Model)
|
||||
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ObjectBase, Slic3r::ModelObject)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ObjectBase, Slic3r::ModelVolume)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ObjectBase, Slic3r::ModelInstance)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ObjectBase, Slic3r::Model)
|
||||
#endif
|
|
@ -2,19 +2,20 @@
|
|||
#define slic3r_Model_hpp_
|
||||
|
||||
#include "libslic3r.h"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "Layer.hpp"
|
||||
#include "ObjectID.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "TriangleMesh.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "Slicing.hpp"
|
||||
#include "SLA/SLACommon.hpp"
|
||||
#include "TriangleMesh.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "Geometry.hpp"
|
||||
#include <libslic3r/SLA/SLACommon.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -26,6 +27,38 @@ class ModelVolume;
|
|||
class Print;
|
||||
class SLAPrint;
|
||||
|
||||
namespace UndoRedo {
|
||||
class StackImpl;
|
||||
}
|
||||
|
||||
class ModelConfig : public ObjectBase, public DynamicPrintConfig
|
||||
{
|
||||
private:
|
||||
friend class cereal::access;
|
||||
friend class UndoRedo::StackImpl;
|
||||
friend class ModelObject;
|
||||
friend class ModelVolume;
|
||||
friend class ModelMaterial;
|
||||
|
||||
// Constructors to be only called by derived classes.
|
||||
// Default constructor to assign a unique ID.
|
||||
explicit ModelConfig() {}
|
||||
// Constructor with ignored int parameter to assign an invalid ID, to be replaced
|
||||
// by an existing ID copied from elsewhere.
|
||||
explicit ModelConfig(int) : ObjectBase(-1) {}
|
||||
// Copy constructor copies the ID.
|
||||
explicit ModelConfig(const ModelConfig &cfg) : ObjectBase(-1), DynamicPrintConfig(cfg) { this->copy_id(cfg); }
|
||||
// Move constructor copies the ID.
|
||||
explicit ModelConfig(ModelConfig &&cfg) : ObjectBase(-1), DynamicPrintConfig(std::move(cfg)) { this->copy_id(cfg); }
|
||||
|
||||
ModelConfig& operator=(const ModelConfig &rhs) = default;
|
||||
ModelConfig& operator=(ModelConfig &&rhs) = default;
|
||||
|
||||
template<class Archive> void serialize(Archive &ar) {
|
||||
ar(cereal::base_class<DynamicPrintConfig>(this));
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::string t_model_material_id;
|
||||
typedef std::string t_model_material_attribute;
|
||||
typedef std::map<t_model_material_attribute, std::string> t_model_material_attributes;
|
||||
|
@ -35,74 +68,13 @@ typedef std::vector<ModelObject*> ModelObjectPtrs;
|
|||
typedef std::vector<ModelVolume*> ModelVolumePtrs;
|
||||
typedef std::vector<ModelInstance*> ModelInstancePtrs;
|
||||
|
||||
// Unique identifier of a Model, ModelObject, ModelVolume, ModelInstance or ModelMaterial.
|
||||
// Used to synchronize the front end (UI) with the back end (BackgroundSlicingProcess / Print / PrintObject)
|
||||
// Valid IDs are strictly positive (non zero).
|
||||
// It is declared as an object, as some compilers (notably msvcc) consider a typedef size_t equivalent to size_t
|
||||
// for parameter overload.
|
||||
struct ModelID
|
||||
{
|
||||
ModelID(size_t id) : id(id) {}
|
||||
|
||||
bool operator==(const ModelID &rhs) const { return this->id == rhs.id; }
|
||||
bool operator!=(const ModelID &rhs) const { return this->id != rhs.id; }
|
||||
bool operator< (const ModelID &rhs) const { return this->id < rhs.id; }
|
||||
bool operator> (const ModelID &rhs) const { return this->id > rhs.id; }
|
||||
bool operator<=(const ModelID &rhs) const { return this->id <= rhs.id; }
|
||||
bool operator>=(const ModelID &rhs) const { return this->id >= rhs.id; }
|
||||
|
||||
bool valid() const { return id != 0; }
|
||||
|
||||
size_t id;
|
||||
};
|
||||
|
||||
// Unique object / instance ID for the wipe tower.
|
||||
extern ModelID wipe_tower_object_id();
|
||||
extern ModelID wipe_tower_instance_id();
|
||||
|
||||
// Base for Model, ModelObject, ModelVolume, ModelInstance or ModelMaterial to provide a unique ID
|
||||
// to synchronize the front end (UI) with the back end (BackgroundSlicingProcess / Print / PrintObject).
|
||||
// Achtung! The s_last_id counter is not thread safe, so it is expected, that the ModelBase derived instances
|
||||
// are only instantiated from the main thread.
|
||||
class ModelBase
|
||||
{
|
||||
public:
|
||||
ModelID id() const { return m_id; }
|
||||
|
||||
protected:
|
||||
// Constructors to be only called by derived classes.
|
||||
// Default constructor to assign a unique ID.
|
||||
ModelBase() : m_id(generate_new_id()) {}
|
||||
// Constructor with ignored int parameter to assign an invalid ID, to be replaced
|
||||
// by an existing ID copied from elsewhere.
|
||||
ModelBase(int) : m_id(ModelID(0)) {}
|
||||
|
||||
// Use with caution!
|
||||
void set_new_unique_id() { m_id = generate_new_id(); }
|
||||
void set_invalid_id() { m_id = 0; }
|
||||
// Use with caution!
|
||||
void copy_id(const ModelBase &rhs) { m_id = rhs.id(); }
|
||||
|
||||
// Override this method if a ModelBase derived class owns other ModelBase derived instances.
|
||||
void assign_new_unique_ids_recursive() { this->set_new_unique_id(); }
|
||||
|
||||
private:
|
||||
ModelID m_id;
|
||||
|
||||
static inline ModelID generate_new_id() { return ModelID(++ s_last_id); }
|
||||
static size_t s_last_id;
|
||||
|
||||
friend ModelID wipe_tower_object_id();
|
||||
friend ModelID wipe_tower_instance_id();
|
||||
};
|
||||
|
||||
#define MODELBASE_DERIVED_COPY_MOVE_CLONE(TYPE) \
|
||||
#define OBJECTBASE_DERIVED_COPY_MOVE_CLONE(TYPE) \
|
||||
/* Copy a model, copy the IDs. The Print::apply() will call the TYPE::copy() method */ \
|
||||
/* to make a private copy for background processing. */ \
|
||||
static TYPE* new_copy(const TYPE &rhs) { return new TYPE(rhs); } \
|
||||
static TYPE* new_copy(TYPE &&rhs) { return new TYPE(std::move(rhs)); } \
|
||||
static TYPE make_copy(const TYPE &rhs) { return TYPE(rhs); } \
|
||||
static TYPE make_copy(TYPE &&rhs) { return TYPE(std::move(rhs)); } \
|
||||
static TYPE* new_copy(const TYPE &rhs) { auto *ret = new TYPE(rhs); assert(ret->id() == rhs.id()); return ret; } \
|
||||
static TYPE* new_copy(TYPE &&rhs) { auto *ret = new TYPE(std::move(rhs)); assert(ret->id() == rhs.id()); return ret; } \
|
||||
static TYPE make_copy(const TYPE &rhs) { TYPE ret(rhs); assert(ret.id() == rhs.id()); return ret; } \
|
||||
static TYPE make_copy(TYPE &&rhs) { TYPE ret(std::move(rhs)); assert(ret.id() == rhs.id()); return ret; } \
|
||||
TYPE& assign_copy(const TYPE &rhs); \
|
||||
TYPE& assign_copy(TYPE &&rhs); \
|
||||
/* Copy a TYPE, generate new IDs. The front end will use this call. */ \
|
||||
|
@ -110,52 +82,62 @@ private:
|
|||
/* Default constructor assigning an invalid ID. */ \
|
||||
auto obj = new TYPE(-1); \
|
||||
obj->assign_clone(rhs); \
|
||||
assert(obj->id().valid() && obj->id() != rhs.id()); \
|
||||
return obj; \
|
||||
} \
|
||||
TYPE make_clone(const TYPE &rhs) { \
|
||||
/* Default constructor assigning an invalid ID. */ \
|
||||
TYPE obj(-1); \
|
||||
obj.assign_clone(rhs); \
|
||||
assert(obj.id().valid() && obj.id() != rhs.id()); \
|
||||
return obj; \
|
||||
} \
|
||||
TYPE& assign_clone(const TYPE &rhs) { \
|
||||
this->assign_copy(rhs); \
|
||||
assert(this->id().valid() && this->id() == rhs.id()); \
|
||||
this->assign_new_unique_ids_recursive(); \
|
||||
assert(this->id().valid() && this->id() != rhs.id()); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
#define MODELBASE_DERIVED_PRIVATE_COPY_MOVE(TYPE) \
|
||||
private: \
|
||||
/* Private constructor with an unused int parameter will create a TYPE instance with an invalid ID. */ \
|
||||
explicit TYPE(int) : ModelBase(-1) {}; \
|
||||
void assign_new_unique_ids_recursive();
|
||||
|
||||
// Material, which may be shared across multiple ModelObjects of a single Model.
|
||||
class ModelMaterial : public ModelBase
|
||||
class ModelMaterial final : public ObjectBase
|
||||
{
|
||||
public:
|
||||
// Attributes are defined by the AMF file format, but they don't seem to be used by Slic3r for any purpose.
|
||||
t_model_material_attributes attributes;
|
||||
// Dynamic configuration storage for the object specific configuration values, overriding the global configuration.
|
||||
DynamicPrintConfig config;
|
||||
ModelConfig config;
|
||||
|
||||
Model* get_model() const { return m_model; }
|
||||
void apply(const t_model_material_attributes &attributes)
|
||||
{ this->attributes.insert(attributes.begin(), attributes.end()); }
|
||||
|
||||
protected:
|
||||
friend class Model;
|
||||
// Constructor, which assigns a new unique ID.
|
||||
ModelMaterial(Model *model) : m_model(model) {}
|
||||
// Copy constructor copies the ID and m_model!
|
||||
ModelMaterial(const ModelMaterial &rhs) = default;
|
||||
void set_model(Model *model) { m_model = model; }
|
||||
|
||||
private:
|
||||
// Parent, owning this material.
|
||||
Model *m_model;
|
||||
|
||||
ModelMaterial() = delete;
|
||||
// To be accessed by the Model.
|
||||
friend class Model;
|
||||
// Constructor, which assigns a new unique ID to the material and to its config.
|
||||
ModelMaterial(Model *model) : m_model(model) { assert(this->id().valid()); }
|
||||
// Copy constructor copies the IDs of the ModelMaterial and its config, and m_model!
|
||||
ModelMaterial(const ModelMaterial &rhs) = default;
|
||||
void set_model(Model *model) { m_model = model; }
|
||||
void set_new_unique_id() { ObjectBase::set_new_unique_id(); this->config.set_new_unique_id(); }
|
||||
|
||||
// To be accessed by the serialization and Undo/Redo code.
|
||||
friend class cereal::access;
|
||||
friend class UndoRedo::StackImpl;
|
||||
// Create an object for deserialization, don't allocate IDs for ModelMaterial and its config.
|
||||
ModelMaterial() : ObjectBase(-1), config(-1), m_model(nullptr) { assert(this->id().invalid()); assert(this->config.id().invalid()); }
|
||||
template<class Archive> void serialize(Archive &ar) {
|
||||
assert(this->id().invalid()); assert(this->config.id().invalid());
|
||||
ar(attributes, config);
|
||||
// assert(this->id().valid()); assert(this->config.id().valid());
|
||||
}
|
||||
|
||||
// Disabled methods.
|
||||
ModelMaterial(ModelMaterial &&rhs) = delete;
|
||||
ModelMaterial& operator=(const ModelMaterial &rhs) = delete;
|
||||
ModelMaterial& operator=(ModelMaterial &&rhs) = delete;
|
||||
|
@ -165,9 +147,8 @@ private:
|
|||
// and possibly having multiple modifier volumes, each modifier volume with its set of parameters and materials.
|
||||
// Each ModelObject may be instantiated mutliple times, each instance having different placement on the print bed,
|
||||
// different rotation and different uniform scaling.
|
||||
class ModelObject : public ModelBase
|
||||
class ModelObject final : public ObjectBase
|
||||
{
|
||||
friend class Model;
|
||||
public:
|
||||
std::string name;
|
||||
std::string input_file; // XXX: consider fs::path
|
||||
|
@ -178,7 +159,7 @@ public:
|
|||
// ModelVolumes are owned by this ModelObject.
|
||||
ModelVolumePtrs volumes;
|
||||
// Configuration parameters specific to a single ModelObject, overriding the global Slic3r settings.
|
||||
DynamicPrintConfig config;
|
||||
ModelConfig config;
|
||||
// Variation of a layer thickness for spans of Z coordinates + optional parameter overrides.
|
||||
t_layer_config_ranges layer_config_ranges;
|
||||
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
|
||||
|
@ -264,7 +245,7 @@ public:
|
|||
void mirror(Axis axis);
|
||||
|
||||
// This method could only be called before the meshes of this ModelVolumes are not shared!
|
||||
void scale_mesh(const Vec3d& versor);
|
||||
void scale_mesh_after_creation(const Vec3d& versor);
|
||||
|
||||
size_t materials_count() const;
|
||||
size_t facets_count() const;
|
||||
|
@ -293,26 +274,48 @@ public:
|
|||
// Get count of errors in the mesh( or all object's meshes, if volume index isn't defined)
|
||||
int get_mesh_errors_count(const int vol_idx = -1) const;
|
||||
|
||||
protected:
|
||||
friend class Print;
|
||||
friend class SLAPrint;
|
||||
// Called by Print::apply() to set the model pointer after making a copy.
|
||||
void set_model(Model *model) { m_model = model; }
|
||||
|
||||
private:
|
||||
ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()),
|
||||
m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) {}
|
||||
friend class Model;
|
||||
// This constructor assigns new ID to this ModelObject and its config.
|
||||
explicit ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()),
|
||||
m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false)
|
||||
{ assert(this->id().valid()); }
|
||||
explicit ModelObject(int) : ObjectBase(-1), config(-1), m_model(nullptr), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false)
|
||||
{ assert(this->id().invalid()); assert(this->config.id().invalid()); }
|
||||
~ModelObject();
|
||||
void assign_new_unique_ids_recursive() override;
|
||||
|
||||
/* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */
|
||||
/* (Omits copy and move(since C++11) constructors, resulting in zero - copy pass - by - value semantics). */
|
||||
ModelObject(const ModelObject &rhs) : ModelBase(-1), m_model(rhs.m_model) { this->assign_copy(rhs); }
|
||||
explicit ModelObject(ModelObject &&rhs) : ModelBase(-1) { this->assign_copy(std::move(rhs)); }
|
||||
ModelObject& operator=(const ModelObject &rhs) { this->assign_copy(rhs); m_model = rhs.m_model; return *this; }
|
||||
ModelObject& operator=(ModelObject &&rhs) { this->assign_copy(std::move(rhs)); m_model = rhs.m_model; return *this; }
|
||||
// To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision"
|
||||
// (Omits copy and move(since C++11) constructors, resulting in zero - copy pass - by - value semantics).
|
||||
ModelObject(const ModelObject &rhs) : ObjectBase(-1), config(-1), m_model(rhs.m_model) {
|
||||
assert(this->id().invalid()); assert(this->config.id().invalid()); assert(rhs.id() != rhs.config.id());
|
||||
this->assign_copy(rhs);
|
||||
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
||||
assert(this->id() == rhs.id()); assert(this->config.id() == rhs.config.id());
|
||||
}
|
||||
explicit ModelObject(ModelObject &&rhs) : ObjectBase(-1), config(-1) {
|
||||
assert(this->id().invalid()); assert(this->config.id().invalid()); assert(rhs.id() != rhs.config.id());
|
||||
this->assign_copy(std::move(rhs));
|
||||
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
||||
assert(this->id() == rhs.id()); assert(this->config.id() == rhs.config.id());
|
||||
}
|
||||
ModelObject& operator=(const ModelObject &rhs) {
|
||||
this->assign_copy(rhs);
|
||||
m_model = rhs.m_model;
|
||||
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
||||
assert(this->id() == rhs.id()); assert(this->config.id() == rhs.config.id());
|
||||
return *this;
|
||||
}
|
||||
ModelObject& operator=(ModelObject &&rhs) {
|
||||
this->assign_copy(std::move(rhs));
|
||||
m_model = rhs.m_model;
|
||||
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
||||
assert(this->id() == rhs.id()); assert(this->config.id() == rhs.config.id());
|
||||
return *this;
|
||||
}
|
||||
void set_new_unique_id() { ObjectBase::set_new_unique_id(); this->config.set_new_unique_id(); }
|
||||
|
||||
MODELBASE_DERIVED_COPY_MOVE_CLONE(ModelObject)
|
||||
MODELBASE_DERIVED_PRIVATE_COPY_MOVE(ModelObject)
|
||||
OBJECTBASE_DERIVED_COPY_MOVE_CLONE(ModelObject)
|
||||
|
||||
// Parent object, owning this ModelObject. Set to nullptr here, so the macros above will have it initialized.
|
||||
Model *m_model = nullptr;
|
||||
|
@ -324,6 +327,24 @@ private:
|
|||
mutable bool m_raw_bounding_box_valid;
|
||||
mutable BoundingBoxf3 m_raw_mesh_bounding_box;
|
||||
mutable bool m_raw_mesh_bounding_box_valid;
|
||||
|
||||
// Called by Print::apply() to set the model pointer after making a copy.
|
||||
friend class Print;
|
||||
friend class SLAPrint;
|
||||
void set_model(Model *model) { m_model = model; }
|
||||
|
||||
// Undo / Redo through the cereal serialization library
|
||||
friend class cereal::access;
|
||||
friend class UndoRedo::StackImpl;
|
||||
// Used for deserialization -> Don't allocate any IDs for the ModelObject or its config.
|
||||
ModelObject() : ObjectBase(-1), config(-1), m_model(nullptr), m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) {
|
||||
assert(this->id().invalid()); assert(this->config.id().invalid());
|
||||
}
|
||||
template<class Archive> void serialize(Archive &ar) {
|
||||
ar(cereal::base_class<ObjectBase>(this));
|
||||
ar(name, input_file, instances, volumes, config, layer_config_ranges, layer_height_profile, sla_support_points, sla_points_status, origin_translation,
|
||||
m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid);
|
||||
}
|
||||
};
|
||||
|
||||
// Declared outside of ModelVolume, so it could be forward declared.
|
||||
|
@ -337,20 +358,20 @@ enum class ModelVolumeType : int {
|
|||
|
||||
// An object STL, or a modifier volume, over which a different set of parameters shall be applied.
|
||||
// ModelVolume instances are owned by a ModelObject.
|
||||
class ModelVolume : public ModelBase
|
||||
class ModelVolume final : public ObjectBase
|
||||
{
|
||||
public:
|
||||
std::string name;
|
||||
// The triangular model.
|
||||
const TriangleMesh& mesh() const { return *m_mesh.get(); }
|
||||
void set_mesh(const TriangleMesh &mesh) { m_mesh = std::make_shared<TriangleMesh>(mesh); }
|
||||
void set_mesh(TriangleMesh &&mesh) { m_mesh = std::make_shared<TriangleMesh>(std::move(mesh)); }
|
||||
void set_mesh(std::shared_ptr<TriangleMesh> &mesh) { m_mesh = mesh; }
|
||||
void set_mesh(std::unique_ptr<TriangleMesh> &&mesh) { m_mesh = std::move(mesh); }
|
||||
void reset_mesh() { m_mesh = std::make_shared<TriangleMesh>(); }
|
||||
void set_mesh(const TriangleMesh &mesh) { m_mesh = std::make_shared<const TriangleMesh>(mesh); }
|
||||
void set_mesh(TriangleMesh &&mesh) { m_mesh = std::make_shared<const TriangleMesh>(std::move(mesh)); }
|
||||
void set_mesh(std::shared_ptr<const TriangleMesh> &mesh) { m_mesh = mesh; }
|
||||
void set_mesh(std::unique_ptr<const TriangleMesh> &&mesh) { m_mesh = std::move(mesh); }
|
||||
void reset_mesh() { m_mesh = std::make_shared<const TriangleMesh>(); }
|
||||
// Configuration parameters specific to an object model geometry or a modifier volume,
|
||||
// overriding the global Slic3r settings and the ModelObject settings.
|
||||
DynamicPrintConfig config;
|
||||
ModelConfig config;
|
||||
|
||||
// A parent object owning this modifier volume.
|
||||
ModelObject* get_object() const { return this->object; };
|
||||
|
@ -385,7 +406,7 @@ public:
|
|||
void mirror(Axis axis);
|
||||
|
||||
// This method could only be called before the meshes of this ModelVolumes are not shared!
|
||||
void scale_geometry(const Vec3d& versor);
|
||||
void scale_geometry_after_creation(const Vec3d& versor);
|
||||
|
||||
// Translates the mesh and the convex hull so that the origin of their vertices is in the center of this volume's bounding box.
|
||||
// Attention! This method may only be called just after ModelVolume creation! It must not be called once the TriangleMesh of this ModelVolume is shared!
|
||||
|
@ -431,15 +452,18 @@ public:
|
|||
|
||||
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); }
|
||||
|
||||
using ModelBase::set_new_unique_id;
|
||||
void set_new_unique_id() { ObjectBase::set_new_unique_id(); this->config.set_new_unique_id(); }
|
||||
|
||||
protected:
|
||||
friend class Print;
|
||||
friend class SLAPrint;
|
||||
friend class Model;
|
||||
friend class ModelObject;
|
||||
|
||||
// Copies IDs of both the ModelVolume and its config.
|
||||
explicit ModelVolume(const ModelVolume &rhs) = default;
|
||||
void set_model_object(ModelObject *model_object) { object = model_object; }
|
||||
void assign_new_unique_ids_recursive() override { ObjectBase::set_new_unique_id(); config.set_new_unique_id(); }
|
||||
void transform_this_mesh(const Transform3d& t, bool fix_left_handed);
|
||||
void transform_this_mesh(const Matrix3d& m, bool fix_left_handed);
|
||||
|
||||
|
@ -447,12 +471,12 @@ private:
|
|||
// Parent object owning this ModelVolume.
|
||||
ModelObject* object;
|
||||
// The triangular model.
|
||||
std::shared_ptr<TriangleMesh> m_mesh;
|
||||
std::shared_ptr<const TriangleMesh> m_mesh;
|
||||
// Is it an object to be printed, or a modifier volume?
|
||||
ModelVolumeType m_type;
|
||||
t_model_material_id m_material_id;
|
||||
// The convex hull of this model's mesh.
|
||||
std::shared_ptr<TriangleMesh> m_convex_hull;
|
||||
std::shared_ptr<const TriangleMesh> m_convex_hull;
|
||||
Geometry::Transformation m_transformation;
|
||||
|
||||
// flag to optimize the checking if the volume is splittable
|
||||
|
@ -463,34 +487,53 @@ private:
|
|||
|
||||
ModelVolume(ModelObject *object, const TriangleMesh &mesh) : m_mesh(new TriangleMesh(mesh)), m_type(ModelVolumeType::MODEL_PART), object(object)
|
||||
{
|
||||
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
||||
if (mesh.stl.stats.number_of_facets > 1)
|
||||
calculate_convex_hull();
|
||||
}
|
||||
ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) :
|
||||
m_mesh(new TriangleMesh(std::move(mesh))), m_convex_hull(new TriangleMesh(std::move(convex_hull))), m_type(ModelVolumeType::MODEL_PART), object(object) {}
|
||||
m_mesh(new TriangleMesh(std::move(mesh))), m_convex_hull(new TriangleMesh(std::move(convex_hull))), m_type(ModelVolumeType::MODEL_PART), object(object) {
|
||||
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
||||
}
|
||||
|
||||
// Copying an existing volume, therefore this volume will get a copy of the ID assigned.
|
||||
ModelVolume(ModelObject *object, const ModelVolume &other) :
|
||||
ModelBase(other), // copy the ID
|
||||
ObjectBase(other),
|
||||
name(other.name), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation)
|
||||
{
|
||||
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
||||
assert(this->id() == other.id() && this->config.id() == other.config.id());
|
||||
this->set_material_id(other.material_id());
|
||||
}
|
||||
// Providing a new mesh, therefore this volume will get a new unique ID assigned.
|
||||
ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) :
|
||||
name(other.name), m_mesh(new TriangleMesh(std::move(mesh))), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation)
|
||||
{
|
||||
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
||||
assert(this->id() != other.id() && this->config.id() == other.config.id());
|
||||
this->set_material_id(other.material_id());
|
||||
this->config.set_new_unique_id();
|
||||
if (mesh.stl.stats.number_of_facets > 1)
|
||||
calculate_convex_hull();
|
||||
assert(this->config.id().valid()); assert(this->config.id() != other.config.id()); assert(this->id() != this->config.id());
|
||||
}
|
||||
|
||||
ModelVolume& operator=(ModelVolume &rhs) = delete;
|
||||
|
||||
friend class cereal::access;
|
||||
friend class UndoRedo::StackImpl;
|
||||
// Used for deserialization, therefore no IDs are allocated.
|
||||
ModelVolume() : ObjectBase(-1), config(-1), object(nullptr) {
|
||||
assert(this->id().invalid()); assert(this->config.id().invalid());
|
||||
}
|
||||
template<class Archive> void serialize(Archive &ar) {
|
||||
ar(name, config, m_mesh, m_type, m_material_id, m_convex_hull, m_transformation, m_is_splittable);
|
||||
}
|
||||
};
|
||||
|
||||
// A single instance of a ModelObject.
|
||||
// Knows the affine transformation of an object.
|
||||
class ModelInstance : public ModelBase
|
||||
class ModelInstance final : public ObjectBase
|
||||
{
|
||||
public:
|
||||
enum EPrintVolumeState : unsigned char
|
||||
|
@ -556,6 +599,7 @@ public:
|
|||
protected:
|
||||
friend class Print;
|
||||
friend class SLAPrint;
|
||||
friend class Model;
|
||||
friend class ModelObject;
|
||||
|
||||
explicit ModelInstance(const ModelInstance &rhs) = default;
|
||||
|
@ -566,15 +610,22 @@ private:
|
|||
ModelObject* object;
|
||||
|
||||
// Constructor, which assigns a new unique ID.
|
||||
explicit ModelInstance(ModelObject *object) : object(object), print_volume_state(PVS_Inside) {}
|
||||
explicit ModelInstance(ModelObject *object) : object(object), print_volume_state(PVS_Inside) { assert(this->id().valid()); }
|
||||
// Constructor, which assigns a new unique ID.
|
||||
explicit ModelInstance(ModelObject *object, const ModelInstance &other) :
|
||||
m_transformation(other.m_transformation), object(object), print_volume_state(PVS_Inside) {}
|
||||
m_transformation(other.m_transformation), object(object), print_volume_state(PVS_Inside) { assert(this->id().valid() && this->id() != other.id()); }
|
||||
|
||||
ModelInstance() = delete;
|
||||
explicit ModelInstance(ModelInstance &&rhs) = delete;
|
||||
ModelInstance& operator=(const ModelInstance &rhs) = delete;
|
||||
ModelInstance& operator=(ModelInstance &&rhs) = delete;
|
||||
|
||||
friend class cereal::access;
|
||||
friend class UndoRedo::StackImpl;
|
||||
// Used for deserialization, therefore no IDs are allocated.
|
||||
ModelInstance() : ObjectBase(-1), object(nullptr) { assert(this->id().invalid()); }
|
||||
template<class Archive> void serialize(Archive &ar) {
|
||||
ar(m_transformation, print_volume_state);
|
||||
}
|
||||
};
|
||||
|
||||
// The print bed content.
|
||||
|
@ -582,7 +633,7 @@ private:
|
|||
// and with multiple modifier meshes.
|
||||
// A model groups multiple objects, each object having possibly multiple instances,
|
||||
// all objects may share mutliple materials.
|
||||
class Model : public ModelBase
|
||||
class Model final : public ObjectBase
|
||||
{
|
||||
static unsigned int s_auto_extruder_id;
|
||||
|
||||
|
@ -594,17 +645,17 @@ public:
|
|||
ModelObjectPtrs objects;
|
||||
|
||||
// Default constructor assigns a new ID to the model.
|
||||
Model() {}
|
||||
Model() { assert(this->id().valid()); }
|
||||
~Model() { this->clear_objects(); this->clear_materials(); }
|
||||
|
||||
// To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision"
|
||||
// (Omits copy and move(since C++11) constructors, resulting in zero - copy pass - by - value semantics).
|
||||
Model(const Model &rhs) : ModelBase(-1) { this->assign_copy(rhs); }
|
||||
explicit Model(Model &&rhs) : ModelBase(-1) { this->assign_copy(std::move(rhs)); }
|
||||
Model& operator=(const Model &rhs) { this->assign_copy(rhs); return *this; }
|
||||
Model& operator=(Model &&rhs) { this->assign_copy(std::move(rhs)); return *this; }
|
||||
/* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */
|
||||
/* (Omits copy and move(since C++11) constructors, resulting in zero - copy pass - by - value semantics). */
|
||||
Model(const Model &rhs) : ObjectBase(-1) { assert(this->id().invalid()); this->assign_copy(rhs); assert(this->id().valid()); assert(this->id() == rhs.id()); }
|
||||
explicit Model(Model &&rhs) : ObjectBase(-1) { assert(this->id().invalid()); this->assign_copy(std::move(rhs)); assert(this->id().valid()); assert(this->id() == rhs.id()); }
|
||||
Model& operator=(const Model &rhs) { this->assign_copy(rhs); assert(this->id().valid()); assert(this->id() == rhs.id()); return *this; }
|
||||
Model& operator=(Model &&rhs) { this->assign_copy(std::move(rhs)); assert(this->id().valid()); assert(this->id() == rhs.id()); return *this; }
|
||||
|
||||
MODELBASE_DERIVED_COPY_MOVE_CLONE(Model)
|
||||
OBJECTBASE_DERIVED_COPY_MOVE_CLONE(Model)
|
||||
|
||||
static Model read_from_file(const std::string &input_file, DynamicPrintConfig *config = nullptr, bool add_default_instances = true);
|
||||
static Model read_from_archive(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances = true);
|
||||
|
@ -615,7 +666,7 @@ public:
|
|||
ModelObject* add_object(const char *name, const char *path, TriangleMesh &&mesh);
|
||||
ModelObject* add_object(const ModelObject &other);
|
||||
void delete_object(size_t idx);
|
||||
bool delete_object(ModelID id);
|
||||
bool delete_object(ObjectID id);
|
||||
bool delete_object(ModelObject* object);
|
||||
void clear_objects();
|
||||
|
||||
|
@ -662,11 +713,19 @@ public:
|
|||
std::string propose_export_file_name_and_path(const std::string &new_extension) const;
|
||||
|
||||
private:
|
||||
MODELBASE_DERIVED_PRIVATE_COPY_MOVE(Model)
|
||||
explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); };
|
||||
void assign_new_unique_ids_recursive();
|
||||
void update_links_bottom_up_recursive();
|
||||
|
||||
friend class cereal::access;
|
||||
friend class UndoRedo::StackImpl;
|
||||
template<class Archive> void serialize(Archive &ar) {
|
||||
ar(materials, objects);
|
||||
}
|
||||
};
|
||||
|
||||
#undef MODELBASE_DERIVED_COPY_MOVE_CLONE
|
||||
#undef MODELBASE_DERIVED_PRIVATE_COPY_MOVE
|
||||
#undef OBJECTBASE_DERIVED_COPY_MOVE_CLONE
|
||||
#undef OBJECTBASE_DERIVED_PRIVATE_COPY_MOVE
|
||||
|
||||
// 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.
|
||||
|
@ -686,6 +745,6 @@ void check_model_ids_validity(const Model &model);
|
|||
void check_model_ids_equal(const Model &model1, const Model &model2);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
}
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif
|
||||
#endif /* slic3r_Model_hpp_ */
|
||||
|
|
|
@ -332,7 +332,7 @@ Polyline MotionPlannerGraph::shortest_path(size_t node_start, size_t node_end) c
|
|||
queue.pop();
|
||||
map_node_to_queue_id[u] = size_t(-1);
|
||||
// Stop searching if we reached our destination.
|
||||
if (u == node_end)
|
||||
if (size_t(u) == node_end)
|
||||
break;
|
||||
// Visit each edge starting at node u.
|
||||
for (const Neighbor& neighbor : m_adjacency_list[u])
|
||||
|
|
22
src/libslic3r/ObjectID.cpp
Normal file
22
src/libslic3r/ObjectID.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include "ObjectID.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
size_t ObjectBase::s_last_id = 0;
|
||||
|
||||
// Unique object / instance ID for the wipe tower.
|
||||
ObjectID wipe_tower_object_id()
|
||||
{
|
||||
static ObjectBase mine;
|
||||
return mine.id();
|
||||
}
|
||||
|
||||
ObjectID wipe_tower_instance_id()
|
||||
{
|
||||
static ObjectBase mine;
|
||||
return mine.id();
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
// CEREAL_REGISTER_TYPE(Slic3r::ObjectBase)
|
93
src/libslic3r/ObjectID.hpp
Normal file
93
src/libslic3r/ObjectID.hpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
#ifndef slic3r_ObjectID_hpp_
|
||||
#define slic3r_ObjectID_hpp_
|
||||
|
||||
#include <cereal/access.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace UndoRedo {
|
||||
class StackImpl;
|
||||
};
|
||||
|
||||
// Unique identifier of a mutable object accross the application.
|
||||
// Used to synchronize the front end (UI) with the back end (BackgroundSlicingProcess / Print / PrintObject)
|
||||
// (for Model, ModelObject, ModelVolume, ModelInstance or ModelMaterial classes)
|
||||
// and to serialize / deserialize an object onto the Undo / Redo stack.
|
||||
// Valid IDs are strictly positive (non zero).
|
||||
// It is declared as an object, as some compilers (notably msvcc) consider a typedef size_t equivalent to size_t
|
||||
// for parameter overload.
|
||||
class ObjectID
|
||||
{
|
||||
public:
|
||||
ObjectID(size_t id) : id(id) {}
|
||||
// Default constructor constructs an invalid ObjectID.
|
||||
ObjectID() : id(0) {}
|
||||
|
||||
bool operator==(const ObjectID &rhs) const { return this->id == rhs.id; }
|
||||
bool operator!=(const ObjectID &rhs) const { return this->id != rhs.id; }
|
||||
bool operator< (const ObjectID &rhs) const { return this->id < rhs.id; }
|
||||
bool operator> (const ObjectID &rhs) const { return this->id > rhs.id; }
|
||||
bool operator<=(const ObjectID &rhs) const { return this->id <= rhs.id; }
|
||||
bool operator>=(const ObjectID &rhs) const { return this->id >= rhs.id; }
|
||||
|
||||
bool valid() const { return id != 0; }
|
||||
bool invalid() const { return id == 0; }
|
||||
|
||||
size_t id;
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(id); }
|
||||
};
|
||||
|
||||
// Base for Model, ModelObject, ModelVolume, ModelInstance or ModelMaterial to provide a unique ID
|
||||
// to synchronize the front end (UI) with the back end (BackgroundSlicingProcess / Print / PrintObject).
|
||||
// Achtung! The s_last_id counter is not thread safe, so it is expected, that the ObjectBase derived instances
|
||||
// are only instantiated from the main thread.
|
||||
class ObjectBase
|
||||
{
|
||||
public:
|
||||
ObjectID id() const { return m_id; }
|
||||
|
||||
protected:
|
||||
// Constructors to be only called by derived classes.
|
||||
// Default constructor to assign a unique ID.
|
||||
ObjectBase() : m_id(generate_new_id()) {}
|
||||
// Constructor with ignored int parameter to assign an invalid ID, to be replaced
|
||||
// by an existing ID copied from elsewhere.
|
||||
ObjectBase(int) : m_id(ObjectID(0)) {}
|
||||
// The class tree will have virtual tables and type information.
|
||||
virtual ~ObjectBase() {}
|
||||
|
||||
// Use with caution!
|
||||
void set_new_unique_id() { m_id = generate_new_id(); }
|
||||
void set_invalid_id() { m_id = 0; }
|
||||
// Use with caution!
|
||||
void copy_id(const ObjectBase &rhs) { m_id = rhs.id(); }
|
||||
|
||||
// Override this method if a ObjectBase derived class owns other ObjectBase derived instances.
|
||||
virtual void assign_new_unique_ids_recursive() { this->set_new_unique_id(); }
|
||||
|
||||
private:
|
||||
ObjectID m_id;
|
||||
|
||||
static inline ObjectID generate_new_id() { return ObjectID(++ s_last_id); }
|
||||
static size_t s_last_id;
|
||||
|
||||
friend ObjectID wipe_tower_object_id();
|
||||
friend ObjectID wipe_tower_instance_id();
|
||||
|
||||
friend class cereal::access;
|
||||
friend class Slic3r::UndoRedo::StackImpl;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(m_id); }
|
||||
ObjectBase(const ObjectID id) : m_id(id) {}
|
||||
template<class Archive> static void load_and_construct(Archive & ar, cereal::construct<ObjectBase> &construct) { ObjectID id; ar(id); construct(id); }
|
||||
};
|
||||
|
||||
// Unique object / instance ID for the wipe tower.
|
||||
extern ObjectID wipe_tower_object_id();
|
||||
extern ObjectID wipe_tower_instance_id();
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_ObjectID_hpp_ */
|
|
@ -175,7 +175,7 @@ void PerimeterGenerator::process()
|
|||
const PerimeterGeneratorLoop &loop = contours_d[i];
|
||||
// find the contour loop that contains it
|
||||
for (int t = d - 1; t >= 0; -- t) {
|
||||
for (int j = 0; j < contours[t].size(); ++ j) {
|
||||
for (size_t j = 0; j < contours[t].size(); ++ j) {
|
||||
PerimeterGeneratorLoop &candidate_parent = contours[t][j];
|
||||
if (candidate_parent.polygon.contains(loop.polygon.first_point())) {
|
||||
candidate_parent.children.push_back(loop);
|
||||
|
@ -397,7 +397,7 @@ static inline ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyli
|
|||
pp.push_back(line.b);
|
||||
width.push_back(line.b_width);
|
||||
|
||||
assert(pp.size() == segments + 1);
|
||||
assert(pp.size() == segments + 1u);
|
||||
assert(width.size() == segments*2);
|
||||
}
|
||||
|
||||
|
|
|
@ -521,7 +521,6 @@ namespace client
|
|||
static void regex_op(expr &lhs, boost::iterator_range<Iterator> &rhs, char op)
|
||||
{
|
||||
const std::string *subject = nullptr;
|
||||
const std::string *mask = nullptr;
|
||||
if (lhs.type == TYPE_STRING) {
|
||||
// One type is string, the other could be converted to string.
|
||||
subject = &lhs.s();
|
||||
|
@ -563,7 +562,6 @@ namespace client
|
|||
|
||||
static void ternary_op(expr &lhs, expr &rhs1, expr &rhs2)
|
||||
{
|
||||
bool value = false;
|
||||
if (lhs.type != TYPE_BOOL)
|
||||
lhs.throw_exception("Not a boolean expression");
|
||||
if (lhs.b())
|
||||
|
@ -975,7 +973,7 @@ namespace client
|
|||
// depending on the context->just_boolean_expression flag. This way a single static expression parser
|
||||
// could serve both purposes.
|
||||
start = eps[px::bind(&MyContext::evaluate_full_macro, _r1, _a)] >
|
||||
( eps(_a==true) > text_block(_r1) [_val=_1]
|
||||
( (eps(_a==true) > text_block(_r1) [_val=_1])
|
||||
| conditional_expression(_r1) [ px::bind(&expr<Iterator>::evaluate_boolean_to_string, _1, _val) ]
|
||||
) > eoi;
|
||||
start.name("start");
|
||||
|
@ -1245,7 +1243,7 @@ static std::string process_macro(const std::string &templ, client::MyContext &co
|
|||
std::string::const_iterator end = templ.end();
|
||||
// Accumulator for the processed template.
|
||||
std::string output;
|
||||
bool res = phrase_parse(iter, end, macro_processor_instance(&context), space, output);
|
||||
phrase_parse(iter, end, macro_processor_instance(&context), space, output);
|
||||
if (!context.error_message.empty()) {
|
||||
if (context.error_message.back() != '\n' && context.error_message.back() != '\r')
|
||||
context.error_message += '\n';
|
||||
|
|
|
@ -291,4 +291,21 @@ namespace boost { namespace polygon {
|
|||
} }
|
||||
// end Boost
|
||||
|
||||
// Serialization through the Cereal library
|
||||
namespace cereal {
|
||||
// template<class Archive> void serialize(Archive& archive, Slic3r::Vec2crd &v) { archive(v.x(), v.y()); }
|
||||
// template<class Archive> void serialize(Archive& archive, Slic3r::Vec3crd &v) { archive(v.x(), v.y(), v.z()); }
|
||||
template<class Archive> void serialize(Archive& archive, Slic3r::Vec2i &v) { archive(v.x(), v.y()); }
|
||||
template<class Archive> void serialize(Archive& archive, Slic3r::Vec3i &v) { archive(v.x(), v.y(), v.z()); }
|
||||
// template<class Archive> void serialize(Archive& archive, Slic3r::Vec2i64 &v) { archive(v.x(), v.y()); }
|
||||
// template<class Archive> void serialize(Archive& archive, Slic3r::Vec3i64 &v) { archive(v.x(), v.y(), v.z()); }
|
||||
template<class Archive> void serialize(Archive& archive, Slic3r::Vec2f &v) { archive(v.x(), v.y()); }
|
||||
template<class Archive> void serialize(Archive& archive, Slic3r::Vec3f &v) { archive(v.x(), v.y(), v.z()); }
|
||||
template<class Archive> void serialize(Archive& archive, Slic3r::Vec2d &v) { archive(v.x(), v.y()); }
|
||||
template<class Archive> void serialize(Archive& archive, Slic3r::Vec3d &v) { archive(v.x(), v.y(), v.z()); }
|
||||
|
||||
template<class Archive> void load(Archive& archive, Slic3r::Matrix2f &m) { archive.loadBinary((char*)m.data(), sizeof(float) * 4); }
|
||||
template<class Archive> void save(Archive& archive, Slic3r::Matrix2f &m) { archive.saveBinary((char*)m.data(), sizeof(float) * 4); }
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -61,7 +61,7 @@ Polylines PolylineCollection::_chained_path_from(
|
|||
while (! endpoints.empty()) {
|
||||
// find nearest point
|
||||
int endpoint_index = nearest_point_index<double>(endpoints, start_near, no_reverse);
|
||||
assert(endpoint_index >= 0 && endpoint_index < endpoints.size() * 2);
|
||||
assert(endpoint_index >= 0 && size_t(endpoint_index) < endpoints.size() * 2);
|
||||
if (move_from_src) {
|
||||
retval.push_back(std::move(src[endpoints[endpoint_index/2].idx]));
|
||||
} else {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "I18N.hpp"
|
||||
#include "SupportMaterial.hpp"
|
||||
#include "GCode.hpp"
|
||||
#include "GCode/WipeTowerPrusaMM.hpp"
|
||||
#include "GCode/WipeTower.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
//#include "PrintExport.hpp"
|
||||
|
@ -93,7 +93,6 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||
"filament_density",
|
||||
"filament_notes",
|
||||
"filament_cost",
|
||||
"filament_max_volumetric_speed",
|
||||
"first_layer_acceleration",
|
||||
"first_layer_bed_temperature",
|
||||
"first_layer_speed",
|
||||
|
@ -188,6 +187,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||
|| opt_key == "filament_cooling_initial_speed"
|
||||
|| opt_key == "filament_cooling_final_speed"
|
||||
|| opt_key == "filament_ramming_parameters"
|
||||
|| opt_key == "filament_max_volumetric_speed"
|
||||
|| opt_key == "gcode_flavor"
|
||||
|| opt_key == "high_current_on_filament_swap"
|
||||
|| opt_key == "infill_first"
|
||||
|
@ -392,7 +392,7 @@ static inline void model_volume_list_copy_configs(ModelObject &model_object_dst,
|
|||
assert(mv_src.id() == mv_dst.id());
|
||||
// Copy the ModelVolume data.
|
||||
mv_dst.name = mv_src.name;
|
||||
mv_dst.config = mv_src.config;
|
||||
static_cast<DynamicPrintConfig&>(mv_dst.config) = static_cast<const DynamicPrintConfig&>(mv_src.config);
|
||||
//FIXME what to do with the materials?
|
||||
// mv_dst.m_material_id = mv_src.m_material_id;
|
||||
++ i_src;
|
||||
|
@ -587,8 +587,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||
Moved,
|
||||
Deleted,
|
||||
};
|
||||
ModelObjectStatus(ModelID id, Status status = Unknown) : id(id), status(status) {}
|
||||
ModelID id;
|
||||
ModelObjectStatus(ObjectID id, Status status = Unknown) : id(id), status(status) {}
|
||||
ObjectID id;
|
||||
Status status;
|
||||
LayerRanges layer_ranges;
|
||||
// Search by id.
|
||||
|
@ -695,9 +695,9 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||
print_object(print_object),
|
||||
trafo(print_object->trafo()),
|
||||
status(status) {}
|
||||
PrintObjectStatus(ModelID id) : id(id), print_object(nullptr), trafo(Transform3d::Identity()), status(Unknown) {}
|
||||
PrintObjectStatus(ObjectID id) : id(id), print_object(nullptr), trafo(Transform3d::Identity()), status(Unknown) {}
|
||||
// ID of the ModelObject & PrintObject
|
||||
ModelID id;
|
||||
ObjectID id;
|
||||
// Pointer to the old PrintObject
|
||||
PrintObject *print_object;
|
||||
// Trafo generated with model_object->world_matrix(true)
|
||||
|
@ -757,7 +757,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||
// Synchronize Object's config.
|
||||
bool object_config_changed = model_object.config != model_object_new.config;
|
||||
if (object_config_changed)
|
||||
model_object.config = model_object_new.config;
|
||||
static_cast<DynamicPrintConfig&>(model_object.config) = static_cast<const DynamicPrintConfig&>(model_object_new.config);
|
||||
if (! object_diff.empty() || object_config_changed) {
|
||||
PrintObjectConfig new_config = PrintObject::object_config_from_model_object(m_default_object_config, model_object, num_extruders);
|
||||
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
||||
|
@ -995,7 +995,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||
region_id = regions_in_object[idx_region_in_object ++];
|
||||
// Assign volume to a region.
|
||||
if (fresh) {
|
||||
if (region_id >= print_object.region_volumes.size() || print_object.region_volumes[region_id].empty())
|
||||
if ((size_t)region_id >= print_object.region_volumes.size() || print_object.region_volumes[region_id].empty())
|
||||
++ m_regions[region_id]->m_refcnt;
|
||||
print_object.add_region_volume(region_id, volume_id, it_range->first);
|
||||
}
|
||||
|
@ -1091,18 +1091,16 @@ std::string Print::validate() const
|
|||
return L("The Spiral Vase option can only be used when printing single material objects.");
|
||||
}
|
||||
|
||||
if (m_config.single_extruder_multi_material) {
|
||||
for (size_t i=1; i<m_config.nozzle_diameter.values.size(); ++i)
|
||||
if (m_config.nozzle_diameter.values[i] != m_config.nozzle_diameter.values[i-1])
|
||||
return L("All extruders must have the same diameter for single extruder multimaterial printer.");
|
||||
}
|
||||
|
||||
if (this->has_wipe_tower() && ! m_objects.empty()) {
|
||||
if (m_config.gcode_flavor != gcfRepRap && m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlin)
|
||||
return L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter and Repetier G-code flavors.");
|
||||
if (! m_config.use_relative_e_distances)
|
||||
return L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).");
|
||||
|
||||
for (size_t i=1; i<m_config.nozzle_diameter.values.size(); ++i)
|
||||
if (m_config.nozzle_diameter.values[i] != m_config.nozzle_diameter.values[i-1])
|
||||
return L("All extruders must have the same diameter for the Wipe Tower.");
|
||||
|
||||
if (m_objects.size() > 1) {
|
||||
bool has_custom_layering = false;
|
||||
std::vector<std::vector<coordf_t>> layer_height_profiles;
|
||||
|
@ -1139,11 +1137,10 @@ std::string Print::validate() const
|
|||
if (has_custom_layering) {
|
||||
const std::vector<coordf_t> &layer_height_profile_tallest = layer_height_profiles[tallest_object_idx];
|
||||
for (size_t idx_object = 0; idx_object < m_objects.size(); ++ idx_object) {
|
||||
const PrintObject *object = m_objects[idx_object];
|
||||
const std::vector<coordf_t> &layer_height_profile = layer_height_profiles[idx_object];
|
||||
bool failed = false;
|
||||
if (layer_height_profile_tallest.size() >= layer_height_profile.size()) {
|
||||
int i = 0;
|
||||
size_t i = 0;
|
||||
while (i < layer_height_profile.size() && i < layer_height_profile_tallest.size()) {
|
||||
if (std::abs(layer_height_profile_tallest[i] - layer_height_profile[i])) {
|
||||
failed = true;
|
||||
|
@ -1508,7 +1505,7 @@ void Print::_make_skirt()
|
|||
}
|
||||
|
||||
// Number of skirt loops per skirt layer.
|
||||
int n_skirts = m_config.skirts.value;
|
||||
size_t n_skirts = m_config.skirts.value;
|
||||
if (this->has_infinite_skirt() && n_skirts == 0)
|
||||
n_skirts = 1;
|
||||
|
||||
|
@ -1520,7 +1517,7 @@ void Print::_make_skirt()
|
|||
// Draw outlines from outside to inside.
|
||||
// Loop while we have less skirts than required or any extruder hasn't reached the min length if any.
|
||||
std::vector<coordf_t> extruded_length(extruders.size(), 0.);
|
||||
for (int i = n_skirts, extruder_idx = 0; i > 0; -- i) {
|
||||
for (size_t i = n_skirts, extruder_idx = 0; i > 0; -- i) {
|
||||
this->throw_if_canceled();
|
||||
// Offset the skirt outside.
|
||||
distance += float(scale_(spacing));
|
||||
|
@ -1610,7 +1607,6 @@ void Print::_make_brim()
|
|||
bool Print::has_wipe_tower() const
|
||||
{
|
||||
return
|
||||
m_config.single_extruder_multi_material.value &&
|
||||
! m_config.spiral_vase.value &&
|
||||
m_config.wipe_tower.value &&
|
||||
m_config.nozzle_diameter.values.size() > 1;
|
||||
|
@ -1674,7 +1670,8 @@ void Print::_make_wipe_tower()
|
|||
this->throw_if_canceled();
|
||||
|
||||
// Initialize the wipe tower.
|
||||
WipeTowerPrusaMM wipe_tower(
|
||||
WipeTower wipe_tower(
|
||||
m_config.single_extruder_multi_material.value,
|
||||
float(m_config.wipe_tower_x.value), float(m_config.wipe_tower_y.value),
|
||||
float(m_config.wipe_tower_width.value),
|
||||
float(m_config.wipe_tower_rotation_angle.value), float(m_config.cooling_tube_retraction.value),
|
||||
|
@ -1688,9 +1685,10 @@ void Print::_make_wipe_tower()
|
|||
|
||||
// Set the extruder & material properties at the wipe tower object.
|
||||
for (size_t i = 0; i < number_of_extruders; ++ i)
|
||||
|
||||
wipe_tower.set_extruder(
|
||||
i,
|
||||
WipeTowerPrusaMM::parse_material(m_config.filament_type.get_at(i).c_str()),
|
||||
m_config.filament_type.get_at(i),
|
||||
m_config.temperature.get_at(i),
|
||||
m_config.first_layer_temperature.get_at(i),
|
||||
(float)m_config.filament_loading_speed.get_at(i),
|
||||
|
@ -1702,9 +1700,10 @@ void Print::_make_wipe_tower()
|
|||
(float)m_config.filament_cooling_initial_speed.get_at(i),
|
||||
(float)m_config.filament_cooling_final_speed.get_at(i),
|
||||
m_config.filament_ramming_parameters.get_at(i),
|
||||
(float)m_config.nozzle_diameter.get_at(i));
|
||||
m_config.filament_max_volumetric_speed.get_at(i),
|
||||
m_config.nozzle_diameter.get_at(i));
|
||||
|
||||
m_wipe_tower_data.priming = Slic3r::make_unique<WipeTower::ToolChangeResult>(
|
||||
m_wipe_tower_data.priming = Slic3r::make_unique<std::vector<WipeTower::ToolChangeResult>>(
|
||||
wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false));
|
||||
|
||||
// Lets go through the wipe tower layers and determine pairs of extruder changes for each
|
||||
|
|
|
@ -120,7 +120,7 @@ public:
|
|||
void clear_support_layers();
|
||||
SupportLayer* get_support_layer(int idx) { return m_support_layers[idx]; }
|
||||
SupportLayer* add_support_layer(int id, coordf_t height, coordf_t print_z);
|
||||
SupportLayerPtrs::const_iterator insert_support_layer(SupportLayerPtrs::const_iterator pos, int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
|
||||
SupportLayerPtrs::const_iterator insert_support_layer(SupportLayerPtrs::const_iterator pos, size_t id, coordf_t height, coordf_t print_z, coordf_t slice_z);
|
||||
void delete_support_layer(int idx);
|
||||
|
||||
// Initialize the layer_height_profile from the model_object's layer_height_profile, from model_object's layer height table, or from slicing parameters.
|
||||
|
@ -216,7 +216,7 @@ struct WipeTowerData
|
|||
// Cache it here, so it does not need to be recalculated during the G-code generation.
|
||||
ToolOrdering tool_ordering;
|
||||
// Cache of tool changes per print layer.
|
||||
std::unique_ptr<WipeTower::ToolChangeResult> priming;
|
||||
std::unique_ptr<std::vector<WipeTower::ToolChangeResult>> priming;
|
||||
std::vector<std::vector<WipeTower::ToolChangeResult>> tool_changes;
|
||||
std::unique_ptr<WipeTower::ToolChangeResult> final_purge;
|
||||
std::vector<float> used_filament;
|
||||
|
|
|
@ -246,7 +246,7 @@ public:
|
|||
struct TaskParams {
|
||||
TaskParams() : single_model_object(0), single_model_instance_only(false), to_object_step(-1), to_print_step(-1) {}
|
||||
// If non-empty, limit the processing to this ModelObject.
|
||||
ModelID single_model_object;
|
||||
ObjectID single_model_object;
|
||||
// If set, only process single_model_object. Otherwise process everything, but single_model_object first.
|
||||
bool single_model_instance_only;
|
||||
// If non-negative, stop processing at the successive object step.
|
||||
|
|
|
@ -36,7 +36,6 @@ PrintConfigDef::PrintConfigDef()
|
|||
|
||||
void PrintConfigDef::init_common_params()
|
||||
{
|
||||
t_optiondef_map &Options = this->options;
|
||||
ConfigOptionDef* def;
|
||||
|
||||
def = this->add("printer_technology", coEnum);
|
||||
|
@ -102,7 +101,6 @@ void PrintConfigDef::init_common_params()
|
|||
|
||||
void PrintConfigDef::init_fff_params()
|
||||
{
|
||||
t_optiondef_map &Options = this->options;
|
||||
ConfigOptionDef* def;
|
||||
|
||||
// Maximum extruder temperature, bumped to 1500 to support printing of glass.
|
||||
|
@ -368,7 +366,8 @@ void PrintConfigDef::init_fff_params()
|
|||
|
||||
def = this->add("end_filament_gcode", coStrings);
|
||||
def->label = L("End G-code");
|
||||
def->tooltip = L("This end procedure is inserted at the end of the output file, before the printer end gcode. "
|
||||
def->tooltip = L("This end procedure is inserted at the end of the output file, before the printer end gcode (and "
|
||||
"before any toolchange from this filament in case of multimaterial printers). "
|
||||
"Note that you can use placeholder variables for all Slic3r settings. "
|
||||
"If you have multiple extruders, the gcode is processed in extruder order.");
|
||||
def->multiline = true;
|
||||
|
@ -406,10 +405,13 @@ void PrintConfigDef::init_fff_params()
|
|||
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipRectilinear));
|
||||
|
||||
def = this->add("bottom_fill_pattern", coEnum);
|
||||
*def = *def_top_fill_pattern;
|
||||
def->label = L("Bottom fill pattern");
|
||||
def->category = L("Infill");
|
||||
def->tooltip = L("Fill pattern for bottom infill. This only affects the bottom external visible layer, and not its adjacent solid shells.");
|
||||
def->cli = "bottom-fill-pattern|external-fill-pattern|solid-fill-pattern";
|
||||
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
|
||||
def->enum_values = def_top_fill_pattern->enum_values;
|
||||
def->aliases = def_top_fill_pattern->aliases;
|
||||
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipRectilinear));
|
||||
|
||||
def = this->add("external_perimeter_extrusion_width", coFloatOrPercent);
|
||||
|
@ -1085,16 +1087,16 @@ void PrintConfigDef::init_fff_params()
|
|||
// Add the machine feedrate limits for XYZE axes. (M203)
|
||||
def = this->add("machine_max_feedrate_" + axis.name, coFloats);
|
||||
def->full_label = (boost::format("Maximum feedrate %1%") % axis_upper).str();
|
||||
L("Maximum feedrate X");
|
||||
L("Maximum feedrate Y");
|
||||
L("Maximum feedrate Z");
|
||||
L("Maximum feedrate E");
|
||||
(void)L("Maximum feedrate X");
|
||||
(void)L("Maximum feedrate Y");
|
||||
(void)L("Maximum feedrate Z");
|
||||
(void)L("Maximum feedrate E");
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = (boost::format("Maximum feedrate of the %1% axis") % axis_upper).str();
|
||||
L("Maximum feedrate of the X axis");
|
||||
L("Maximum feedrate of the Y axis");
|
||||
L("Maximum feedrate of the Z axis");
|
||||
L("Maximum feedrate of the E axis");
|
||||
(void)L("Maximum feedrate of the X axis");
|
||||
(void)L("Maximum feedrate of the Y axis");
|
||||
(void)L("Maximum feedrate of the Z axis");
|
||||
(void)L("Maximum feedrate of the E axis");
|
||||
def->sidetext = L("mm/s");
|
||||
def->min = 0;
|
||||
def->width = machine_limits_opt_width;
|
||||
|
@ -1103,16 +1105,16 @@ void PrintConfigDef::init_fff_params()
|
|||
// Add the machine acceleration limits for XYZE axes (M201)
|
||||
def = this->add("machine_max_acceleration_" + axis.name, coFloats);
|
||||
def->full_label = (boost::format("Maximum acceleration %1%") % axis_upper).str();
|
||||
L("Maximum acceleration X");
|
||||
L("Maximum acceleration Y");
|
||||
L("Maximum acceleration Z");
|
||||
L("Maximum acceleration E");
|
||||
(void)L("Maximum acceleration X");
|
||||
(void)L("Maximum acceleration Y");
|
||||
(void)L("Maximum acceleration Z");
|
||||
(void)L("Maximum acceleration E");
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = (boost::format("Maximum acceleration of the %1% axis") % axis_upper).str();
|
||||
L("Maximum acceleration of the X axis");
|
||||
L("Maximum acceleration of the Y axis");
|
||||
L("Maximum acceleration of the Z axis");
|
||||
L("Maximum acceleration of the E axis");
|
||||
(void)L("Maximum acceleration of the X axis");
|
||||
(void)L("Maximum acceleration of the Y axis");
|
||||
(void)L("Maximum acceleration of the Z axis");
|
||||
(void)L("Maximum acceleration of the E axis");
|
||||
def->sidetext = L("mm/s²");
|
||||
def->min = 0;
|
||||
def->width = machine_limits_opt_width;
|
||||
|
@ -1121,16 +1123,16 @@ void PrintConfigDef::init_fff_params()
|
|||
// Add the machine jerk limits for XYZE axes (M205)
|
||||
def = this->add("machine_max_jerk_" + axis.name, coFloats);
|
||||
def->full_label = (boost::format("Maximum jerk %1%") % axis_upper).str();
|
||||
L("Maximum jerk X");
|
||||
L("Maximum jerk Y");
|
||||
L("Maximum jerk Z");
|
||||
L("Maximum jerk E");
|
||||
(void)L("Maximum jerk X");
|
||||
(void)L("Maximum jerk Y");
|
||||
(void)L("Maximum jerk Z");
|
||||
(void)L("Maximum jerk E");
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = (boost::format("Maximum jerk of the %1% axis") % axis_upper).str();
|
||||
L("Maximum jerk of the X axis");
|
||||
L("Maximum jerk of the Y axis");
|
||||
L("Maximum jerk of the Z axis");
|
||||
L("Maximum jerk of the E axis");
|
||||
(void)L("Maximum jerk of the X axis");
|
||||
(void)L("Maximum jerk of the Y axis");
|
||||
(void)L("Maximum jerk of the Z axis");
|
||||
(void)L("Maximum jerk of the E axis");
|
||||
def->sidetext = L("mm/s");
|
||||
def->min = 0;
|
||||
def->width = machine_limits_opt_width;
|
||||
|
@ -1784,7 +1786,8 @@ void PrintConfigDef::init_fff_params()
|
|||
|
||||
def = this->add("start_filament_gcode", coStrings);
|
||||
def->label = L("Start G-code");
|
||||
def->tooltip = L("This start procedure is inserted at the beginning, after any printer start gcode. "
|
||||
def->tooltip = L("This start procedure is inserted at the beginning, after any printer start gcode (and "
|
||||
"after any toolchange to this filament in case of multi-material printers). "
|
||||
"This is used to override settings for a specific filament. If Slic3r detects "
|
||||
"M104, M109, M140 or M190 in your custom codes, such commands will "
|
||||
"not be prepended automatically so you're free to customize the order "
|
||||
|
@ -2039,9 +2042,10 @@ void PrintConfigDef::init_fff_params()
|
|||
|
||||
def = this->add("toolchange_gcode", coString);
|
||||
def->label = L("Tool change G-code");
|
||||
def->tooltip = L("This custom code is inserted right before every extruder change. "
|
||||
"Note that you can use placeholder variables for all Slic3r settings as well "
|
||||
"as [previous_extruder] and [next_extruder].");
|
||||
def->tooltip = L("This custom code is inserted at every extruder change. If you don't leave this empty, you are "
|
||||
"expected to take care of the toolchange yourself - PrusaSlicer will not output any other G-code to "
|
||||
"change the filament. You can use placeholder variables for all Slic3r settings as well as [previous_extruder] "
|
||||
"and [next_extruder], so e.g. the standard toolchange command can be scripted as T[next_extruder].");
|
||||
def->multiline = true;
|
||||
def->full_width = true;
|
||||
def->height = 5;
|
||||
|
@ -2228,7 +2232,6 @@ void PrintConfigDef::init_fff_params()
|
|||
|
||||
void PrintConfigDef::init_sla_params()
|
||||
{
|
||||
t_optiondef_map &Options = this->options;
|
||||
ConfigOptionDef* def;
|
||||
|
||||
// SLA Printer settings
|
||||
|
@ -3250,3 +3253,7 @@ void DynamicPrintAndCLIConfig::handle_legacy(t_config_option_key &opt_key, std::
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
#include <cereal/types/polymorphic.hpp>
|
||||
CEREAL_REGISTER_TYPE(Slic3r::DynamicPrintConfig)
|
||||
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::DynamicConfig, Slic3r::DynamicPrintConfig)
|
||||
|
|
|
@ -1218,6 +1218,8 @@ private:
|
|||
this->options.insert(cli_actions_config_def.options.begin(), cli_actions_config_def.options.end());
|
||||
this->options.insert(cli_transform_config_def.options.begin(), cli_transform_config_def.options.end());
|
||||
this->options.insert(cli_misc_config_def.options.begin(), cli_misc_config_def.options.end());
|
||||
for (const auto &kvp : this->options)
|
||||
this->by_serialization_key_ordinal[kvp.second.serialization_key_ordinal] = &kvp.second;
|
||||
}
|
||||
// Do not release the default values, they are handled by print_config_def & cli_actions_config_def / cli_transform_config_def / cli_misc_config_def.
|
||||
~PrintAndCLIConfigDef() { this->options.clear(); }
|
||||
|
@ -1227,4 +1229,38 @@ private:
|
|||
|
||||
} // namespace Slic3r
|
||||
|
||||
// Serialization through the Cereal library
|
||||
namespace cereal {
|
||||
// Let cereal know that there are load / save non-member functions declared for DynamicPrintConfig, ignore serialize / load / save from parent class DynamicConfig.
|
||||
template <class Archive> struct specialize<Archive, Slic3r::DynamicPrintConfig, cereal::specialization::non_member_load_save> {};
|
||||
|
||||
template<class Archive> void load(Archive& archive, Slic3r::DynamicPrintConfig &config)
|
||||
{
|
||||
size_t cnt;
|
||||
archive(cnt);
|
||||
config.clear();
|
||||
for (size_t i = 0; i < cnt; ++ i) {
|
||||
size_t serialization_key_ordinal;
|
||||
archive(serialization_key_ordinal);
|
||||
assert(serialization_key_ordinal > 0);
|
||||
auto it = Slic3r::print_config_def.by_serialization_key_ordinal.find(serialization_key_ordinal);
|
||||
assert(it != Slic3r::print_config_def.by_serialization_key_ordinal.end());
|
||||
config.set_key_value(it->second->opt_key, it->second->load_option_from_archive(archive));
|
||||
}
|
||||
}
|
||||
|
||||
template<class Archive> void save(Archive& archive, const Slic3r::DynamicPrintConfig &config)
|
||||
{
|
||||
size_t cnt = config.size();
|
||||
archive(cnt);
|
||||
for (auto it = config.cbegin(); it != config.cend(); ++it) {
|
||||
const Slic3r::ConfigOptionDef* optdef = Slic3r::print_config_def.get(it->first);
|
||||
assert(optdef != nullptr);
|
||||
assert(optdef->serialization_key_ordinal > 0);
|
||||
archive(optdef->serialization_key_ordinal);
|
||||
optdef->save_option_to_archive(archive, it->second.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -430,7 +430,7 @@ SupportLayer* PrintObject::add_support_layer(int id, coordf_t height, coordf_t p
|
|||
return m_support_layers.back();
|
||||
}
|
||||
|
||||
SupportLayerPtrs::const_iterator PrintObject::insert_support_layer(SupportLayerPtrs::const_iterator pos, int id, coordf_t height, coordf_t print_z, coordf_t slice_z)
|
||||
SupportLayerPtrs::const_iterator PrintObject::insert_support_layer(SupportLayerPtrs::const_iterator pos, size_t id, coordf_t height, coordf_t print_z, coordf_t slice_z)
|
||||
{
|
||||
return m_support_layers.insert(pos, new SupportLayer(id, this, height, print_z, slice_z));
|
||||
}
|
||||
|
@ -625,7 +625,7 @@ void PrintObject::detect_surfaces_type()
|
|||
// should be visible.
|
||||
bool interface_shells = m_config.interface_shells.value;
|
||||
|
||||
for (int idx_region = 0; idx_region < this->region_volumes.size(); ++ idx_region) {
|
||||
for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++ idx_region) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << idx_region << " in parallel - start";
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
for (Layer *layer : m_layers)
|
||||
|
@ -811,8 +811,6 @@ void PrintObject::process_external_surfaces()
|
|||
BOOST_LOG_TRIVIAL(info) << "Processing external surfaces..." << log_memory_info();
|
||||
|
||||
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++region_id) {
|
||||
const PrintRegion ®ion = *m_print->regions()[region_id];
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Processing external surfaces for region " << region_id << " in parallel - start";
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, m_layers.size()),
|
||||
|
@ -1033,7 +1031,6 @@ void PrintObject::discover_vertical_shells()
|
|||
bool hole_first = true;
|
||||
for (int n = (int)idx_layer - n_extra_bottom_layers; n <= (int)idx_layer + n_extra_top_layers; ++ n)
|
||||
if (n >= 0 && n < (int)m_layers.size()) {
|
||||
Layer &neighbor_layer = *m_layers[n];
|
||||
const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[n];
|
||||
if (hole_first) {
|
||||
hole_first = false;
|
||||
|
@ -2308,7 +2305,7 @@ void PrintObject::discover_horizontal_shells()
|
|||
BOOST_LOG_TRIVIAL(trace) << "discover_horizontal_shells()";
|
||||
|
||||
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
||||
for (int i = 0; i < int(m_layers.size()); ++ i) {
|
||||
for (size_t i = 0; i < m_layers.size(); ++ i) {
|
||||
m_print->throw_if_canceled();
|
||||
LayerRegion *layerm = m_layers[i]->regions()[region_id];
|
||||
const PrintRegionConfig ®ion_config = layerm->region()->config();
|
||||
|
@ -2325,7 +2322,7 @@ void PrintObject::discover_horizontal_shells()
|
|||
if (region_config.ensure_vertical_shell_thickness.value)
|
||||
continue;
|
||||
|
||||
for (int idx_surface_type = 0; idx_surface_type < 3; ++ idx_surface_type) {
|
||||
for (size_t idx_surface_type = 0; idx_surface_type < 3; ++ idx_surface_type) {
|
||||
m_print->throw_if_canceled();
|
||||
SurfaceType type = (idx_surface_type == 0) ? stTop : (idx_surface_type == 1) ? stBottom : stBottomBridge;
|
||||
// Find slices of current type for current layer.
|
||||
|
@ -2354,7 +2351,7 @@ void PrintObject::discover_horizontal_shells()
|
|||
// Slic3r::debugf "Layer %d has %s surfaces\n", $i, ($type == S_TYPE_TOP) ? 'top' : 'bottom';
|
||||
|
||||
size_t solid_layers = (type == stTop) ? region_config.top_solid_layers.value : region_config.bottom_solid_layers.value;
|
||||
for (int n = (type == stTop) ? i-1 : i+1; std::abs(n - i) < solid_layers; (type == stTop) ? -- n : ++ n) {
|
||||
for (int n = (type == stTop) ? i-1 : i+1; std::abs(n - (int)i) < solid_layers; (type == stTop) ? -- n : ++ n) {
|
||||
if (n < 0 || n >= int(m_layers.size()))
|
||||
continue;
|
||||
// Slic3r::debugf " looking for neighbors on layer %d...\n", $n;
|
||||
|
@ -2499,7 +2496,7 @@ void PrintObject::combine_infill()
|
|||
// Work on each region separately.
|
||||
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
||||
const PrintRegion *region = this->print()->regions()[region_id];
|
||||
const int every = region->config().infill_every_layers.value;
|
||||
const size_t every = region->config().infill_every_layers.value;
|
||||
if (every < 2 || region->config().fill_density == 0.)
|
||||
continue;
|
||||
// Limit the number of combined layers to the maximum height allowed by this regions' nozzle.
|
||||
|
|
|
@ -59,8 +59,6 @@ SLAAutoSupports::SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3
|
|||
void SLAAutoSupports::project_onto_mesh(std::vector<sla::SupportPoint>& points) const
|
||||
{
|
||||
// The function makes sure that all the points are really exactly placed on the mesh.
|
||||
igl::Hit hit_up{0, 0, 0.f, 0.f, 0.f};
|
||||
igl::Hit hit_down{0, 0, 0.f, 0.f, 0.f};
|
||||
|
||||
// Use a reasonable granularity to account for the worker thread synchronization cost.
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, points.size(), 64),
|
||||
|
@ -140,7 +138,6 @@ static std::vector<SLAAutoSupports::MyLayer> make_layers(
|
|||
SLAAutoSupports::MyLayer &layer_above = layers[layer_id];
|
||||
SLAAutoSupports::MyLayer &layer_below = layers[layer_id - 1];
|
||||
//FIXME WTF?
|
||||
const float height = (layer_id>2 ? heights[layer_id-3] : heights[0]-(heights[1]-heights[0]));
|
||||
const float layer_height = (layer_id!=0 ? heights[layer_id]-heights[layer_id-1] : heights[0]);
|
||||
const float safe_angle = 5.f * (float(M_PI)/180.f); // smaller number - less supports
|
||||
const float between_layers_offset = float(scale_(layer_height / std::tan(safe_angle)));
|
||||
|
@ -212,7 +209,7 @@ void SLAAutoSupports::process(const std::vector<ExPolygons>& slices, const std::
|
|||
for (Structure &top : layer_top->islands)
|
||||
for (Structure::Link &bottom_link : top.islands_below) {
|
||||
Structure &bottom = *bottom_link.island;
|
||||
float centroids_dist = (bottom.centroid - top.centroid).norm();
|
||||
//float centroids_dist = (bottom.centroid - top.centroid).norm();
|
||||
// Penalization resulting from centroid offset:
|
||||
// bottom.supports_force *= std::min(1.f, 1.f - std::min(1.f, (1600.f * layer_height) * centroids_dist * centroids_dist / bottom.area));
|
||||
float &support_force = support_force_bottom[&bottom - layer_bottom->islands.data()];
|
||||
|
@ -239,7 +236,7 @@ void SLAAutoSupports::process(const std::vector<ExPolygons>& slices, const std::
|
|||
// s.supports_force_inherited /= std::max(1.f, (layer_height / 0.3f) * e_area / s.area);
|
||||
s.supports_force_inherited /= std::max(1.f, 0.17f * (s.overhangs_area) / s.area);
|
||||
|
||||
float force_deficit = s.support_force_deficit(m_config.tear_pressure());
|
||||
//float force_deficit = s.support_force_deficit(m_config.tear_pressure());
|
||||
if (s.islands_below.empty()) { // completely new island - needs support no doubt
|
||||
uniformly_cover({ *s.polygon }, s, point_grid, true);
|
||||
} else if (! s.dangling_areas.empty()) {
|
||||
|
@ -380,7 +377,7 @@ static inline std::vector<Vec2f> poisson_disk_from_samples(const std::vector<Vec
|
|||
{
|
||||
typename Cells::iterator last_cell_id_it;
|
||||
Vec2i last_cell_id(-1, -1);
|
||||
for (int i = 0; i < raw_samples_sorted.size(); ++ i) {
|
||||
for (size_t i = 0; i < raw_samples_sorted.size(); ++ i) {
|
||||
const RawSample &sample = raw_samples_sorted[i];
|
||||
if (sample.cell_id == last_cell_id) {
|
||||
// This sample is in the same cell as the previous, so just increase the count. Cells are
|
||||
|
|
|
@ -43,6 +43,8 @@ struct SupportPoint {
|
|||
|
||||
bool operator==(const SupportPoint& sp) const { return (pos==sp.pos) && head_front_radius==sp.head_front_radius && is_new_island==sp.is_new_island; }
|
||||
bool operator!=(const SupportPoint& sp) const { return !(sp == (*this)); }
|
||||
|
||||
template<class Archive> void serialize(Archive &ar) { ar(pos, head_front_radius, is_new_island); }
|
||||
};
|
||||
|
||||
/// An index-triangle structure for libIGL functions. Also serves as an
|
||||
|
|
|
@ -211,8 +211,8 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
|
|||
Moved,
|
||||
Deleted,
|
||||
};
|
||||
ModelObjectStatus(ModelID id, Status status = Unknown) : id(id), status(status) {}
|
||||
ModelID id;
|
||||
ModelObjectStatus(ObjectID id, Status status = Unknown) : id(id), status(status) {}
|
||||
ObjectID id;
|
||||
Status status;
|
||||
// Search by id.
|
||||
bool operator<(const ModelObjectStatus &rhs) const { return id < rhs.id; }
|
||||
|
@ -315,9 +315,9 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
|
|||
print_object(print_object),
|
||||
trafo(print_object->trafo()),
|
||||
status(status) {}
|
||||
PrintObjectStatus(ModelID id) : id(id), print_object(nullptr), trafo(Transform3d::Identity()), status(Unknown) {}
|
||||
PrintObjectStatus(ObjectID id) : id(id), print_object(nullptr), trafo(Transform3d::Identity()), status(Unknown) {}
|
||||
// ID of the ModelObject & PrintObject
|
||||
ModelID id;
|
||||
ObjectID id;
|
||||
// Pointer to the old PrintObject
|
||||
SLAPrintObject *print_object;
|
||||
// Trafo generated with model_object->world_matrix(true)
|
||||
|
@ -367,7 +367,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
|
|||
// Synchronize Object's config.
|
||||
bool object_config_changed = model_object.config != model_object_new.config;
|
||||
if (object_config_changed)
|
||||
model_object.config = model_object_new.config;
|
||||
static_cast<DynamicPrintConfig&>(model_object.config) = static_cast<const DynamicPrintConfig&>(model_object_new.config);
|
||||
if (! object_diff.empty() || object_config_changed) {
|
||||
SLAPrintObjectConfig new_config = m_default_object_config;
|
||||
normalize_and_apply_config(new_config, model_object.config);
|
||||
|
|
|
@ -54,10 +54,10 @@ public:
|
|||
bool is_left_handed() const { return m_left_handed; }
|
||||
|
||||
struct Instance {
|
||||
Instance(ModelID instance_id, const Point &shift, float rotation) : instance_id(instance_id), shift(shift), rotation(rotation) {}
|
||||
Instance(ObjectID instance_id, const Point &shift, float rotation) : instance_id(instance_id), shift(shift), rotation(rotation) {}
|
||||
bool operator==(const Instance &rhs) const { return this->instance_id == rhs.instance_id && this->shift == rhs.shift && this->rotation == rhs.rotation; }
|
||||
// ID of the corresponding ModelInstance.
|
||||
ModelID instance_id;
|
||||
ObjectID instance_id;
|
||||
// Slic3r::Point objects in scaled G-code coordinates
|
||||
Point shift;
|
||||
// Rotation along the Z axis, in radians.
|
||||
|
|
|
@ -196,7 +196,6 @@ std::vector<coordf_t> layer_height_profile_from_ranges(
|
|||
coordf_t hi = it_range->first.second;
|
||||
coordf_t height = it_range->second;
|
||||
coordf_t last_z = layer_height_profile.empty() ? 0. : layer_height_profile[layer_height_profile.size() - 2];
|
||||
coordf_t last_height = layer_height_profile.empty() ? 0. : layer_height_profile[layer_height_profile.size() - 1];
|
||||
if (lo > last_z + EPSILON) {
|
||||
// Insert a step of normal layer height.
|
||||
layer_height_profile.push_back(last_z);
|
||||
|
@ -212,7 +211,6 @@ std::vector<coordf_t> layer_height_profile_from_ranges(
|
|||
}
|
||||
|
||||
coordf_t last_z = layer_height_profile.empty() ? 0. : layer_height_profile[layer_height_profile.size() - 2];
|
||||
coordf_t last_height = layer_height_profile.empty() ? 0. : layer_height_profile[layer_height_profile.size() - 1];
|
||||
if (last_z < slicing_params.object_print_z_height()) {
|
||||
// Insert a step of normal layer height up to the object top.
|
||||
layer_height_profile.push_back(last_z);
|
||||
|
@ -254,7 +252,6 @@ std::vector<coordf_t> layer_height_profile_adaptive(
|
|||
}
|
||||
coordf_t slice_z = slicing_params.first_object_layer_height;
|
||||
coordf_t height = slicing_params.first_object_layer_height;
|
||||
coordf_t cusp_height = 0.;
|
||||
int current_facet = 0;
|
||||
while ((slice_z - height) <= slicing_params.object_print_z_height()) {
|
||||
height = 999;
|
||||
|
@ -410,7 +407,6 @@ void adjust_layer_height_profile(
|
|||
}
|
||||
// Adjust height by layer_thickness_delta.
|
||||
coordf_t weight = std::abs(zz - z) < 0.5 * band_width ? (0.5 + 0.5 * cos(2. * M_PI * (zz - z) / band_width)) : 0.;
|
||||
coordf_t height_new = height;
|
||||
switch (action) {
|
||||
case LAYER_HEIGHT_EDIT_ACTION_INCREASE:
|
||||
case LAYER_HEIGHT_EDIT_ACTION_DECREASE:
|
||||
|
|
|
@ -175,4 +175,9 @@ extern int generate_layer_height_texture(
|
|||
|
||||
}; // namespace Slic3r
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
template<class Archive> void serialize(Archive& archive, Slic3r::t_layer_height_range &lhr) { archive(lhr.first, lhr.second); }
|
||||
}
|
||||
|
||||
#endif /* slic3r_Slicing_hpp_ */
|
||||
|
|
|
@ -361,17 +361,17 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
|
|||
std::sort(layers_sorted.begin(), layers_sorted.end(), MyLayersPtrCompare());
|
||||
int layer_id = 0;
|
||||
assert(object.support_layers().empty());
|
||||
for (int i = 0; i < int(layers_sorted.size());) {
|
||||
for (size_t i = 0; i < layers_sorted.size();) {
|
||||
// Find the last layer with roughly the same print_z, find the minimum layer height of all.
|
||||
// Due to the floating point inaccuracies, the print_z may not be the same even if in theory they should.
|
||||
int j = i + 1;
|
||||
size_t j = i + 1;
|
||||
coordf_t zmax = layers_sorted[i]->print_z + EPSILON;
|
||||
for (; j < layers_sorted.size() && layers_sorted[j]->print_z <= zmax; ++j) ;
|
||||
// Assign an average print_z to the set of layers with nearly equal print_z.
|
||||
coordf_t zavg = 0.5 * (layers_sorted[i]->print_z + layers_sorted[j - 1]->print_z);
|
||||
coordf_t height_min = layers_sorted[i]->height;
|
||||
bool empty = true;
|
||||
for (int u = i; u < j; ++u) {
|
||||
for (size_t u = i; u < j; ++u) {
|
||||
MyLayer &layer = *layers_sorted[u];
|
||||
if (! layer.polygons.empty())
|
||||
empty = false;
|
||||
|
@ -1042,7 +1042,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
|||
float fw = float(layerm->flow(frExternalPerimeter).scaled_width());
|
||||
no_interface_offset = (no_interface_offset == 0.f) ? fw : std::min(no_interface_offset, fw);
|
||||
float lower_layer_offset =
|
||||
(layer_id < m_object_config->support_material_enforce_layers.value) ?
|
||||
(layer_id < (size_t)m_object_config->support_material_enforce_layers.value) ?
|
||||
// Enforce a full possible support, ignore the overhang angle.
|
||||
0.f :
|
||||
(threshold_rad > 0. ?
|
||||
|
@ -1352,7 +1352,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
|||
{
|
||||
// Find the span of layers, which are to be printed at the first layer height.
|
||||
int j = 0;
|
||||
for (; j < contact_out.size() && contact_out[j]->print_z < m_slicing_params.first_print_layer_height + this->m_support_layer_height_min - EPSILON; ++ j);
|
||||
for (; j < (int)contact_out.size() && contact_out[j]->print_z < m_slicing_params.first_print_layer_height + this->m_support_layer_height_min - EPSILON; ++ j);
|
||||
if (j > 0) {
|
||||
// Merge the contact_out layers (0) to (j - 1) into the contact_out[0].
|
||||
MyLayer &dst = *contact_out.front();
|
||||
|
@ -1377,7 +1377,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
|||
// Find the span of layers closer than m_support_layer_height_min.
|
||||
int j = i + 1;
|
||||
coordf_t zmax = contact_out[i]->print_z + m_support_layer_height_min + EPSILON;
|
||||
for (; j < contact_out.size() && contact_out[j]->print_z < zmax; ++ j) ;
|
||||
for (; j < (int)contact_out.size() && contact_out[j]->print_z < zmax; ++ j) ;
|
||||
if (i + 1 < j) {
|
||||
// Merge the contact_out layers (i + 1) to (j - 1) into the contact_out[i].
|
||||
MyLayer &dst = *contact_out[i];
|
||||
|
@ -1395,7 +1395,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
|||
contact_out[k] = contact_out[i];
|
||||
i = j;
|
||||
}
|
||||
if (k < contact_out.size())
|
||||
if (k < (int)contact_out.size())
|
||||
contact_out.erase(contact_out.begin() + k, contact_out.end());
|
||||
}
|
||||
|
||||
|
@ -2566,11 +2566,11 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const
|
|||
{
|
||||
// make more loops
|
||||
Polygons loop_polygons = loops0;
|
||||
for (size_t i = 1; i < n_contact_loops; ++ i)
|
||||
for (int i = 1; i < n_contact_loops; ++ i)
|
||||
polygons_append(loop_polygons,
|
||||
offset2(
|
||||
loops0,
|
||||
- int(i) * flow.scaled_spacing() - 0.5f * flow.scaled_spacing(),
|
||||
- i * flow.scaled_spacing() - 0.5f * flow.scaled_spacing(),
|
||||
0.5f * flow.scaled_spacing()));
|
||||
// Clip such loops to the side oriented towards the object.
|
||||
// Collect split points, so they will be recognized after the clipping.
|
||||
|
|
|
@ -195,4 +195,24 @@ TriangleMesh make_sphere(double rho, double fa=(2*PI/360));
|
|||
|
||||
}
|
||||
|
||||
// Serialization through the Cereal library
|
||||
#include <cereal/access.hpp>
|
||||
namespace cereal {
|
||||
template <class Archive> struct specialize<Archive, Slic3r::TriangleMesh, cereal::specialization::non_member_load_save> {};
|
||||
template<class Archive> void load(Archive &archive, Slic3r::TriangleMesh &mesh) {
|
||||
stl_file &stl = mesh.stl;
|
||||
stl.stats.type = inmemory;
|
||||
archive(stl.stats.number_of_facets, stl.stats.original_num_facets);
|
||||
stl_allocate(&stl);
|
||||
archive.loadBinary((char*)stl.facet_start.data(), stl.facet_start.size() * 50);
|
||||
stl_get_size(&stl);
|
||||
mesh.repair();
|
||||
}
|
||||
template<class Archive> void save(Archive &archive, const Slic3r::TriangleMesh &mesh) {
|
||||
const stl_file& stl = mesh.stl;
|
||||
archive(stl.stats.number_of_facets, stl.stats.original_num_facets);
|
||||
archive.saveBinary((char*)stl.facet_start.data(), stl.facet_start.size() * 50);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -182,7 +182,7 @@ class ScopeGuard
|
|||
public:
|
||||
typedef std::function<void()> Closure;
|
||||
private:
|
||||
bool committed;
|
||||
// bool committed;
|
||||
Closure closure;
|
||||
|
||||
public:
|
||||
|
|
|
@ -102,6 +102,9 @@
|
|||
#include <Eigen/Dense>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#include <cereal/access.hpp>
|
||||
#include <cereal/types/base_class.hpp>
|
||||
|
||||
#include "BoundingBox.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Config.hpp"
|
||||
|
|
|
@ -414,13 +414,13 @@ std::string format_memsize_MB(size_t n)
|
|||
scale *= 1000;
|
||||
}
|
||||
char buf[8];
|
||||
sprintf(buf, "%d", n);
|
||||
sprintf(buf, "%d", (int)n);
|
||||
out = buf;
|
||||
while (scale != 1) {
|
||||
scale /= 1000;
|
||||
n = n2 / scale;
|
||||
n2 = n2 % scale;
|
||||
sprintf(buf, ",%03d", n);
|
||||
sprintf(buf, ",%03d", (int)n);
|
||||
out += buf;
|
||||
}
|
||||
return out + "MB";
|
||||
|
|
|
@ -148,6 +148,8 @@ set(SLIC3R_GUI_SOURCES
|
|||
Utils/PresetUpdater.hpp
|
||||
Utils/Time.cpp
|
||||
Utils/Time.hpp
|
||||
Utils/UndoRedo.cpp
|
||||
Utils/UndoRedo.hpp
|
||||
Utils/HexFile.cpp
|
||||
Utils/HexFile.hpp
|
||||
)
|
||||
|
@ -161,7 +163,7 @@ endif ()
|
|||
|
||||
add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
|
||||
|
||||
target_link_libraries(libslic3r_gui libslic3r avrdude imgui ${GLEW_LIBRARIES})
|
||||
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui ${GLEW_LIBRARIES})
|
||||
if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY)
|
||||
add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE)
|
||||
endif ()
|
||||
|
|
|
@ -604,6 +604,7 @@ void GLCanvas3D::LayersEditing::accept_changes(GLCanvas3D& canvas)
|
|||
{
|
||||
if (last_object_id >= 0) {
|
||||
if (m_layer_height_profile_modified) {
|
||||
wxGetApp().plater()->take_snapshot(_(L("Layers heights")));
|
||||
const_cast<ModelObject*>(m_model_object)->layer_height_profile = m_layer_height_profile;
|
||||
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
|
@ -1188,6 +1189,8 @@ wxDEFINE_EVENT(EVT_GLCANVAS_TAB, SimpleEvent);
|
|||
wxDEFINE_EVENT(EVT_GLCANVAS_RESETGIZMOS, SimpleEvent);
|
||||
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);
|
||||
|
||||
GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar)
|
||||
: m_canvas(canvas)
|
||||
|
@ -1200,6 +1203,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
|
|||
, m_camera(camera)
|
||||
, m_view_toolbar(view_toolbar)
|
||||
, m_toolbar(GLToolbar::Normal, "Top")
|
||||
, m_gizmos(*this)
|
||||
, m_use_clipping_planes(false)
|
||||
, m_sidebar_field("")
|
||||
, m_keep_dirty(false)
|
||||
|
@ -1316,7 +1320,7 @@ bool GLCanvas3D::init()
|
|||
// if (!m_volumes.empty())
|
||||
// m_volumes.finalize_geometry();
|
||||
|
||||
if (m_gizmos.is_enabled() && !m_gizmos.init(*this))
|
||||
if (m_gizmos.is_enabled() && !m_gizmos.init())
|
||||
std::cout << "Unable to initialize gizmos: please, check that all the required textures are available" << std::endl;
|
||||
|
||||
if (!_init_toolbar())
|
||||
|
@ -1717,7 +1721,7 @@ void GLCanvas3D::deselect_all()
|
|||
m_selection.set_mode(Selection::Instance);
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
m_gizmos.reset_all_states();
|
||||
m_gizmos.update_data(*this);
|
||||
m_gizmos.update_data();
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
|
||||
}
|
||||
|
||||
|
@ -1791,7 +1795,7 @@ std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx)
|
|||
void GLCanvas3D::mirror_selection(Axis axis)
|
||||
{
|
||||
m_selection.mirror(axis);
|
||||
do_mirror();
|
||||
do_mirror("Mirror Object");
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
}
|
||||
|
||||
|
@ -1812,14 +1816,14 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
struct ModelVolumeState {
|
||||
ModelVolumeState(const GLVolume *volume) :
|
||||
model_volume(nullptr), geometry_id(volume->geometry_id), volume_idx(-1) {}
|
||||
ModelVolumeState(const ModelVolume *model_volume, const ModelID &instance_id, const GLVolume::CompositeID &composite_id) :
|
||||
ModelVolumeState(const ModelVolume *model_volume, const ObjectID &instance_id, const GLVolume::CompositeID &composite_id) :
|
||||
model_volume(model_volume), geometry_id(std::make_pair(model_volume->id().id, instance_id.id)), composite_id(composite_id), volume_idx(-1) {}
|
||||
ModelVolumeState(const ModelID &volume_id, const ModelID &instance_id) :
|
||||
ModelVolumeState(const ObjectID &volume_id, const ObjectID &instance_id) :
|
||||
model_volume(nullptr), geometry_id(std::make_pair(volume_id.id, instance_id.id)), volume_idx(-1) {}
|
||||
bool new_geometry() const { return this->volume_idx == size_t(-1); }
|
||||
const ModelVolume *model_volume;
|
||||
// ModelID of ModelVolume + ModelID of ModelInstance
|
||||
// or timestamp of an SLAPrintObjectStep + ModelID of ModelInstance
|
||||
// ObjectID of ModelVolume + ObjectID of ModelInstance
|
||||
// or timestamp of an SLAPrintObjectStep + ObjectID of ModelInstance
|
||||
std::pair<size_t, size_t> geometry_id;
|
||||
GLVolume::CompositeID composite_id;
|
||||
// Volume index in the new GLVolume vector.
|
||||
|
@ -2014,9 +2018,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id);
|
||||
if (it->new_geometry())
|
||||
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
|
||||
else
|
||||
else {
|
||||
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
|
||||
m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx);
|
||||
m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2038,11 +2044,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
// Should the wipe tower be visualized ?
|
||||
unsigned int extruders_count = (unsigned int)dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values.size();
|
||||
|
||||
bool semm = dynamic_cast<const ConfigOptionBool*>(m_config->option("single_extruder_multi_material"))->value;
|
||||
bool wt = dynamic_cast<const ConfigOptionBool*>(m_config->option("wipe_tower"))->value;
|
||||
bool co = dynamic_cast<const ConfigOptionBool*>(m_config->option("complete_objects"))->value;
|
||||
|
||||
if ((extruders_count > 1) && semm && wt && !co)
|
||||
if ((extruders_count > 1) && wt && !co)
|
||||
{
|
||||
// Height of a print (Show at least a slab)
|
||||
double height = std::max(m_model->bounding_box().max(2), 10.0);
|
||||
|
@ -2079,8 +2084,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
m_selection.volumes_changed(map_glvolume_old_to_new);
|
||||
}
|
||||
|
||||
m_gizmos.update_data(*this);
|
||||
m_gizmos.refresh_on_off_state(m_selection);
|
||||
m_gizmos.update_data();
|
||||
m_gizmos.refresh_on_off_state();
|
||||
|
||||
// Update the toolbar
|
||||
if (update_object_list)
|
||||
|
@ -2317,7 +2322,10 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_gizmos.on_char(evt, *this))
|
||||
if ((keyCode == WXK_ESCAPE) && _deactivate_undo_redo_toolbar_items())
|
||||
return;
|
||||
|
||||
if (m_gizmos.on_char(evt))
|
||||
return;
|
||||
|
||||
//#ifdef __APPLE__
|
||||
|
@ -2349,6 +2357,25 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
|||
#endif /* __APPLE__ */
|
||||
post_event(SimpleEvent(EVT_GLTOOLBAR_PASTE));
|
||||
break;
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
case 'y':
|
||||
case 'Y':
|
||||
#else /* __APPLE__ */
|
||||
case WXK_CONTROL_Y:
|
||||
#endif /* __APPLE__ */
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_REDO));
|
||||
break;
|
||||
#ifdef __APPLE__
|
||||
case 'z':
|
||||
case 'Z':
|
||||
#else /* __APPLE__ */
|
||||
case WXK_CONTROL_Z:
|
||||
#endif /* __APPLE__ */
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_UNDO));
|
||||
break;
|
||||
|
||||
#ifdef __APPLE__
|
||||
case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead.
|
||||
#else /* __APPLE__ */
|
||||
|
@ -2369,7 +2396,6 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
|||
#endif /* __APPLE__ */
|
||||
post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE));
|
||||
break;
|
||||
|
||||
case WXK_ESCAPE: { deselect_all(); break; }
|
||||
case '0': { select_view("iso"); break; }
|
||||
case '1': { select_view("top"); break; }
|
||||
|
@ -2426,7 +2452,7 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!m_gizmos.on_key(evt, *this))
|
||||
if (!m_gizmos.on_key(evt))
|
||||
{
|
||||
if (evt.GetEventType() == wxEVT_KEY_UP) {
|
||||
if (m_tab_down && keyCode == WXK_TAB && !evt.HasAnyModifiers()) {
|
||||
|
@ -2536,7 +2562,7 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
|
|||
}
|
||||
|
||||
// Inform gizmos about the event so they have the opportunity to react.
|
||||
if (m_gizmos.on_mouse_wheel(evt, *this))
|
||||
if (m_gizmos.on_mouse_wheel(evt))
|
||||
return;
|
||||
|
||||
// Calculate the zoom delta and apply it to the current zoom factor
|
||||
|
@ -2664,7 +2690,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_gizmos.on_mouse(evt, *this))
|
||||
if (m_gizmos.on_mouse(evt))
|
||||
{
|
||||
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
||||
mouse_up_cleanup();
|
||||
|
@ -2716,12 +2742,17 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
}
|
||||
else if (evt.Leaving())
|
||||
{
|
||||
_deactivate_undo_redo_toolbar_items();
|
||||
|
||||
// to remove hover on objects when the mouse goes out of this canvas
|
||||
m_mouse.position = Vec2d(-1.0, -1.0);
|
||||
m_dirty = true;
|
||||
}
|
||||
else if (evt.LeftDown() || evt.RightDown())
|
||||
else if (evt.LeftDown() || evt.RightDown() || evt.MiddleDown())
|
||||
{
|
||||
if (_deactivate_undo_redo_toolbar_items())
|
||||
return;
|
||||
|
||||
// If user pressed left or right button we first check whether this happened
|
||||
// on a volume or not.
|
||||
m_layers_editing.state = LayersEditing::Unknown;
|
||||
|
@ -2786,9 +2817,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
if (m_selection.is_empty())
|
||||
m_gizmos.reset_all_states();
|
||||
else
|
||||
m_gizmos.refresh_on_off_state(m_selection);
|
||||
m_gizmos.refresh_on_off_state();
|
||||
|
||||
m_gizmos.update_data(*this);
|
||||
m_gizmos.update_data();
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
|
||||
m_dirty = true;
|
||||
}
|
||||
|
@ -2919,9 +2950,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
else if ((m_mouse.drag.move_volume_idx != -1) && m_mouse.dragging)
|
||||
{
|
||||
m_regenerate_volumes = false;
|
||||
do_move();
|
||||
do_move("Move Object");
|
||||
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.
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
||||
}
|
||||
|
@ -2956,9 +2987,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
{
|
||||
// forces the selection of the volume
|
||||
m_selection.add(volume_idx);
|
||||
m_gizmos.refresh_on_off_state(m_selection);
|
||||
m_gizmos.refresh_on_off_state();
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
|
||||
m_gizmos.update_data(*this);
|
||||
m_gizmos.update_data();
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
// forces a frame render to update the view before the context menu is shown
|
||||
render();
|
||||
|
@ -3078,11 +3109,14 @@ void GLCanvas3D::set_tooltip(const std::string& tooltip) const
|
|||
}
|
||||
|
||||
|
||||
void GLCanvas3D::do_move()
|
||||
void GLCanvas3D::do_move(const std::string& snapshot_type)
|
||||
{
|
||||
if (m_model == nullptr)
|
||||
return;
|
||||
|
||||
if (!snapshot_type.empty())
|
||||
wxGetApp().plater()->take_snapshot(_(L(snapshot_type)));
|
||||
|
||||
std::set<std::pair<int, int>> done; // keeps track of modified instances
|
||||
bool object_moved = false;
|
||||
Vec3d wipe_tower_origin = Vec3d::Zero();
|
||||
|
@ -3133,13 +3167,18 @@ void GLCanvas3D::do_move()
|
|||
|
||||
if (wipe_tower_origin != Vec3d::Zero())
|
||||
post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_MOVED, std::move(wipe_tower_origin)));
|
||||
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void GLCanvas3D::do_rotate()
|
||||
void GLCanvas3D::do_rotate(const std::string& snapshot_type)
|
||||
{
|
||||
if (m_model == nullptr)
|
||||
return;
|
||||
|
||||
if (!snapshot_type.empty())
|
||||
wxGetApp().plater()->take_snapshot(_(L(snapshot_type)));
|
||||
|
||||
std::set<std::pair<int, int>> done; // keeps track of modified instances
|
||||
|
||||
Selection::EMode selection_mode = m_selection.get_mode();
|
||||
|
@ -3188,13 +3227,18 @@ void GLCanvas3D::do_rotate()
|
|||
|
||||
if (!done.empty())
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_ROTATED));
|
||||
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void GLCanvas3D::do_scale()
|
||||
void GLCanvas3D::do_scale(const std::string& snapshot_type)
|
||||
{
|
||||
if (m_model == nullptr)
|
||||
return;
|
||||
|
||||
if (!snapshot_type.empty())
|
||||
wxGetApp().plater()->take_snapshot(_(L(snapshot_type)));
|
||||
|
||||
std::set<std::pair<int, int>> done; // keeps track of modified instances
|
||||
|
||||
Selection::EMode selection_mode = m_selection.get_mode();
|
||||
|
@ -3240,18 +3284,27 @@ void GLCanvas3D::do_scale()
|
|||
|
||||
if (!done.empty())
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_ROTATED));
|
||||
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void GLCanvas3D::do_flatten()
|
||||
void GLCanvas3D::do_flatten(const Vec3d& normal, const std::string& snapshot_type)
|
||||
{
|
||||
do_rotate();
|
||||
if (!snapshot_type.empty())
|
||||
wxGetApp().plater()->take_snapshot(_(L(snapshot_type)));
|
||||
|
||||
m_selection.flattening_rotate(normal);
|
||||
do_rotate(""); // avoid taking another snapshot
|
||||
}
|
||||
|
||||
void GLCanvas3D::do_mirror()
|
||||
void GLCanvas3D::do_mirror(const std::string& snapshot_type)
|
||||
{
|
||||
if (m_model == nullptr)
|
||||
return;
|
||||
|
||||
if (!snapshot_type.empty())
|
||||
wxGetApp().plater()->take_snapshot(_(L(snapshot_type)));
|
||||
|
||||
std::set<std::pair<int, int>> done; // keeps track of modified instances
|
||||
|
||||
Selection::EMode selection_mode = m_selection.get_mode();
|
||||
|
@ -3290,6 +3343,8 @@ void GLCanvas3D::do_mirror()
|
|||
}
|
||||
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void GLCanvas3D::set_camera_zoom(double zoom)
|
||||
|
@ -3302,8 +3357,8 @@ void GLCanvas3D::set_camera_zoom(double zoom)
|
|||
void GLCanvas3D::update_gizmos_on_off_state()
|
||||
{
|
||||
set_as_dirty();
|
||||
m_gizmos.update_data(*this);
|
||||
m_gizmos.refresh_on_off_state(get_selection());
|
||||
m_gizmos.update_data();
|
||||
m_gizmos.refresh_on_off_state();
|
||||
}
|
||||
|
||||
void GLCanvas3D::handle_sidebar_focus_event(const std::string& opt_key, bool focus_on)
|
||||
|
@ -3413,6 +3468,40 @@ bool GLCanvas3D::_is_shown_on_screen() const
|
|||
return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false;
|
||||
}
|
||||
|
||||
// Getter for the const char*[]
|
||||
static bool string_getter(const bool is_undo, int idx, const char** out_text)
|
||||
{
|
||||
return wxGetApp().plater()->undo_redo_string_getter(is_undo, idx, out_text);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x)
|
||||
{
|
||||
const wxString& stack_name = _(is_undo ? L("Undo") : L("Redo"));
|
||||
ImGuiWrapper* imgui = wxGetApp().imgui();
|
||||
|
||||
const float x = pos_x * (float)get_camera().get_zoom() + 0.5f * (float)get_canvas_size().get_width();
|
||||
imgui->set_next_window_pos(x, m_toolbar.get_height(), ImGuiCond_Always, 0.5f, 0.0f);
|
||||
imgui->set_next_window_bg_alpha(0.5f);
|
||||
imgui->begin(wxString::Format(_(L("%s Stack")), stack_name),
|
||||
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
int hovered = m_imgui_undo_redo_hovered_pos;
|
||||
int selected = -1;
|
||||
const float em = static_cast<float>(wxGetApp().em_unit());
|
||||
|
||||
if (imgui->undo_redo_list(ImVec2(12 * em, 20 * em), is_undo, &string_getter, hovered, selected))
|
||||
m_imgui_undo_redo_hovered_pos = hovered;
|
||||
else
|
||||
m_imgui_undo_redo_hovered_pos = -1;
|
||||
|
||||
if (selected >= 0)
|
||||
is_undo ? wxGetApp().plater()->undo_to(selected) : wxGetApp().plater()->redo_to(selected);
|
||||
|
||||
imgui->text(wxString::Format(_(L("%s %d Action")), stack_name, hovered + 1));
|
||||
|
||||
imgui->end();
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_init_toolbar()
|
||||
{
|
||||
if (!m_toolbar.is_enabled())
|
||||
|
@ -3445,7 +3534,7 @@ bool GLCanvas3D::_init_toolbar()
|
|||
item.icon_filename = "add.svg";
|
||||
item.tooltip = _utf8(L("Add...")) + " [" + GUI::shortkey_ctrl_prefix() + "I]";
|
||||
item.sprite_id = 0;
|
||||
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ADD)); };
|
||||
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ADD)); };
|
||||
if (!m_toolbar.add_item(item))
|
||||
return false;
|
||||
|
||||
|
@ -3453,8 +3542,8 @@ bool GLCanvas3D::_init_toolbar()
|
|||
item.icon_filename = "remove.svg";
|
||||
item.tooltip = _utf8(L("Delete")) + " [Del]";
|
||||
item.sprite_id = 1;
|
||||
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE)); };
|
||||
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_delete(); };
|
||||
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE)); };
|
||||
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_delete(); };
|
||||
if (!m_toolbar.add_item(item))
|
||||
return false;
|
||||
|
||||
|
@ -3462,8 +3551,8 @@ bool GLCanvas3D::_init_toolbar()
|
|||
item.icon_filename = "delete_all.svg";
|
||||
item.tooltip = _utf8(L("Delete all")) + " [" + GUI::shortkey_ctrl_prefix() + "Del]";
|
||||
item.sprite_id = 2;
|
||||
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); };
|
||||
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_delete_all(); };
|
||||
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); };
|
||||
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_delete_all(); };
|
||||
if (!m_toolbar.add_item(item))
|
||||
return false;
|
||||
|
||||
|
@ -3471,8 +3560,8 @@ bool GLCanvas3D::_init_toolbar()
|
|||
item.icon_filename = "arrange.svg";
|
||||
item.tooltip = _utf8(L("Arrange")) + " [A]";
|
||||
item.sprite_id = 3;
|
||||
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ARRANGE)); };
|
||||
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_arrange(); };
|
||||
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ARRANGE)); };
|
||||
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_arrange(); };
|
||||
if (!m_toolbar.add_item(item))
|
||||
return false;
|
||||
|
||||
|
@ -3483,8 +3572,8 @@ bool GLCanvas3D::_init_toolbar()
|
|||
item.icon_filename = "copy.svg";
|
||||
item.tooltip = _utf8(L("Copy")) + " [" + GUI::shortkey_ctrl_prefix() + "C]";
|
||||
item.sprite_id = 4;
|
||||
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_COPY)); };
|
||||
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_copy_to_clipboard(); };
|
||||
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_COPY)); };
|
||||
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_copy_to_clipboard(); };
|
||||
if (!m_toolbar.add_item(item))
|
||||
return false;
|
||||
|
||||
|
@ -3492,8 +3581,8 @@ bool GLCanvas3D::_init_toolbar()
|
|||
item.icon_filename = "paste.svg";
|
||||
item.tooltip = _utf8(L("Paste")) + " [" + GUI::shortkey_ctrl_prefix() + "V]";
|
||||
item.sprite_id = 5;
|
||||
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_PASTE)); };
|
||||
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_paste_from_clipboard(); };
|
||||
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_PASTE)); };
|
||||
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_paste_from_clipboard(); };
|
||||
if (!m_toolbar.add_item(item))
|
||||
return false;
|
||||
|
||||
|
@ -3504,9 +3593,10 @@ bool GLCanvas3D::_init_toolbar()
|
|||
item.icon_filename = "instance_add.svg";
|
||||
item.tooltip = _utf8(L("Add instance")) + " [+]";
|
||||
item.sprite_id = 6;
|
||||
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_MORE)); };
|
||||
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_MORE)); };
|
||||
item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; };
|
||||
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_increase_instances(); };
|
||||
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_increase_instances(); };
|
||||
|
||||
if (!m_toolbar.add_item(item))
|
||||
return false;
|
||||
|
||||
|
@ -3514,9 +3604,9 @@ bool GLCanvas3D::_init_toolbar()
|
|||
item.icon_filename = "instance_remove.svg";
|
||||
item.tooltip = _utf8(L("Remove instance")) + " [-]";
|
||||
item.sprite_id = 7;
|
||||
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_FEWER)); };
|
||||
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_FEWER)); };
|
||||
item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; };
|
||||
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_decrease_instances(); };
|
||||
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_decrease_instances(); };
|
||||
if (!m_toolbar.add_item(item))
|
||||
return false;
|
||||
|
||||
|
@ -3527,9 +3617,9 @@ bool GLCanvas3D::_init_toolbar()
|
|||
item.icon_filename = "split_objects.svg";
|
||||
item.tooltip = _utf8(L("Split to objects"));
|
||||
item.sprite_id = 8;
|
||||
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_OBJECTS)); };
|
||||
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_OBJECTS)); };
|
||||
item.visibility_callback = GLToolbarItem::Default_Visibility_Callback;
|
||||
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_split_to_objects(); };
|
||||
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_split_to_objects(); };
|
||||
if (!m_toolbar.add_item(item))
|
||||
return false;
|
||||
|
||||
|
@ -3537,9 +3627,9 @@ bool GLCanvas3D::_init_toolbar()
|
|||
item.icon_filename = "split_parts.svg";
|
||||
item.tooltip = _utf8(L("Split to parts"));
|
||||
item.sprite_id = 9;
|
||||
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_VOLUMES)); };
|
||||
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_VOLUMES)); };
|
||||
item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; };
|
||||
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_split_to_volumes(); };
|
||||
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_split_to_volumes(); };
|
||||
if (!m_toolbar.add_item(item))
|
||||
return false;
|
||||
|
||||
|
@ -3550,10 +3640,38 @@ bool GLCanvas3D::_init_toolbar()
|
|||
item.icon_filename = "layers_white.svg";
|
||||
item.tooltip = _utf8(L("Layers editing"));
|
||||
item.sprite_id = 10;
|
||||
item.is_toggable = true;
|
||||
item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); };
|
||||
item.left.toggable = true;
|
||||
item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); };
|
||||
item.visibility_callback = [this]()->bool { return m_process->current_printer_technology() == ptFFF; };
|
||||
item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_layers_editing(); };
|
||||
item.enabling_callback = []()->bool { return wxGetApp().plater()->can_layers_editing(); };
|
||||
if (!m_toolbar.add_item(item))
|
||||
return false;
|
||||
|
||||
if (!m_toolbar.add_separator())
|
||||
return false;
|
||||
|
||||
item.name = "undo";
|
||||
item.icon_filename = "undo_toolbar.svg";
|
||||
item.tooltip = _utf8(L("Undo")) + " [" + GUI::shortkey_ctrl_prefix() + "Z]";
|
||||
item.sprite_id = 11;
|
||||
item.left.toggable = false;
|
||||
item.left.action_callback = [this]() { post_event(SimpleEvent(EVT_GLCANVAS_UNDO)); };
|
||||
item.right.toggable = true;
|
||||
item.right.action_callback = [this]() { m_imgui_undo_redo_hovered_pos = -1; };
|
||||
item.right.render_callback = [this](float left, float right, float, float) { if (m_canvas != nullptr) _render_undo_redo_stack(true, 0.5f * (left + right)); };
|
||||
item.visibility_callback = []()->bool { return true; };
|
||||
item.enabling_callback = [this]()->bool { return wxGetApp().plater()->can_undo(); };
|
||||
if (!m_toolbar.add_item(item))
|
||||
return false;
|
||||
|
||||
item.name = "redo";
|
||||
item.icon_filename = "redo_toolbar.svg";
|
||||
item.tooltip = _utf8(L("Redo")) + " [" + GUI::shortkey_ctrl_prefix() + "Y]";
|
||||
item.sprite_id = 12;
|
||||
item.left.action_callback = [this]() { post_event(SimpleEvent(EVT_GLCANVAS_REDO)); };
|
||||
item.right.action_callback = [this]() { m_imgui_undo_redo_hovered_pos = -1; };
|
||||
item.right.render_callback = [this](float left, float right, float, float) { if (m_canvas != nullptr) _render_undo_redo_stack(false, 0.5f * (left + right)); };
|
||||
item.enabling_callback = [this]()->bool { return wxGetApp().plater()->can_redo(); };
|
||||
if (!m_toolbar.add_item(item))
|
||||
return false;
|
||||
|
||||
|
@ -3646,7 +3764,7 @@ void GLCanvas3D::_picking_pass() const
|
|||
if (m_camera_clipping_plane.is_active())
|
||||
::glDisable(GL_CLIP_PLANE0);
|
||||
|
||||
m_gizmos.render_current_gizmo_for_picking_pass(m_selection);
|
||||
m_gizmos.render_current_gizmo_for_picking_pass();
|
||||
|
||||
if (m_multisample_allowed)
|
||||
glsafe(::glEnable(GL_MULTISAMPLE));
|
||||
|
@ -3956,7 +4074,7 @@ void GLCanvas3D::_render_volumes_for_picking() const
|
|||
|
||||
void GLCanvas3D::_render_current_gizmo() const
|
||||
{
|
||||
m_gizmos.render_current_gizmo(m_selection);
|
||||
m_gizmos.render_current_gizmo();
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_gizmos_overlay() const
|
||||
|
@ -3972,7 +4090,7 @@ void GLCanvas3D::_render_gizmos_overlay() const
|
|||
m_gizmos.set_overlay_icon_size(size); //! #ys_FIXME_experiment
|
||||
#endif /* __WXMSW__ */
|
||||
|
||||
m_gizmos.render_overlay(*this, m_selection);
|
||||
m_gizmos.render_overlay();
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_toolbar() const
|
||||
|
@ -4617,7 +4735,7 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
|
|||
{
|
||||
const Print *print;
|
||||
const std::vector<float> *tool_colors;
|
||||
WipeTower::xy wipe_tower_pos;
|
||||
Vec2f wipe_tower_pos;
|
||||
float wipe_tower_angle;
|
||||
|
||||
// Number of vertices (each vertex is 6x4=24 bytes long)
|
||||
|
@ -4648,12 +4766,13 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
|
|||
ctxt.print = print;
|
||||
ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors;
|
||||
if (print->wipe_tower_data().priming && print->config().single_extruder_multi_material_priming)
|
||||
ctxt.priming.emplace_back(*print->wipe_tower_data().priming.get());
|
||||
for (int i=0; i<print->wipe_tower_data().priming.get()->size(); ++i)
|
||||
ctxt.priming.emplace_back(print->wipe_tower_data().priming.get()->at(i));
|
||||
if (print->wipe_tower_data().final_purge)
|
||||
ctxt.final.emplace_back(*print->wipe_tower_data().final_purge.get());
|
||||
|
||||
ctxt.wipe_tower_angle = ctxt.print->config().wipe_tower_rotation_angle.value/180.f * PI;
|
||||
ctxt.wipe_tower_pos = WipeTower::xy(ctxt.print->config().wipe_tower_x.value, ctxt.print->config().wipe_tower_y.value);
|
||||
ctxt.wipe_tower_pos = Vec2f(ctxt.print->config().wipe_tower_x.value, ctxt.print->config().wipe_tower_y.value);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start";
|
||||
|
||||
|
@ -4715,19 +4834,19 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
|
|||
WipeTower::Extrusion e_prev = extrusions.extrusions[i-1];
|
||||
|
||||
if (!extrusions.priming) { // wipe tower extrusions describe the wipe tower at the origin with no rotation
|
||||
e_prev.pos.rotate(ctxt.wipe_tower_angle);
|
||||
e_prev.pos.translate(ctxt.wipe_tower_pos);
|
||||
e_prev.pos = Eigen::Rotation2Df(ctxt.wipe_tower_angle) * e_prev.pos;
|
||||
e_prev.pos += ctxt.wipe_tower_pos;
|
||||
}
|
||||
|
||||
for (; i < j; ++i) {
|
||||
WipeTower::Extrusion e = extrusions.extrusions[i];
|
||||
assert(e.width > 0.f);
|
||||
if (!extrusions.priming) {
|
||||
e.pos.rotate(ctxt.wipe_tower_angle);
|
||||
e.pos.translate(ctxt.wipe_tower_pos);
|
||||
e.pos = Eigen::Rotation2Df(ctxt.wipe_tower_angle) * e.pos;
|
||||
e.pos += ctxt.wipe_tower_pos;
|
||||
}
|
||||
|
||||
lines.emplace_back(Point::new_scale(e_prev.pos.x, e_prev.pos.y), Point::new_scale(e.pos.x, e.pos.y));
|
||||
lines.emplace_back(Point::new_scale(e_prev.pos.x(), e_prev.pos.y()), Point::new_scale(e.pos.x(), e.pos.y()));
|
||||
widths.emplace_back(e.width);
|
||||
|
||||
e_prev = e;
|
||||
|
@ -5271,7 +5390,7 @@ void GLCanvas3D::_load_fff_shells()
|
|||
double max_z = print->objects()[0]->model_object()->get_model()->bounding_box().max(2);
|
||||
const PrintConfig& config = print->config();
|
||||
unsigned int extruders_count = config.nozzle_diameter.size();
|
||||
if ((extruders_count > 1) && config.single_extruder_multi_material && config.wipe_tower && !config.complete_objects) {
|
||||
if ((extruders_count > 1) && config.wipe_tower && !config.complete_objects) {
|
||||
float depth = print->get_wipe_tower_depth();
|
||||
|
||||
// Calculate wipe tower brim spacing.
|
||||
|
@ -5544,13 +5663,29 @@ void GLCanvas3D::_update_selection_from_hover()
|
|||
if (m_selection.is_empty())
|
||||
m_gizmos.reset_all_states();
|
||||
else
|
||||
m_gizmos.refresh_on_off_state(m_selection);
|
||||
m_gizmos.refresh_on_off_state();
|
||||
|
||||
m_gizmos.update_data(*this);
|
||||
m_gizmos.update_data();
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_deactivate_undo_redo_toolbar_items()
|
||||
{
|
||||
if (m_toolbar.is_item_pressed("undo"))
|
||||
{
|
||||
m_toolbar.force_right_action(m_toolbar.get_item_id("undo"), *this);
|
||||
return true;
|
||||
}
|
||||
else if (m_toolbar.is_item_pressed("redo"))
|
||||
{
|
||||
m_toolbar.force_right_action(m_toolbar.get_item_id("redo"), *this);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const Print* GLCanvas3D::fff_print() const
|
||||
{
|
||||
return (m_process == nullptr) ? nullptr : m_process->fff_print();
|
||||
|
|
|
@ -127,6 +127,8 @@ wxDECLARE_EVENT(EVT_GLCANVAS_TAB, SimpleEvent);
|
|||
wxDECLARE_EVENT(EVT_GLCANVAS_RESETGIZMOS, SimpleEvent);
|
||||
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);
|
||||
|
||||
class GLCanvas3D
|
||||
{
|
||||
|
@ -485,6 +487,8 @@ private:
|
|||
RenderStats m_render_stats;
|
||||
#endif // ENABLE_RENDER_STATISTICS
|
||||
|
||||
int m_imgui_undo_redo_hovered_pos{ -1 };
|
||||
|
||||
public:
|
||||
GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar);
|
||||
~GLCanvas3D();
|
||||
|
@ -513,6 +517,9 @@ public:
|
|||
const Selection& get_selection() const { return m_selection; }
|
||||
Selection& get_selection() { return m_selection; }
|
||||
|
||||
const GLGizmosManager& get_gizmos_manager() const { return m_gizmos; }
|
||||
GLGizmosManager& get_gizmos_manager() { return m_gizmos; }
|
||||
|
||||
void bed_shape_changed();
|
||||
|
||||
void set_clipping_plane(unsigned int id, const ClippingPlane& plane)
|
||||
|
@ -596,11 +603,12 @@ public:
|
|||
|
||||
void set_tooltip(const std::string& tooltip) const;
|
||||
|
||||
void do_move();
|
||||
void do_rotate();
|
||||
void do_scale();
|
||||
void do_flatten();
|
||||
void do_mirror();
|
||||
// the following methods add a snapshot to the undo/redo stack, unless the given string is empty
|
||||
void do_move(const std::string& snapshot_type);
|
||||
void do_rotate(const std::string& snapshot_type);
|
||||
void do_scale(const std::string& snapshot_type);
|
||||
void do_flatten(const Vec3d& normal, const std::string& snapshot_type);
|
||||
void do_mirror(const std::string& snapshot_type);
|
||||
|
||||
void set_camera_zoom(double zoom);
|
||||
|
||||
|
@ -673,6 +681,7 @@ private:
|
|||
#endif // ENABLE_SHOW_CAMERA_TARGET
|
||||
void _render_sla_slices() const;
|
||||
void _render_selection_sidebar_hints() const;
|
||||
void _render_undo_redo_stack(const bool is_undo, float pos_x);
|
||||
|
||||
void _update_volumes_hover_state() const;
|
||||
|
||||
|
@ -731,6 +740,8 @@ private:
|
|||
// updates the selection from the content of m_hover_volume_idxs
|
||||
void _update_selection_from_hover();
|
||||
|
||||
bool _deactivate_undo_redo_toolbar_items();
|
||||
|
||||
static std::vector<float> _parse_colors(const std::vector<std::string>& colors);
|
||||
|
||||
public:
|
||||
|
|
|
@ -34,18 +34,24 @@ wxDEFINE_EVENT(EVT_GLVIEWTOOLBAR_PREVIEW, SimpleEvent);
|
|||
|
||||
const GLToolbarItem::ActionCallback GLToolbarItem::Default_Action_Callback = [](){};
|
||||
const GLToolbarItem::VisibilityCallback GLToolbarItem::Default_Visibility_Callback = []()->bool { return true; };
|
||||
const GLToolbarItem::EnabledStateCallback GLToolbarItem::Default_Enabled_State_Callback = []()->bool { return true; };
|
||||
const GLToolbarItem::EnablingCallback GLToolbarItem::Default_Enabling_Callback = []()->bool { return true; };
|
||||
const GLToolbarItem::RenderCallback GLToolbarItem::Default_Render_Callback = [](float, float, float, float){};
|
||||
|
||||
GLToolbarItem::Data::Option::Option()
|
||||
: toggable(false)
|
||||
, action_callback(Default_Action_Callback)
|
||||
, render_callback(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
GLToolbarItem::Data::Data()
|
||||
: name("")
|
||||
, icon_filename("")
|
||||
, tooltip("")
|
||||
, sprite_id(-1)
|
||||
, is_toggable(false)
|
||||
, visible(true)
|
||||
, action_callback(Default_Action_Callback)
|
||||
, visibility_callback(Default_Visibility_Callback)
|
||||
, enabled_state_callback(Default_Enabled_State_Callback)
|
||||
, enabling_callback(Default_Enabling_Callback)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -53,6 +59,7 @@ GLToolbarItem::GLToolbarItem(GLToolbarItem::EType type, const GLToolbarItem::Dat
|
|||
: m_type(type)
|
||||
, m_state(Normal)
|
||||
, m_data(data)
|
||||
, m_last_action_type(Undefined)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -68,7 +75,7 @@ bool GLToolbarItem::update_visibility()
|
|||
|
||||
bool GLToolbarItem::update_enabled_state()
|
||||
{
|
||||
bool enabled = m_data.enabled_state_callback();
|
||||
bool enabled = m_data.enabling_callback();
|
||||
bool ret = (is_enabled() != enabled);
|
||||
if (ret)
|
||||
m_state = enabled ? GLToolbarItem::Normal : GLToolbarItem::Disabled;
|
||||
|
@ -79,6 +86,14 @@ 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
|
||||
{
|
||||
GLTexture::render_sub_texture(tex_id, left, right, bottom, top, get_uvs(tex_width, tex_height, icon_size));
|
||||
|
||||
if (is_pressed())
|
||||
{
|
||||
if ((m_last_action_type == Left) && m_data.left.can_render())
|
||||
m_data.left.render_callback(left, right, bottom, top);
|
||||
else if ((m_last_action_type == Right) && m_data.right.can_render())
|
||||
m_data.right.render_callback(left, right, bottom, top);
|
||||
}
|
||||
}
|
||||
|
||||
GLTexture::Quad_UVs GLToolbarItem::get_uvs(unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) const
|
||||
|
@ -136,6 +151,7 @@ GLToolbar::GLToolbar(GLToolbar::EType type, const std::string& name)
|
|||
, m_enabled(false)
|
||||
, m_icons_texture_dirty(true)
|
||||
, m_tooltip("")
|
||||
, m_pressed_toggable_id(-1)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -295,7 +311,7 @@ void GLToolbar::select_item(const std::string& name)
|
|||
|
||||
bool GLToolbar::is_item_pressed(const std::string& name) const
|
||||
{
|
||||
for (GLToolbarItem* item : m_items)
|
||||
for (const GLToolbarItem* item : m_items)
|
||||
{
|
||||
if (item->get_name() == name)
|
||||
return item->is_pressed();
|
||||
|
@ -306,7 +322,7 @@ bool GLToolbar::is_item_pressed(const std::string& name) const
|
|||
|
||||
bool GLToolbar::is_item_disabled(const std::string& name) const
|
||||
{
|
||||
for (GLToolbarItem* item : m_items)
|
||||
for (const GLToolbarItem* item : m_items)
|
||||
{
|
||||
if (item->get_name() == name)
|
||||
return item->is_disabled();
|
||||
|
@ -317,7 +333,7 @@ bool GLToolbar::is_item_disabled(const std::string& name) const
|
|||
|
||||
bool GLToolbar::is_item_visible(const std::string& name) const
|
||||
{
|
||||
for (GLToolbarItem* item : m_items)
|
||||
for (const GLToolbarItem* item : m_items)
|
||||
{
|
||||
if (item->get_name() == name)
|
||||
return item->is_visible();
|
||||
|
@ -326,11 +342,46 @@ bool GLToolbar::is_item_visible(const std::string& name) const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool GLToolbar::is_any_item_pressed() const
|
||||
{
|
||||
for (const GLToolbarItem* item : m_items)
|
||||
{
|
||||
if (item->is_pressed())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int GLToolbar::get_item_id(const std::string& name) const
|
||||
{
|
||||
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
|
||||
{
|
||||
if (m_items[i]->get_name() == name)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void GLToolbar::force_left_action(unsigned int item_id, GLCanvas3D& parent)
|
||||
{
|
||||
do_action(GLToolbarItem::Left, item_id, parent, false);
|
||||
}
|
||||
|
||||
void GLToolbar::force_right_action(unsigned int item_id, GLCanvas3D& parent)
|
||||
{
|
||||
do_action(GLToolbarItem::Right, item_id, parent, false);
|
||||
}
|
||||
|
||||
bool GLToolbar::update_items_state()
|
||||
{
|
||||
bool ret = false;
|
||||
ret |= update_items_visibility();
|
||||
ret |= update_items_enabled_state();
|
||||
if (!is_any_item_pressed())
|
||||
m_pressed_toggable_id = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -392,10 +443,11 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
|||
m_mouse_capture.left = true;
|
||||
m_mouse_capture.parent = &parent;
|
||||
processed = true;
|
||||
if ((item_id != -2) && !m_items[item_id]->is_separator())
|
||||
if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Left)))
|
||||
{
|
||||
// mouse is inside an icon
|
||||
do_action((unsigned int)item_id, parent);
|
||||
do_action(GLToolbarItem::Left, (unsigned int)item_id, parent, true);
|
||||
parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
else if (evt.MiddleDown())
|
||||
|
@ -407,6 +459,13 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
|||
{
|
||||
m_mouse_capture.right = true;
|
||||
m_mouse_capture.parent = &parent;
|
||||
processed = true;
|
||||
if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Right)))
|
||||
{
|
||||
// mouse is inside an icon
|
||||
do_action(GLToolbarItem::Right, (unsigned int)item_id, parent, true);
|
||||
parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
else if (evt.LeftUp())
|
||||
processed = true;
|
||||
|
@ -477,33 +536,55 @@ float GLToolbar::get_main_size() const
|
|||
return size * m_layout.scale;
|
||||
}
|
||||
|
||||
void GLToolbar::do_action(unsigned int item_id, GLCanvas3D& parent)
|
||||
void GLToolbar::do_action(GLToolbarItem::EActionType type, unsigned int item_id, GLCanvas3D& parent, bool check_hover)
|
||||
{
|
||||
if ((m_pressed_toggable_id == -1) || (m_pressed_toggable_id == item_id))
|
||||
{
|
||||
if (item_id < (unsigned int)m_items.size())
|
||||
{
|
||||
GLToolbarItem* item = m_items[item_id];
|
||||
if ((item != nullptr) && !item->is_separator() && item->is_hovered())
|
||||
if ((item != nullptr) && !item->is_separator() && (!check_hover || item->is_hovered()))
|
||||
{
|
||||
if (item->is_toggable())
|
||||
if (((type == GLToolbarItem::Right) && item->is_right_toggable()) ||
|
||||
((type == GLToolbarItem::Left) && item->is_left_toggable()))
|
||||
{
|
||||
GLToolbarItem::EState state = item->get_state();
|
||||
if (state == GLToolbarItem::Hover)
|
||||
item->set_state(GLToolbarItem::HoverPressed);
|
||||
else if (state == GLToolbarItem::HoverPressed)
|
||||
item->set_state(GLToolbarItem::Hover);
|
||||
else if (state == GLToolbarItem::Pressed)
|
||||
item->set_state(GLToolbarItem::Normal);
|
||||
else if (state == GLToolbarItem::Normal)
|
||||
item->set_state(GLToolbarItem::Pressed);
|
||||
|
||||
m_pressed_toggable_id = item->is_pressed() ? item_id : -1;
|
||||
item->reset_last_action_type();
|
||||
|
||||
parent.render();
|
||||
item->do_action();
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
case GLToolbarItem::Left: { item->do_left_action(); break; }
|
||||
case GLToolbarItem::Right: { item->do_right_action(); break; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_type == Radio)
|
||||
select_item(item->get_name());
|
||||
else
|
||||
item->set_state(GLToolbarItem::HoverPressed);
|
||||
item->set_state(item->is_hovered() ? GLToolbarItem::HoverPressed : GLToolbarItem::Pressed);
|
||||
|
||||
item->reset_last_action_type();
|
||||
parent.render();
|
||||
item->do_action();
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
case GLToolbarItem::Left: { item->do_left_action(); break; }
|
||||
case GLToolbarItem::Right: { item->do_right_action(); break; }
|
||||
}
|
||||
|
||||
if ((m_type == Normal) && (item->get_state() != GLToolbarItem::Disabled))
|
||||
{
|
||||
// the item may get disabled during the action, if not, set it back to hover state
|
||||
|
@ -513,6 +594,7 @@ void GLToolbar::do_action(unsigned int item_id, GLCanvas3D& parent)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string GLToolbar::update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent)
|
||||
|
@ -1212,9 +1294,15 @@ bool GLToolbar::update_items_enabled_state()
|
|||
{
|
||||
bool ret = false;
|
||||
|
||||
for (GLToolbarItem* item : m_items)
|
||||
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
|
||||
{
|
||||
GLToolbarItem* item = m_items[i];
|
||||
ret |= item->update_enabled_state();
|
||||
if (item->is_enabled() && (m_pressed_toggable_id != -1) && (m_pressed_toggable_id != i))
|
||||
{
|
||||
ret = true;
|
||||
item->set_state(GLToolbarItem::Disabled);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
|
|
|
@ -36,7 +36,8 @@ class GLToolbarItem
|
|||
public:
|
||||
typedef std::function<void()> ActionCallback;
|
||||
typedef std::function<bool()> VisibilityCallback;
|
||||
typedef std::function<bool()> EnabledStateCallback;
|
||||
typedef std::function<bool()> EnablingCallback;
|
||||
typedef std::function<void(float, float, float, float)> RenderCallback;
|
||||
|
||||
enum EType : unsigned char
|
||||
{
|
||||
|
@ -45,6 +46,14 @@ public:
|
|||
Num_Types
|
||||
};
|
||||
|
||||
enum EActionType : unsigned char
|
||||
{
|
||||
Undefined,
|
||||
Left,
|
||||
Right,
|
||||
Num_Action_Types
|
||||
};
|
||||
|
||||
enum EState : unsigned char
|
||||
{
|
||||
Normal,
|
||||
|
@ -57,27 +66,42 @@ public:
|
|||
|
||||
struct Data
|
||||
{
|
||||
struct Option
|
||||
{
|
||||
bool toggable;
|
||||
ActionCallback action_callback;
|
||||
RenderCallback render_callback;
|
||||
|
||||
Option();
|
||||
|
||||
bool can_render() const { return toggable && (render_callback != nullptr); }
|
||||
};
|
||||
|
||||
std::string name;
|
||||
std::string icon_filename;
|
||||
std::string tooltip;
|
||||
unsigned int sprite_id;
|
||||
bool is_toggable;
|
||||
// mouse left click
|
||||
Option left;
|
||||
// mouse right click
|
||||
Option right;
|
||||
bool visible;
|
||||
ActionCallback action_callback;
|
||||
VisibilityCallback visibility_callback;
|
||||
EnabledStateCallback enabled_state_callback;
|
||||
EnablingCallback enabling_callback;
|
||||
|
||||
Data();
|
||||
};
|
||||
|
||||
static const ActionCallback Default_Action_Callback;
|
||||
static const VisibilityCallback Default_Visibility_Callback;
|
||||
static const EnabledStateCallback Default_Enabled_State_Callback;
|
||||
static const EnablingCallback Default_Enabling_Callback;
|
||||
static const RenderCallback Default_Render_Callback;
|
||||
|
||||
private:
|
||||
EType m_type;
|
||||
EState m_state;
|
||||
Data m_data;
|
||||
EActionType m_last_action_type;
|
||||
|
||||
public:
|
||||
GLToolbarItem(EType type, const Data& data);
|
||||
|
@ -89,17 +113,25 @@ public:
|
|||
const std::string& get_icon_filename() const { return m_data.icon_filename; }
|
||||
const std::string& get_tooltip() const { return m_data.tooltip; }
|
||||
|
||||
void do_action() { m_data.action_callback(); }
|
||||
void do_left_action() { m_last_action_type = Left; m_data.left.action_callback(); }
|
||||
void do_right_action() { m_last_action_type = Right; m_data.right.action_callback(); }
|
||||
|
||||
bool is_enabled() const { return m_state != Disabled; }
|
||||
bool is_disabled() const { return m_state == Disabled; }
|
||||
bool is_hovered() const { return (m_state == Hover) || (m_state == HoverPressed); }
|
||||
bool is_pressed() const { return (m_state == Pressed) || (m_state == HoverPressed); }
|
||||
|
||||
bool is_toggable() const { return m_data.is_toggable; }
|
||||
bool is_visible() const { return m_data.visible; }
|
||||
bool is_separator() const { return m_type == Separator; }
|
||||
|
||||
bool is_left_toggable() const { return m_data.left.toggable; }
|
||||
bool is_right_toggable() const { return m_data.right.toggable; }
|
||||
|
||||
bool has_left_render_callback() const { return m_data.left.render_callback != nullptr; }
|
||||
bool has_right_render_callback() const { return m_data.right.render_callback != nullptr; }
|
||||
|
||||
EActionType get_last_action_type() const { return m_last_action_type; }
|
||||
void reset_last_action_type() { m_last_action_type = Undefined; }
|
||||
|
||||
// returns true if the state changes
|
||||
bool update_visibility();
|
||||
// returns true if the state changes
|
||||
|
@ -212,6 +244,7 @@ private:
|
|||
|
||||
MouseCapture m_mouse_capture;
|
||||
std::string m_tooltip;
|
||||
unsigned int m_pressed_toggable_id;
|
||||
|
||||
public:
|
||||
GLToolbar(EType type, const std::string& name);
|
||||
|
@ -246,6 +279,13 @@ public:
|
|||
bool is_item_disabled(const std::string& name) const;
|
||||
bool is_item_visible(const std::string& name) const;
|
||||
|
||||
bool is_any_item_pressed() const;
|
||||
|
||||
unsigned int get_item_id(const std::string& name) const;
|
||||
|
||||
void force_left_action(unsigned int item_id, GLCanvas3D& parent);
|
||||
void force_right_action(unsigned int item_id, GLCanvas3D& parent);
|
||||
|
||||
const std::string& get_tooltip() const { return m_tooltip; }
|
||||
|
||||
// returns true if any item changed its state
|
||||
|
@ -262,7 +302,7 @@ private:
|
|||
float get_height_horizontal() const;
|
||||
float get_height_vertical() const;
|
||||
float get_main_size() const;
|
||||
void do_action(unsigned int item_id, GLCanvas3D& parent);
|
||||
void do_action(GLToolbarItem::EActionType type, unsigned int item_id, GLCanvas3D& parent, bool check_hover);
|
||||
std::string update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent);
|
||||
std::string update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D& parent);
|
||||
std::string update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& parent);
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace GUI
|
|||
wxDEFINE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent);
|
||||
|
||||
// pt_FFF
|
||||
FreqSettingsBundle FREQ_SETTINGS_BUNDLE_FFF =
|
||||
SettingsBundle FREQ_SETTINGS_BUNDLE_FFF =
|
||||
{
|
||||
{ L("Layers and Perimeters"), { "layer_height" , "perimeters", "top_solid_layers", "bottom_solid_layers" } },
|
||||
{ L("Infill") , { "fill_density", "fill_pattern" } },
|
||||
|
@ -36,7 +36,7 @@ FreqSettingsBundle FREQ_SETTINGS_BUNDLE_FFF =
|
|||
};
|
||||
|
||||
// pt_SLA
|
||||
FreqSettingsBundle FREQ_SETTINGS_BUNDLE_SLA =
|
||||
SettingsBundle FREQ_SETTINGS_BUNDLE_SLA =
|
||||
{
|
||||
{ L("Pad and Support") , { "supports_enable", "pad_enable" } }
|
||||
};
|
||||
|
@ -66,6 +66,14 @@ static int extruders_count()
|
|||
return wxGetApp().extruders_cnt();
|
||||
}
|
||||
|
||||
static void take_snapshot(const wxString& snapshot_name)
|
||||
{
|
||||
wxGetApp().plater()->take_snapshot(snapshot_name);
|
||||
}
|
||||
|
||||
static void suppress_snapshots(){ wxGetApp().plater()->suppress_snapshots(); }
|
||||
static void allow_snapshots() { wxGetApp().plater()->allow_snapshots(); }
|
||||
|
||||
ObjectList::ObjectList(wxWindow* parent) :
|
||||
wxDataViewCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_MULTIPLE),
|
||||
m_parent(parent)
|
||||
|
@ -138,20 +146,24 @@ ObjectList::ObjectList(wxWindow* parent) :
|
|||
// Bind(wxEVT_KEY_DOWN, &ObjectList::OnChar, this);
|
||||
{
|
||||
// Accelerators
|
||||
wxAcceleratorEntry entries[6];
|
||||
wxAcceleratorEntry entries[8];
|
||||
entries[0].Set(wxACCEL_CTRL, (int) 'C', wxID_COPY);
|
||||
entries[1].Set(wxACCEL_CTRL, (int) 'X', wxID_CUT);
|
||||
entries[2].Set(wxACCEL_CTRL, (int) 'V', wxID_PASTE);
|
||||
entries[3].Set(wxACCEL_CTRL, (int) 'A', wxID_SELECTALL);
|
||||
entries[4].Set(wxACCEL_NORMAL, WXK_DELETE, wxID_DELETE);
|
||||
entries[5].Set(wxACCEL_NORMAL, WXK_BACK, wxID_DELETE);
|
||||
wxAcceleratorTable accel(6, entries);
|
||||
entries[4].Set(wxACCEL_CTRL, (int) 'Z', wxID_UNDO);
|
||||
entries[5].Set(wxACCEL_CTRL, (int) 'Y', wxID_REDO);
|
||||
entries[6].Set(wxACCEL_NORMAL, WXK_DELETE, wxID_DELETE);
|
||||
entries[7].Set(wxACCEL_NORMAL, WXK_BACK, wxID_DELETE);
|
||||
wxAcceleratorTable accel(8, entries);
|
||||
SetAcceleratorTable(accel);
|
||||
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->copy(); }, wxID_COPY);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->paste(); }, wxID_PASTE);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->select_item_all_children(); }, wxID_SELECTALL);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->remove(); }, wxID_DELETE);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->undo(); }, wxID_UNDO);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->redo(); }, wxID_REDO);
|
||||
}
|
||||
#else __WXOSX__
|
||||
Bind(wxEVT_CHAR, [this](wxKeyEvent& event) { key_event(event); }); // doesn't work on OSX
|
||||
|
@ -655,7 +667,6 @@ void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& vol
|
|||
if (volumes.empty())
|
||||
return;
|
||||
|
||||
ModelObject& model_object = *(*m_objects)[obj_idx];
|
||||
const auto object_item = m_objects_model->GetItemById(obj_idx);
|
||||
|
||||
wxDataViewItemArray items;
|
||||
|
@ -665,10 +676,7 @@ void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& vol
|
|||
const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(object_item, wxString::FromUTF8(volume->name.c_str()), volume->type(),
|
||||
volume->get_mesh_errors_count()>0 ,
|
||||
volume->config.has("extruder") ? volume->config.option<ConfigOptionInt>("extruder")->value : 0);
|
||||
auto opt_keys = volume->config.keys();
|
||||
if (!opt_keys.empty() && !((opt_keys.size() == 1) && (opt_keys[0] == "extruder")))
|
||||
select_item(m_objects_model->AddSettingsChild(vol_item));
|
||||
|
||||
add_settings_item(vol_item, &volume->config);
|
||||
items.Add(vol_item);
|
||||
}
|
||||
|
||||
|
@ -805,6 +813,16 @@ void ObjectList::paste()
|
|||
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
|
||||
}
|
||||
|
||||
void ObjectList::undo()
|
||||
{
|
||||
wxGetApp().plater()->undo();
|
||||
}
|
||||
|
||||
void ObjectList::redo()
|
||||
{
|
||||
wxGetApp().plater()->redo();
|
||||
}
|
||||
|
||||
#ifndef __WXOSX__
|
||||
void ObjectList::key_event(wxKeyEvent& event)
|
||||
{
|
||||
|
@ -823,6 +841,10 @@ void ObjectList::key_event(wxKeyEvent& event)
|
|||
copy();
|
||||
else if (wxGetKeyState(wxKeyCode('V')) && wxGetKeyState(WXK_CONTROL))
|
||||
paste();
|
||||
else if (wxGetKeyState(wxKeyCode('Y')) && wxGetKeyState(WXK_CONTROL))
|
||||
redo();
|
||||
else if (wxGetKeyState(wxKeyCode('Z')) && wxGetKeyState(WXK_CONTROL))
|
||||
undo();
|
||||
else
|
||||
event.Skip();
|
||||
}
|
||||
|
@ -908,6 +930,7 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
|
|||
|
||||
if (m_dragged_data.type() == itInstance)
|
||||
{
|
||||
take_snapshot(_(L("Instances to Separated Objects")));
|
||||
instances_to_separated_object(m_dragged_data.obj_idx(), m_dragged_data.inst_idxs());
|
||||
m_dragged_data.clear();
|
||||
return;
|
||||
|
@ -925,6 +948,8 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
|
|||
// if (to_volume_id > from_volume_id) to_volume_id--;
|
||||
// #endif // __WXGTK__
|
||||
|
||||
take_snapshot(_(L("Remov Volume(s)")));
|
||||
|
||||
auto& volumes = (*m_objects)[m_dragged_data.obj_idx()]->volumes;
|
||||
auto delta = to_volume_id < from_volume_id ? -1 : 1;
|
||||
int cnt = 0;
|
||||
|
@ -963,7 +988,7 @@ std::vector<std::string> ObjectList::get_options(const bool is_part)
|
|||
|
||||
const std::vector<std::string>& ObjectList::get_options_for_bundle(const wxString& bundle_name)
|
||||
{
|
||||
const FreqSettingsBundle& bundle = printer_technology() == ptSLA ?
|
||||
const SettingsBundle& bundle = printer_technology() == ptSLA ?
|
||||
FREQ_SETTINGS_BUNDLE_SLA : FREQ_SETTINGS_BUNDLE_FFF;
|
||||
|
||||
for (auto& it : bundle)
|
||||
|
@ -973,7 +998,7 @@ const std::vector<std::string>& ObjectList::get_options_for_bundle(const wxStrin
|
|||
}
|
||||
#if 0
|
||||
// if "Quick menu" is selected
|
||||
FreqSettingsBundle& bundle_quick = printer_technology() == ptSLA ?
|
||||
SettingsBundle& bundle_quick = printer_technology() == ptSLA ?
|
||||
m_freq_settings_sla: m_freq_settings_fff;
|
||||
|
||||
for (auto& it : bundle_quick)
|
||||
|
@ -1049,7 +1074,7 @@ void ObjectList::get_settings_choice(const wxString& category_name)
|
|||
if (selection_cnt > 0)
|
||||
{
|
||||
// Add selected items to the "Quick menu"
|
||||
FreqSettingsBundle& freq_settings = printer_technology() == ptSLA ?
|
||||
SettingsBundle& freq_settings = printer_technology() == ptSLA ?
|
||||
m_freq_settings_sla : m_freq_settings_fff;
|
||||
bool changed_existing = false;
|
||||
|
||||
|
@ -1090,6 +1115,8 @@ void ObjectList::get_settings_choice(const wxString& category_name)
|
|||
}
|
||||
#endif
|
||||
|
||||
take_snapshot(wxString::Format(_(L("Add Settings for %s")), is_part ? _(L("Sub-object")) : _(L("Object"))));
|
||||
|
||||
std::vector <std::string> selected_options;
|
||||
selected_options.reserve(selection_cnt);
|
||||
for (auto sel : selections)
|
||||
|
@ -1119,8 +1146,8 @@ void ObjectList::get_settings_choice(const wxString& category_name)
|
|||
}
|
||||
|
||||
|
||||
// Add settings item for object
|
||||
update_settings_item();
|
||||
// Add settings item for object/sub-object and show them
|
||||
show_settings(add_settings_item(GetSelection(), m_config));
|
||||
}
|
||||
|
||||
void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
|
||||
|
@ -1140,6 +1167,8 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
|
|||
assert(m_config);
|
||||
auto opt_keys = m_config->keys();
|
||||
|
||||
take_snapshot(wxString::Format(_(L("Add Settings Bundle for %s")), m_objects_model->GetItemType(GetSelection()) & itObject ? _(L("Object")) : _(L("Sub-object"))));
|
||||
|
||||
const DynamicPrintConfig& from_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
for (auto& opt_key : options)
|
||||
{
|
||||
|
@ -1154,13 +1183,21 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
|
|||
}
|
||||
}
|
||||
|
||||
// Add settings item for object
|
||||
update_settings_item();
|
||||
// Add settings item for object/sub-object and show them
|
||||
show_settings(add_settings_item(GetSelection(), m_config));
|
||||
}
|
||||
|
||||
void ObjectList::update_settings_item()
|
||||
void ObjectList::show_settings(const wxDataViewItem settings_item)
|
||||
{
|
||||
auto item = GetSelection();
|
||||
if (!settings_item)
|
||||
return;
|
||||
|
||||
select_item(settings_item);
|
||||
|
||||
// update object selection on Plater
|
||||
if (!m_prevent_canvas_selection_update)
|
||||
update_selections_on_canvas();
|
||||
/* auto item = GetSelection();
|
||||
if (item) {
|
||||
if (m_objects_model->GetItemType(item) == itInstance)
|
||||
item = m_objects_model->GetTopParent(item);
|
||||
|
@ -1173,11 +1210,13 @@ void ObjectList::update_settings_item()
|
|||
update_selections_on_canvas();
|
||||
}
|
||||
else {
|
||||
//# ys_FIXME ??? use case ???
|
||||
auto panel = wxGetApp().sidebar().scrolled_panel();
|
||||
panel->Freeze();
|
||||
wxGetApp().obj_settings()->UpdateAndShow(true);
|
||||
panel->Thaw();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
wxMenu* ObjectList::append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type) {
|
||||
|
@ -1488,7 +1527,7 @@ wxMenu* ObjectList::create_settings_popupmenu(wxMenu *parent_menu)
|
|||
void ObjectList::create_freq_settings_popupmenu(wxMenu *menu)
|
||||
{
|
||||
// Add default settings bundles
|
||||
const FreqSettingsBundle& bundle = printer_technology() == ptFFF ?
|
||||
const SettingsBundle& bundle = printer_technology() == ptFFF ?
|
||||
FREQ_SETTINGS_BUNDLE_FFF : FREQ_SETTINGS_BUNDLE_SLA;
|
||||
|
||||
const int extruders_cnt = extruders_count();
|
||||
|
@ -1503,7 +1542,7 @@ void ObjectList::create_freq_settings_popupmenu(wxMenu *menu)
|
|||
}
|
||||
#if 0
|
||||
// Add "Quick" settings bundles
|
||||
const FreqSettingsBundle& bundle_quick = printer_technology() == ptFFF ?
|
||||
const SettingsBundle& bundle_quick = printer_technology() == ptFFF ?
|
||||
m_freq_settings_fff : m_freq_settings_sla;
|
||||
|
||||
for (auto& it : bundle_quick) {
|
||||
|
@ -1539,6 +1578,8 @@ void ObjectList::load_subobject(ModelVolumeType type)
|
|||
if (m_objects_model->GetItemType(item)&itInstance)
|
||||
item = m_objects_model->GetItemById(obj_idx);
|
||||
|
||||
take_snapshot(_(L("Load Part")));
|
||||
|
||||
std::vector<std::pair<wxString, bool>> volumes_info;
|
||||
load_part((*m_objects)[obj_idx], volumes_info, type);
|
||||
|
||||
|
@ -1614,6 +1655,8 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
|
|||
if (instance_idx == -1)
|
||||
return;
|
||||
|
||||
take_snapshot(_(L("Add Generic Subobject")));
|
||||
|
||||
// Selected object
|
||||
ModelObject &model_object = *(*m_objects)[obj_idx];
|
||||
// Bounding box of the selected instance in world coordinate system including the translation, without modifiers.
|
||||
|
@ -1720,6 +1763,8 @@ void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item)
|
|||
is_layer_settings && opt_cnt == 2 && m_config->has("extruder") && m_config->has("layer_height"))
|
||||
return;
|
||||
|
||||
take_snapshot(_(L("Delete Settings")));
|
||||
|
||||
int extruder = -1;
|
||||
if (m_config->has("extruder"))
|
||||
extruder = m_config->option<ConfigOptionInt>("extruder")->value;
|
||||
|
@ -1742,6 +1787,8 @@ void ObjectList::del_instances_from_object(const int obj_idx)
|
|||
if (instances.size() <= 1)
|
||||
return;
|
||||
|
||||
take_snapshot(_(L("Delete All Instances from Object")));
|
||||
|
||||
while ( instances.size()> 1)
|
||||
instances.pop_back();
|
||||
|
||||
|
@ -1756,6 +1803,8 @@ void ObjectList::del_layer_from_object(const int obj_idx, const t_layer_height_r
|
|||
if (del_range == object(obj_idx)->layer_config_ranges.end())
|
||||
return;
|
||||
|
||||
take_snapshot(_(L("Delete Layers Range")));
|
||||
|
||||
object(obj_idx)->layer_config_ranges.erase(del_range);
|
||||
|
||||
changed_object(obj_idx);
|
||||
|
@ -1789,6 +1838,8 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
|
|||
return false;
|
||||
}
|
||||
|
||||
take_snapshot(_(L("Delete Subobject")));
|
||||
|
||||
object->delete_volume(idx);
|
||||
|
||||
if (object->volumes.size() == 1)
|
||||
|
@ -1805,6 +1856,8 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
|
|||
Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last intance from object.")));
|
||||
return false;
|
||||
}
|
||||
|
||||
take_snapshot(_(L("Delete Instance")));
|
||||
object->delete_instance(idx);
|
||||
}
|
||||
else
|
||||
|
@ -1832,6 +1885,8 @@ void ObjectList::split()
|
|||
return;
|
||||
}
|
||||
|
||||
take_snapshot(_(L("Split to Parts")));
|
||||
|
||||
wxBusyCursor wait;
|
||||
|
||||
auto model_object = (*m_objects)[obj_idx];
|
||||
|
@ -1850,11 +1905,7 @@ void ObjectList::split()
|
|||
volume->config.option<ConfigOptionInt>("extruder")->value : 0,
|
||||
false);
|
||||
// add settings to the part, if it has those
|
||||
auto opt_keys = volume->config.keys();
|
||||
if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) {
|
||||
select_item(m_objects_model->AddSettingsChild(vol_item));
|
||||
Expand(vol_item);
|
||||
}
|
||||
add_settings_item(vol_item, &volume->config);
|
||||
}
|
||||
|
||||
if (parent == item)
|
||||
|
@ -1879,8 +1930,10 @@ void ObjectList::layers_editing()
|
|||
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||
|
||||
// set some default value
|
||||
if (ranges.empty())
|
||||
if (ranges.empty()) {
|
||||
take_snapshot(_(L("Add Layers")));
|
||||
ranges[{ 0.0f, 2.0f }] = get_default_layer_config(obj_idx);
|
||||
}
|
||||
|
||||
// create layer root item
|
||||
layers_item = add_layer_root_item(obj_item);
|
||||
|
@ -1912,6 +1965,7 @@ wxDataViewItem ObjectList::add_layer_root_item(const wxDataViewItem obj_item)
|
|||
for (const auto range : object(obj_idx)->layer_config_ranges)
|
||||
add_layer_item(range.first, layers_item);
|
||||
|
||||
Expand(layers_item);
|
||||
return layers_item;
|
||||
}
|
||||
|
||||
|
@ -2097,7 +2151,79 @@ void ObjectList::part_selection_changed()
|
|||
panel.Thaw();
|
||||
}
|
||||
|
||||
void ObjectList::add_object_to_list(size_t obj_idx)
|
||||
SettingsBundle ObjectList::get_item_settings_bundle(const DynamicPrintConfig* config, const bool is_layers_range_settings)
|
||||
{
|
||||
auto opt_keys = config->keys();
|
||||
if (opt_keys.empty())
|
||||
return SettingsBundle();
|
||||
|
||||
update_opt_keys(opt_keys); // update options list according to print technology
|
||||
|
||||
if (opt_keys.size() == 1 && opt_keys[0] == "extruder" ||
|
||||
is_layers_range_settings && opt_keys.size() == 2)
|
||||
return SettingsBundle();
|
||||
|
||||
const int extruders_cnt = wxGetApp().extruders_edited_cnt();
|
||||
|
||||
SettingsBundle bundle;
|
||||
for (auto& opt_key : opt_keys)
|
||||
{
|
||||
auto category = config->def()->get(opt_key)->category;
|
||||
if (category.empty() || (category == "Extruders" && extruders_cnt == 1))
|
||||
continue;
|
||||
|
||||
std::vector< std::string > new_category;
|
||||
|
||||
auto& cat_opt = bundle.find(category) == bundle.end() ? new_category : bundle.at(category);
|
||||
cat_opt.push_back(opt_key);
|
||||
if (cat_opt.size() == 1)
|
||||
bundle[category] = cat_opt;
|
||||
}
|
||||
|
||||
return bundle;
|
||||
}
|
||||
|
||||
// Add new SettingsItem for parent_item if it doesn't exist, or just update a digest according to new config
|
||||
wxDataViewItem ObjectList::add_settings_item(wxDataViewItem parent_item, const DynamicPrintConfig* config)
|
||||
{
|
||||
wxDataViewItem ret = wxDataViewItem(0);
|
||||
|
||||
if (!parent_item)
|
||||
return ret;
|
||||
|
||||
const bool is_layers_range_settings = m_objects_model->GetItemType(parent_item) == itLayer;
|
||||
SettingsBundle cat_options = get_item_settings_bundle(config, is_layers_range_settings);
|
||||
if (cat_options.empty())
|
||||
return ret;
|
||||
|
||||
std::vector<std::string> categories;
|
||||
categories.reserve(cat_options.size());
|
||||
for (auto& cat : cat_options)
|
||||
{
|
||||
if (cat.second.size() == 1 &&
|
||||
(cat.second[0] == "extruder" || is_layers_range_settings && cat.second[0] == "layer_height"))
|
||||
continue;
|
||||
|
||||
categories.push_back(cat.first);
|
||||
}
|
||||
|
||||
if (categories.empty())
|
||||
return ret;
|
||||
|
||||
if (m_objects_model->GetItemType(parent_item) & itInstance)
|
||||
parent_item = m_objects_model->GetTopParent(parent_item);
|
||||
|
||||
ret = m_objects_model->IsSettingsItem(parent_item) ? parent_item : m_objects_model->GetSettingsItem(parent_item);
|
||||
|
||||
if (!ret) ret = m_objects_model->AddSettingsChild(parent_item);
|
||||
|
||||
m_objects_model->UpdateSettingsDigest(ret, categories);
|
||||
Expand(parent_item);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed)
|
||||
{
|
||||
auto model_object = (*m_objects)[obj_idx];
|
||||
const wxString& item_name = from_u8(model_object->name);
|
||||
|
@ -2116,11 +2242,7 @@ void ObjectList::add_object_to_list(size_t obj_idx)
|
|||
!volume->config.has("extruder") ? 0 :
|
||||
volume->config.option<ConfigOptionInt>("extruder")->value,
|
||||
false);
|
||||
auto opt_keys = volume->config.keys();
|
||||
if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) {
|
||||
select_item(m_objects_model->AddSettingsChild(vol_item));
|
||||
Expand(vol_item);
|
||||
}
|
||||
add_settings_item(vol_item, &volume->config);
|
||||
}
|
||||
Expand(item);
|
||||
}
|
||||
|
@ -2130,16 +2252,13 @@ void ObjectList::add_object_to_list(size_t obj_idx)
|
|||
increase_object_instances(obj_idx, model_object->instances.size());
|
||||
|
||||
// add settings to the object, if it has those
|
||||
auto opt_keys = model_object->config.keys();
|
||||
if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) {
|
||||
select_item(m_objects_model->AddSettingsChild(item));
|
||||
Expand(item);
|
||||
}
|
||||
add_settings_item(item, &model_object->config);
|
||||
|
||||
// Add layers if it has
|
||||
add_layer_root_item(item);
|
||||
|
||||
#ifndef __WXOSX__
|
||||
if (call_selection_changed)
|
||||
selection_changed();
|
||||
#endif //__WXMSW__
|
||||
}
|
||||
|
@ -2175,6 +2294,8 @@ void ObjectList::delete_from_model_and_list(const ItemType type, const int obj_i
|
|||
if ( !(type&(itObject|itVolume|itInstance)) )
|
||||
return;
|
||||
|
||||
take_snapshot(_(L("Delete Selected Item")));
|
||||
|
||||
if (type&itObject) {
|
||||
del_object(obj_idx);
|
||||
delete_object_from_list(obj_idx);
|
||||
|
@ -2285,6 +2406,9 @@ void ObjectList::remove()
|
|||
|
||||
wxDataViewItem parent = wxDataViewItem(0);
|
||||
|
||||
take_snapshot(_(L("Delete Selected")));
|
||||
suppress_snapshots();
|
||||
|
||||
for (auto& item : sels)
|
||||
{
|
||||
if (m_objects_model->GetParent(item) == wxDataViewItem(0))
|
||||
|
@ -2305,6 +2429,8 @@ void ObjectList::remove()
|
|||
|
||||
if (parent)
|
||||
select_item(parent);
|
||||
|
||||
allow_snapshots();
|
||||
}
|
||||
|
||||
void ObjectList::del_layer_range(const t_layer_height_range& range)
|
||||
|
@ -2350,6 +2476,8 @@ void ObjectList::add_layer_range_after_current(const t_layer_height_range& curre
|
|||
|
||||
if (current_range == last_range)
|
||||
{
|
||||
take_snapshot(_(L("Add New Layers Range")));
|
||||
|
||||
const t_layer_height_range& new_range = { last_range.second, last_range.second + 2.0f };
|
||||
ranges[new_range] = get_default_layer_config(obj_idx);
|
||||
add_layer_item(new_range, layers_item);
|
||||
|
@ -2377,22 +2505,28 @@ void ObjectList::add_layer_range_after_current(const t_layer_height_range& curre
|
|||
|
||||
t_layer_height_range new_range = { midl_layer, next_range.second };
|
||||
|
||||
take_snapshot(_(L("Add New Layers Range")));
|
||||
suppress_snapshots();
|
||||
|
||||
// create new 2 layers instead of deleted one
|
||||
|
||||
// delete old layer
|
||||
|
||||
wxDataViewItem layer_item = m_objects_model->GetItemByLayerRange(obj_idx, next_range);
|
||||
del_subobject_item(layer_item);
|
||||
|
||||
// create new 2 layers instead of deleted one
|
||||
|
||||
ranges[new_range] = old_config;
|
||||
add_layer_item(new_range, layers_item, layer_idx);
|
||||
|
||||
new_range = { current_range.second, midl_layer };
|
||||
ranges[new_range] = get_default_layer_config(obj_idx);
|
||||
add_layer_item(new_range, layers_item, layer_idx);
|
||||
allow_snapshots();
|
||||
}
|
||||
else
|
||||
{
|
||||
take_snapshot(_(L("Add New Layers Range")));
|
||||
|
||||
const t_layer_height_range new_range = { current_range.second, next_range.first };
|
||||
ranges[new_range] = get_default_layer_config(obj_idx);
|
||||
add_layer_item(new_range, layers_item, layer_idx);
|
||||
|
@ -2420,9 +2554,7 @@ void ObjectList::add_layer_item(const t_layer_height_range& range,
|
|||
range,
|
||||
config.opt_int("extruder"),
|
||||
layer_idx);
|
||||
|
||||
if (config.keys().size() > 2)
|
||||
select_item(m_objects_model->AddSettingsChild(layer_item));
|
||||
add_settings_item(layer_item, &config);
|
||||
}
|
||||
|
||||
bool ObjectList::edit_layer_range(const t_layer_height_range& range, coordf_t layer_height)
|
||||
|
@ -2452,6 +2584,8 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_lay
|
|||
const int obj_idx = get_selected_obj_idx();
|
||||
if (obj_idx < 0) return false;
|
||||
|
||||
take_snapshot(_(L("Edit Layers Range")));
|
||||
|
||||
const ItemType sel_type = m_objects_model->GetItemType(GetSelection());
|
||||
|
||||
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||
|
@ -2918,6 +3052,8 @@ void ObjectList::change_part_type()
|
|||
if (new_type == type || new_type == ModelVolumeType::INVALID)
|
||||
return;
|
||||
|
||||
take_snapshot(_(L("Paste from Clipboard")));
|
||||
|
||||
const auto item = GetSelection();
|
||||
volume->set_type(new_type);
|
||||
m_objects_model->SetVolumeType(item, new_type);
|
||||
|
@ -2933,18 +3069,17 @@ void ObjectList::change_part_type()
|
|||
}
|
||||
else if (!settings_item &&
|
||||
(new_type == ModelVolumeType::MODEL_PART || new_type == ModelVolumeType::PARAMETER_MODIFIER)) {
|
||||
select_item(m_objects_model->AddSettingsChild(item));
|
||||
add_settings_item(item, &volume->config);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectList::last_volume_is_deleted(const int obj_idx)
|
||||
{
|
||||
|
||||
if (obj_idx < 0 || m_objects->empty() ||
|
||||
obj_idx <= m_objects->size() ||
|
||||
(*m_objects)[obj_idx]->volumes.empty())
|
||||
if (obj_idx < 0 || obj_idx >= m_objects->size() || (*m_objects)[obj_idx]->volumes.empty())
|
||||
return;
|
||||
auto volume = (*m_objects)[obj_idx]->volumes[0];
|
||||
|
||||
auto volume = (*m_objects)[obj_idx]->volumes.front();
|
||||
|
||||
// clear volume's config values
|
||||
volume->config.clear();
|
||||
|
@ -2966,6 +3101,7 @@ bool ObjectList::has_multi_part_objects()
|
|||
return false;
|
||||
}
|
||||
|
||||
/* #lm_FIXME_delete_after_testing
|
||||
void ObjectList::update_settings_items()
|
||||
{
|
||||
m_prevent_canvas_selection_update = true;
|
||||
|
@ -2991,22 +3127,52 @@ void ObjectList::update_settings_items()
|
|||
SetSelections(sel);
|
||||
m_prevent_canvas_selection_update = false;
|
||||
}
|
||||
*/
|
||||
void ObjectList::update_and_show_object_settings_item()
|
||||
{
|
||||
const wxDataViewItem item = GetSelection();
|
||||
if (!item) return;
|
||||
|
||||
const wxDataViewItem& obj_item = m_objects_model->IsSettingsItem(item) ? m_objects_model->GetParent(item) : item;
|
||||
select_item(add_settings_item(obj_item, &get_item_config(obj_item)));
|
||||
}
|
||||
|
||||
// Update settings item for item had it
|
||||
void ObjectList::update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections)
|
||||
{
|
||||
const wxDataViewItem& settings_item = m_objects_model->GetSettingsItem(item);
|
||||
select_item(settings_item ? settings_item : m_objects_model->AddSettingsChild(item));
|
||||
const wxDataViewItem old_settings_item = m_objects_model->GetSettingsItem(item);
|
||||
const wxDataViewItem new_settings_item = add_settings_item(item, &get_item_config(item));
|
||||
|
||||
if (!new_settings_item && old_settings_item)
|
||||
m_objects_model->Delete(old_settings_item);
|
||||
|
||||
// if ols settings item was is selected area
|
||||
if (selections.Index(old_settings_item) != wxNOT_FOUND)
|
||||
{
|
||||
// If settings item was just updated
|
||||
if (old_settings_item == new_settings_item)
|
||||
{
|
||||
Sidebar& panel = wxGetApp().sidebar();
|
||||
panel.Freeze();
|
||||
|
||||
// update settings list
|
||||
wxGetApp().obj_settings()->UpdateAndShow(true);
|
||||
|
||||
panel.Layout();
|
||||
panel.Thaw();
|
||||
}
|
||||
else
|
||||
// If settings item was deleted from the list,
|
||||
// it's need to be deleted from selection array, if it was there
|
||||
if (settings_item != m_objects_model->GetSettingsItem(item) &&
|
||||
selections.Index(settings_item) != wxNOT_FOUND) {
|
||||
selections.Remove(settings_item);
|
||||
{
|
||||
selections.Remove(old_settings_item);
|
||||
|
||||
// Select item, if settings_item doesn't exist for item anymore, but was selected
|
||||
if (selections.Index(item) == wxNOT_FOUND)
|
||||
if (selections.Index(item) == wxNOT_FOUND) {
|
||||
selections.Add(item);
|
||||
select_item(item); // to correct update of the SettingsList and ManipulationPanel sizers
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3360,6 +3526,35 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const
|
|||
wxGetApp().plater()->update();
|
||||
}
|
||||
|
||||
void ObjectList::update_after_undo_redo()
|
||||
{
|
||||
m_prevent_list_events = true;
|
||||
m_prevent_canvas_selection_update = true;
|
||||
|
||||
suppress_snapshots();
|
||||
|
||||
// Unselect all objects before deleting them, so that no change of selection is emitted during deletion.
|
||||
this->UnselectAll();
|
||||
m_objects_model->DeleteAll();
|
||||
|
||||
size_t obj_idx = 0;
|
||||
while (obj_idx < m_objects->size()) {
|
||||
add_object_to_list(obj_idx, false);
|
||||
++obj_idx;
|
||||
}
|
||||
|
||||
allow_snapshots();
|
||||
|
||||
#ifndef __WXOSX__
|
||||
selection_changed();
|
||||
#endif /* __WXOSX__ */
|
||||
|
||||
update_selections();
|
||||
|
||||
m_prevent_canvas_selection_update = false;
|
||||
m_prevent_list_events = false;
|
||||
}
|
||||
|
||||
ModelObject* ObjectList::object(const int obj_idx) const
|
||||
{
|
||||
if (obj_idx < 0)
|
||||
|
|
|
@ -26,7 +26,7 @@ enum class ModelVolumeType : int;
|
|||
// FIXME: broken build on mac os because of this is missing:
|
||||
typedef std::vector<std::string> t_config_option_keys;
|
||||
|
||||
typedef std::map<std::string, std::vector<std::string>> FreqSettingsBundle;
|
||||
typedef std::map<std::string, std::vector<std::string>> SettingsBundle;
|
||||
|
||||
// category -> vector ( option ; label )
|
||||
typedef std::map< std::string, std::vector< std::pair<std::string, std::string> > > settings_menu_hierarchy;
|
||||
|
@ -152,8 +152,8 @@ class ObjectList : public wxDataViewCtrl
|
|||
wxDataViewItem m_last_selected_item {nullptr};
|
||||
|
||||
#if 0
|
||||
FreqSettingsBundle m_freq_settings_fff;
|
||||
FreqSettingsBundle m_freq_settings_sla;
|
||||
SettingsBundle m_freq_settings_fff;
|
||||
SettingsBundle m_freq_settings_sla;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
@ -204,10 +204,12 @@ public:
|
|||
|
||||
void copy();
|
||||
void paste();
|
||||
void undo();
|
||||
void redo();
|
||||
|
||||
void get_settings_choice(const wxString& category_name);
|
||||
void get_freq_settings_choice(const wxString& bundle_name);
|
||||
void update_settings_item();
|
||||
void show_settings(const wxDataViewItem settings_item);
|
||||
|
||||
wxMenu* append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type);
|
||||
void append_menu_items_add_volume(wxMenu* menu);
|
||||
|
@ -245,6 +247,7 @@ public:
|
|||
void layers_editing();
|
||||
|
||||
wxDataViewItem add_layer_root_item(const wxDataViewItem obj_item);
|
||||
wxDataViewItem add_settings_item(wxDataViewItem parent_item, const DynamicPrintConfig* config);
|
||||
|
||||
DynamicPrintConfig get_default_layer_config(const int obj_idx);
|
||||
bool get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume);
|
||||
|
@ -256,12 +259,13 @@ public:
|
|||
wxBoxSizer* get_sizer() {return m_sizer;}
|
||||
int get_selected_obj_idx() const;
|
||||
DynamicPrintConfig& get_item_config(const wxDataViewItem& item) const;
|
||||
SettingsBundle get_item_settings_bundle(const DynamicPrintConfig* config, const bool is_layers_range_settings);
|
||||
|
||||
void changed_object(const int obj_idx = -1) const;
|
||||
void part_selection_changed();
|
||||
|
||||
// Add object to the list
|
||||
void add_object_to_list(size_t obj_idx);
|
||||
void add_object_to_list(size_t obj_idx, bool call_selection_changed = true);
|
||||
// Delete object from the list
|
||||
void delete_object_from_list();
|
||||
void delete_object_from_list(const size_t obj_idx);
|
||||
|
@ -315,6 +319,7 @@ public:
|
|||
void last_volume_is_deleted(const int obj_idx);
|
||||
bool has_multi_part_objects();
|
||||
void update_settings_items();
|
||||
void update_and_show_object_settings_item();
|
||||
void update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections);
|
||||
void update_object_list_by_printer_technology();
|
||||
void update_object_menu();
|
||||
|
@ -333,6 +338,8 @@ public:
|
|||
|
||||
void msw_rescale();
|
||||
|
||||
void update_after_undo_redo();
|
||||
|
||||
private:
|
||||
#ifdef __WXOSX__
|
||||
// void OnChar(wxKeyEvent& event);
|
||||
|
|
|
@ -242,8 +242,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL);
|
||||
selection.synchronize_unselected_volumes();
|
||||
// Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
|
||||
canvas->do_mirror();
|
||||
canvas->set_as_dirty();
|
||||
canvas->do_mirror("Set Mirror");
|
||||
UpdateAndShow(true);
|
||||
});
|
||||
return sizer;
|
||||
|
@ -324,7 +323,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL);
|
||||
selection.synchronize_unselected_volumes();
|
||||
// Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
|
||||
canvas->do_rotate();
|
||||
canvas->do_rotate("Set Rotation");
|
||||
|
||||
UpdateAndShow(true);
|
||||
});
|
||||
|
@ -710,7 +709,7 @@ void ObjectManipulation::change_position_value(int axis, double value)
|
|||
Selection& selection = canvas->get_selection();
|
||||
selection.start_dragging();
|
||||
selection.translate(position - m_cache.position, selection.requires_local_axes());
|
||||
canvas->do_move();
|
||||
canvas->do_move("Set Position");
|
||||
|
||||
m_cache.position = position;
|
||||
m_cache.position_rounded(axis) = DBL_MAX;
|
||||
|
@ -741,7 +740,7 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
|
|||
selection.rotate(
|
||||
(M_PI / 180.0) * (transformation_type.absolute() ? rotation : rotation - m_cache.rotation),
|
||||
transformation_type);
|
||||
canvas->do_rotate();
|
||||
canvas->do_rotate("Set Orientation");
|
||||
|
||||
m_cache.rotation = rotation;
|
||||
m_cache.rotation_rounded(axis) = DBL_MAX;
|
||||
|
@ -806,7 +805,7 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
|
|||
|
||||
selection.start_dragging();
|
||||
selection.scale(scaling_factor * 0.01, transformation_type);
|
||||
wxGetApp().plater()->canvas3D()->do_scale();
|
||||
wxGetApp().plater()->canvas3D()->do_scale("Set Scale");
|
||||
}
|
||||
|
||||
void ObjectManipulation::on_change(t_config_option_key opt_key, const boost::any& value)
|
||||
|
|
|
@ -63,20 +63,28 @@ ObjectSettings::ObjectSettings(wxWindow* parent) :
|
|||
m_bmp_delete = ScalableBitmap(parent, "cross");
|
||||
}
|
||||
|
||||
void ObjectSettings::update_settings_list()
|
||||
bool ObjectSettings::update_settings_list()
|
||||
{
|
||||
m_settings_list_sizer->Clear(true);
|
||||
m_og_settings.resize(0);
|
||||
|
||||
auto objects_ctrl = wxGetApp().obj_list();
|
||||
auto objects_model = wxGetApp().obj_list()->GetModel();
|
||||
auto config = wxGetApp().obj_list()->config();
|
||||
|
||||
const auto item = objects_ctrl->GetSelection();
|
||||
const bool is_layers_range_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itLayer;
|
||||
|
||||
if (item && !objects_ctrl->multiple_selection() &&
|
||||
config && objects_model->IsSettingsItem(item))
|
||||
if (!item || !objects_model->IsSettingsItem(item) || !config || objects_ctrl->multiple_selection())
|
||||
return false;
|
||||
|
||||
const bool is_layers_range_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itLayer;
|
||||
SettingsBundle cat_options = objects_ctrl->get_item_settings_bundle(config, is_layers_range_settings);
|
||||
|
||||
if (!cat_options.empty())
|
||||
{
|
||||
std::vector<std::string> categories;
|
||||
categories.reserve(cat_options.size());
|
||||
|
||||
auto extra_column = [config, this](wxWindow* parent, const Line& line)
|
||||
{
|
||||
auto opt_key = (line.get_options())[0].opt_id; //we assume that we have one option per line
|
||||
|
@ -96,35 +104,14 @@ void ObjectSettings::update_settings_list()
|
|||
return btn;
|
||||
};
|
||||
|
||||
std::map<std::string, std::vector<std::string>> cat_options;
|
||||
auto opt_keys = config->keys();
|
||||
objects_ctrl->update_opt_keys(opt_keys); // update options list according to print technology
|
||||
|
||||
m_og_settings.resize(0);
|
||||
std::vector<std::string> categories;
|
||||
if (!(opt_keys.size() == 1 && opt_keys[0] == "extruder"))// return;
|
||||
for (auto& cat : cat_options)
|
||||
{
|
||||
const int extruders_cnt = wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA ? 1 :
|
||||
wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
|
||||
|
||||
for (auto& opt_key : opt_keys) {
|
||||
auto category = config->def()->get(opt_key)->category;
|
||||
if (category.empty() ||
|
||||
(category == "Extruders" && extruders_cnt == 1)) continue;
|
||||
|
||||
std::vector< std::string > new_category;
|
||||
|
||||
auto& cat_opt = cat_options.find(category) == cat_options.end() ? new_category : cat_options.at(category);
|
||||
cat_opt.push_back(opt_key);
|
||||
if (cat_opt.size() == 1)
|
||||
cat_options[category] = cat_opt;
|
||||
}
|
||||
|
||||
for (auto& cat : cat_options) {
|
||||
if (cat.second.size() == 1 &&
|
||||
(cat.second[0] == "extruder" || is_layers_range_settings && cat.second[0] == "layer_height"))
|
||||
continue;
|
||||
|
||||
categories.push_back(cat.first);
|
||||
|
||||
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), _(cat.first), config, false, extra_column);
|
||||
optgroup->label_width = 15;
|
||||
optgroup->sidetext_width = 5.5;
|
||||
|
@ -132,20 +119,6 @@ void ObjectSettings::update_settings_list()
|
|||
optgroup->m_on_change = [](const t_config_option_key& opt_id, const boost::any& value) {
|
||||
wxGetApp().obj_list()->changed_object(); };
|
||||
|
||||
const bool is_extruders_cat = cat.first == "Extruders";
|
||||
for (auto& opt : cat.second)
|
||||
{
|
||||
if (opt == "extruder" || is_layers_range_settings && opt == "layer_height")
|
||||
continue;
|
||||
Option option = optgroup->get_option(opt);
|
||||
option.opt.width = 12;
|
||||
if (is_extruders_cat)
|
||||
option.opt.max = wxGetApp().extruders_cnt();
|
||||
optgroup->append_single_option_line(option);
|
||||
}
|
||||
optgroup->reload_config();
|
||||
m_settings_list_sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 0);
|
||||
|
||||
// call back for rescaling of the extracolumn control
|
||||
optgroup->rescale_extra_column_item = [this](wxWindow* win) {
|
||||
auto *ctrl = dynamic_cast<ScalableButton*>(win);
|
||||
|
@ -154,28 +127,38 @@ void ObjectSettings::update_settings_list()
|
|||
ctrl->SetBitmap_(m_bmp_delete);
|
||||
};
|
||||
|
||||
const bool is_extruders_cat = cat.first == "Extruders";
|
||||
for (auto& opt : cat.second)
|
||||
{
|
||||
if (opt == "extruder" || is_layers_range_settings && opt == "layer_height")
|
||||
continue;
|
||||
Option option = optgroup->get_option(opt);
|
||||
option.opt.width = 12;
|
||||
if (is_extruders_cat)
|
||||
option.opt.max = wxGetApp().extruders_edited_cnt();
|
||||
optgroup->append_single_option_line(option);
|
||||
}
|
||||
optgroup->reload_config();
|
||||
|
||||
m_settings_list_sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 0);
|
||||
m_og_settings.push_back(optgroup);
|
||||
|
||||
categories.push_back(cat.first);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_og_settings.empty()) {
|
||||
objects_ctrl->select_item(objects_model->Delete(item));
|
||||
}
|
||||
else {
|
||||
if (!categories.empty())
|
||||
objects_model->UpdateSettingsDigest(item, categories);
|
||||
}
|
||||
else
|
||||
{
|
||||
objects_ctrl->select_item(objects_model->Delete(item));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ObjectSettings::UpdateAndShow(const bool show)
|
||||
{
|
||||
if (show)
|
||||
update_settings_list();
|
||||
|
||||
OG_Settings::UpdateAndShow(show);
|
||||
OG_Settings::UpdateAndShow(show ? update_settings_list() : false);
|
||||
}
|
||||
|
||||
void ObjectSettings::msw_rescale()
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
ObjectSettings(wxWindow* parent);
|
||||
~ObjectSettings() {}
|
||||
|
||||
void update_settings_list();
|
||||
bool update_settings_list();
|
||||
void UpdateAndShow(const bool show) override;
|
||||
void msw_rescale();
|
||||
};
|
||||
|
|
|
@ -132,6 +132,7 @@ void GLGizmoBase::Grabber::render_face(float half_size) const
|
|||
glsafe(::glEnd());
|
||||
}
|
||||
|
||||
|
||||
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: m_parent(parent)
|
||||
, m_group_id(-1)
|
||||
|
@ -179,7 +180,7 @@ void GLGizmoBase::disable_grabber(unsigned int id)
|
|||
on_disable_grabber(id);
|
||||
}
|
||||
|
||||
void GLGizmoBase::start_dragging(const Selection& selection)
|
||||
void GLGizmoBase::start_dragging()
|
||||
{
|
||||
m_dragging = true;
|
||||
|
||||
|
@ -188,7 +189,7 @@ void GLGizmoBase::start_dragging(const Selection& selection)
|
|||
m_grabbers[i].dragging = (m_hover_id == i);
|
||||
}
|
||||
|
||||
on_start_dragging(selection);
|
||||
on_start_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoBase::stop_dragging()
|
||||
|
@ -203,10 +204,10 @@ void GLGizmoBase::stop_dragging()
|
|||
on_stop_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoBase::update(const UpdateData& data, const Selection& selection)
|
||||
void GLGizmoBase::update(const UpdateData& data)
|
||||
{
|
||||
if (m_hover_id != -1)
|
||||
on_update(data, selection);
|
||||
on_update(data);
|
||||
}
|
||||
|
||||
std::array<float, 3> GLGizmoBase::picking_color_component(unsigned int id) const
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/Selection.hpp"
|
||||
|
||||
#include <cereal/archives/binary.hpp>
|
||||
|
||||
class wxWindow;
|
||||
class GLUquadric;
|
||||
|
@ -75,10 +76,10 @@ public:
|
|||
|
||||
struct UpdateData
|
||||
{
|
||||
const Linef3 mouse_ray;
|
||||
const Point* mouse_pos;
|
||||
const Linef3& mouse_ray;
|
||||
const Point& mouse_pos;
|
||||
|
||||
UpdateData(const Linef3& mouse_ray, const Point* mouse_pos = nullptr)
|
||||
UpdateData(const Linef3& mouse_ray, const Point& mouse_pos)
|
||||
: mouse_ray(mouse_ray), mouse_pos(mouse_pos)
|
||||
{}
|
||||
};
|
||||
|
@ -105,6 +106,9 @@ public:
|
|||
|
||||
bool init() { return on_init(); }
|
||||
|
||||
void load(cereal::BinaryInputArchive& ar) { m_state = On; on_load(ar); }
|
||||
void save(cereal::BinaryOutputArchive& ar) const { on_save(ar); }
|
||||
|
||||
std::string get_name() const { return on_get_name(); }
|
||||
|
||||
int get_group_id() const { return m_group_id; }
|
||||
|
@ -118,7 +122,7 @@ public:
|
|||
|
||||
const std::string& get_icon_filename() const { return m_icon_filename; }
|
||||
|
||||
bool is_activable(const Selection& selection) const { return on_is_activable(selection); }
|
||||
bool is_activable() const { return on_is_activable(); }
|
||||
bool is_selectable() const { return on_is_selectable(); }
|
||||
|
||||
unsigned int get_sprite_id() const { return m_sprite_id; }
|
||||
|
@ -131,32 +135,34 @@ public:
|
|||
void enable_grabber(unsigned int id);
|
||||
void disable_grabber(unsigned int id);
|
||||
|
||||
void start_dragging(const Selection& selection);
|
||||
void start_dragging();
|
||||
void stop_dragging();
|
||||
|
||||
bool is_dragging() const { return m_dragging; }
|
||||
|
||||
void update(const UpdateData& data, const Selection& selection);
|
||||
void update(const UpdateData& data);
|
||||
|
||||
void render(const Selection& selection) const { on_render(selection); }
|
||||
void render_for_picking(const Selection& selection) const { on_render_for_picking(selection); }
|
||||
void render_input_window(float x, float y, float bottom_limit, const Selection& selection) { on_render_input_window(x, y, bottom_limit, selection); }
|
||||
void render() const { on_render(); }
|
||||
void render_for_picking() const { on_render_for_picking(); }
|
||||
void render_input_window(float x, float y, float bottom_limit) { on_render_input_window(x, y, bottom_limit); }
|
||||
|
||||
protected:
|
||||
virtual bool on_init() = 0;
|
||||
virtual void on_load(cereal::BinaryInputArchive& ar) {}
|
||||
virtual void on_save(cereal::BinaryOutputArchive& ar) const {}
|
||||
virtual std::string on_get_name() const = 0;
|
||||
virtual void on_set_state() {}
|
||||
virtual void on_set_hover_id() {}
|
||||
virtual bool on_is_activable(const Selection& selection) const { return true; }
|
||||
virtual bool on_is_activable() const { return true; }
|
||||
virtual bool on_is_selectable() const { return true; }
|
||||
virtual void on_enable_grabber(unsigned int id) {}
|
||||
virtual void on_disable_grabber(unsigned int id) {}
|
||||
virtual void on_start_dragging(const Selection& selection) {}
|
||||
virtual void on_start_dragging() {}
|
||||
virtual void on_stop_dragging() {}
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection) = 0;
|
||||
virtual void on_render(const Selection& selection) const = 0;
|
||||
virtual void on_render_for_picking(const Selection& selection) const = 0;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit, const Selection& selection) {}
|
||||
virtual void on_update(const UpdateData& data) {}
|
||||
virtual void on_render() const = 0;
|
||||
virtual void on_render_for_picking() const = 0;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit) {}
|
||||
|
||||
// Returns the picking color for the given id, based on the BASE_ID constant
|
||||
// No check is made for clashing with other picking color (i.e. GLVolumes)
|
||||
|
|
|
@ -28,7 +28,6 @@ GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, uns
|
|||
, m_rotate_lower(false)
|
||||
{}
|
||||
|
||||
|
||||
bool GLGizmoCut::on_init()
|
||||
{
|
||||
m_grabbers.emplace_back();
|
||||
|
@ -49,15 +48,18 @@ void GLGizmoCut::on_set_state()
|
|||
}
|
||||
}
|
||||
|
||||
bool GLGizmoCut::on_is_activable(const Selection& selection) const
|
||||
bool GLGizmoCut::on_is_activable() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
return selection.is_single_full_instance() && !selection.is_wipe_tower();
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_start_dragging(const Selection& selection)
|
||||
void GLGizmoCut::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id == -1) { return; }
|
||||
if (m_hover_id == -1)
|
||||
return;
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
m_start_z = m_cut_z;
|
||||
update_max_z(selection);
|
||||
|
@ -66,19 +68,21 @@ void GLGizmoCut::on_start_dragging(const Selection& selection)
|
|||
m_drag_center(2) = m_cut_z;
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_update(const UpdateData& data, const Selection& selection)
|
||||
void GLGizmoCut::on_update(const UpdateData& data)
|
||||
{
|
||||
if (m_hover_id != -1) {
|
||||
set_cut_z(m_start_z + calc_projection(data.mouse_ray));
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_render(const Selection& selection) const
|
||||
void GLGizmoCut::on_render() const
|
||||
{
|
||||
if (m_grabbers[0].dragging) {
|
||||
set_tooltip("Z: " + format(m_cut_z, 2));
|
||||
}
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
update_max_z(selection);
|
||||
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
|
@ -124,14 +128,13 @@ void GLGizmoCut::on_render(const Selection& selection) const
|
|||
m_grabbers[0].render(m_hover_id == 0, (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0));
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_render_for_picking(const Selection& selection) const
|
||||
void GLGizmoCut::on_render_for_picking() const
|
||||
{
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
render_grabbers_for_picking(selection.get_bounding_box());
|
||||
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection)
|
||||
void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
const float approx_height = m_imgui->scaled(11.0f);
|
||||
y = std::min(y, bottom_limit - approx_height);
|
||||
|
@ -154,7 +157,7 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, co
|
|||
m_imgui->end();
|
||||
|
||||
if (cut_clicked && (m_keep_upper || m_keep_lower)) {
|
||||
perform_cut(selection);
|
||||
perform_cut(m_parent.get_selection());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,14 +27,16 @@ public:
|
|||
|
||||
protected:
|
||||
virtual bool on_init();
|
||||
virtual void on_load(cereal::BinaryInputArchive& ar) { ar(m_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower); }
|
||||
virtual void on_save(cereal::BinaryOutputArchive& ar) const { ar(m_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower); }
|
||||
virtual std::string on_get_name() const;
|
||||
virtual void on_set_state();
|
||||
virtual bool on_is_activable(const Selection& selection) const;
|
||||
virtual void on_start_dragging(const Selection& selection);
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection);
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit, const Selection& selection);
|
||||
virtual bool on_is_activable() const;
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_update(const UpdateData& data);
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit);
|
||||
|
||||
private:
|
||||
void update_max_z(const Selection& selection) const;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
#include "GLGizmoFlatten.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
#include <numeric>
|
||||
|
||||
|
@ -27,23 +28,25 @@ std::string GLGizmoFlatten::on_get_name() const
|
|||
return (_(L("Place on face")) + " [F]").ToUTF8().data();
|
||||
}
|
||||
|
||||
bool GLGizmoFlatten::on_is_activable(const Selection& selection) const
|
||||
bool GLGizmoFlatten::on_is_activable() const
|
||||
{
|
||||
return selection.is_single_full_instance();
|
||||
return m_parent.get_selection().is_single_full_instance();
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::on_start_dragging(const Selection& selection)
|
||||
void GLGizmoFlatten::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1)
|
||||
{
|
||||
assert(m_planes_valid);
|
||||
m_normal = m_planes[m_hover_id].normal;
|
||||
m_starting_center = selection.get_bounding_box().center();
|
||||
m_starting_center = m_parent.get_selection().get_bounding_box().center();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::on_render(const Selection& selection) const
|
||||
void GLGizmoFlatten::on_render() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
@ -78,8 +81,10 @@ void GLGizmoFlatten::on_render(const Selection& selection) const
|
|||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::on_render_for_picking(const Selection& selection) const
|
||||
void GLGizmoFlatten::on_render_for_picking() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
||||
|
|
|
@ -45,11 +45,10 @@ public:
|
|||
protected:
|
||||
virtual bool on_init();
|
||||
virtual std::string on_get_name() const;
|
||||
virtual bool on_is_activable(const Selection& selection) const;
|
||||
virtual void on_start_dragging(const Selection& selection);
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection) {}
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const;
|
||||
virtual bool on_is_activable() const;
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
virtual void on_set_state()
|
||||
{
|
||||
if (m_state == On && is_plane_update_necessary())
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
#include "GLGizmoMove.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
@ -47,12 +48,12 @@ std::string GLGizmoMove3D::on_get_name() const
|
|||
return (_(L("Move")) + " [M]").ToUTF8().data();
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_start_dragging(const Selection& selection)
|
||||
void GLGizmoMove3D::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1)
|
||||
{
|
||||
m_displacement = Vec3d::Zero();
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
|
||||
m_starting_drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting_box_center = box.center();
|
||||
m_starting_box_bottom_center = box.center();
|
||||
|
@ -65,7 +66,7 @@ void GLGizmoMove3D::on_stop_dragging()
|
|||
m_displacement = Vec3d::Zero();
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_update(const UpdateData& data, const Selection& selection)
|
||||
void GLGizmoMove3D::on_update(const UpdateData& data)
|
||||
{
|
||||
if (m_hover_id == 0)
|
||||
m_displacement(0) = calc_projection(data);
|
||||
|
@ -75,8 +76,10 @@ void GLGizmoMove3D::on_update(const UpdateData& data, const Selection& selection
|
|||
m_displacement(2) = calc_projection(data);
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_render(const Selection& selection) const
|
||||
void GLGizmoMove3D::on_render() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
bool show_position = selection.is_single_full_instance();
|
||||
const Vec3d& position = selection.get_bounding_box().center();
|
||||
|
||||
|
@ -152,20 +155,21 @@ void GLGizmoMove3D::on_render(const Selection& selection) const
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_render_for_picking(const Selection& selection) const
|
||||
void GLGizmoMove3D::on_render_for_picking() const
|
||||
{
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
|
||||
render_grabbers_for_picking(box);
|
||||
render_grabber_extension(X, box, true);
|
||||
render_grabber_extension(Y, box, true);
|
||||
render_grabber_extension(Z, box, true);
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection)
|
||||
{
|
||||
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
void GLGizmoMove3D::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
bool show_position = selection.is_single_full_instance();
|
||||
const Vec3d& position = selection.get_bounding_box().center();
|
||||
|
||||
|
@ -178,8 +182,8 @@ void GLGizmoMove3D::on_render_input_window(float x, float y, float bottom_limit,
|
|||
m_imgui->input_vec3("", displacement, 100.0f, "%.2f");
|
||||
|
||||
m_imgui->end();
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
}
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
|
||||
double GLGizmoMove3D::calc_projection(const UpdateData& data) const
|
||||
{
|
||||
|
|
|
@ -33,12 +33,14 @@ public:
|
|||
protected:
|
||||
virtual bool on_init();
|
||||
virtual std::string on_get_name() const;
|
||||
virtual void on_start_dragging(const Selection& selection);
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_stop_dragging();
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection);
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit, const Selection& selection);
|
||||
virtual void on_update(const UpdateData& data);
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit);
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
|
||||
private:
|
||||
double calc_projection(const UpdateData& data) const;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
#include "GLGizmoRotate.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
@ -72,9 +73,9 @@ bool GLGizmoRotate::on_init()
|
|||
return true;
|
||||
}
|
||||
|
||||
void GLGizmoRotate::on_start_dragging(const Selection& selection)
|
||||
void GLGizmoRotate::on_start_dragging()
|
||||
{
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
|
||||
m_center = box.center();
|
||||
m_radius = Offset + box.radius();
|
||||
m_snap_coarse_in_radius = m_radius / 3.0f;
|
||||
|
@ -83,9 +84,9 @@ void GLGizmoRotate::on_start_dragging(const Selection& selection)
|
|||
m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth;
|
||||
}
|
||||
|
||||
void GLGizmoRotate::on_update(const UpdateData& data, const Selection& selection)
|
||||
void GLGizmoRotate::on_update(const UpdateData& data)
|
||||
{
|
||||
Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray, selection));
|
||||
Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray, m_parent.get_selection()));
|
||||
|
||||
Vec2d orig_dir = Vec2d::UnitX();
|
||||
Vec2d new_dir = mouse_pos.normalized();
|
||||
|
@ -118,11 +119,12 @@ void GLGizmoRotate::on_update(const UpdateData& data, const Selection& selection
|
|||
m_angle = theta;
|
||||
}
|
||||
|
||||
void GLGizmoRotate::on_render(const Selection& selection) const
|
||||
void GLGizmoRotate::on_render() const
|
||||
{
|
||||
if (!m_grabbers[0].enabled)
|
||||
return;
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
|
||||
std::string axis;
|
||||
|
@ -175,8 +177,10 @@ void GLGizmoRotate::on_render(const Selection& selection) const
|
|||
glsafe(::glPopMatrix());
|
||||
}
|
||||
|
||||
void GLGizmoRotate::on_render_for_picking(const Selection& selection) const
|
||||
void GLGizmoRotate::on_render_for_picking() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
glsafe(::glPushMatrix());
|
||||
|
@ -445,10 +449,10 @@ std::string GLGizmoRotate3D::on_get_name() const
|
|||
return (_(L("Rotate")) + " [R]").ToUTF8().data();
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::on_start_dragging(const Selection& selection)
|
||||
void GLGizmoRotate3D::on_start_dragging()
|
||||
{
|
||||
if ((0 <= m_hover_id) && (m_hover_id < 3))
|
||||
m_gizmos[m_hover_id].start_dragging(selection);
|
||||
m_gizmos[m_hover_id].start_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::on_stop_dragging()
|
||||
|
@ -457,23 +461,23 @@ void GLGizmoRotate3D::on_stop_dragging()
|
|||
m_gizmos[m_hover_id].stop_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::on_render(const Selection& selection) const
|
||||
void GLGizmoRotate3D::on_render() const
|
||||
{
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
if ((m_hover_id == -1) || (m_hover_id == 0))
|
||||
m_gizmos[X].render(selection);
|
||||
m_gizmos[X].render();
|
||||
|
||||
if ((m_hover_id == -1) || (m_hover_id == 1))
|
||||
m_gizmos[Y].render(selection);
|
||||
m_gizmos[Y].render();
|
||||
|
||||
if ((m_hover_id == -1) || (m_hover_id == 2))
|
||||
m_gizmos[Z].render(selection);
|
||||
m_gizmos[Z].render();
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection)
|
||||
{
|
||||
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
Vec3d rotation(Geometry::rad2deg(m_gizmos[0].get_angle()), Geometry::rad2deg(m_gizmos[1].get_angle()), Geometry::rad2deg(m_gizmos[2].get_angle()));
|
||||
wxString label = _(L("Rotation (deg)"));
|
||||
|
||||
|
@ -482,8 +486,8 @@ void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limi
|
|||
m_imgui->begin(label, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
m_imgui->input_vec3("", rotation, 100.0f, "%.2f");
|
||||
m_imgui->end();
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
}
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -52,10 +52,10 @@ public:
|
|||
protected:
|
||||
virtual bool on_init();
|
||||
virtual std::string on_get_name() const { return ""; }
|
||||
virtual void on_start_dragging(const Selection& selection);
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection);
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const;
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_update(const UpdateData& data);
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
|
||||
private:
|
||||
void render_circle() const;
|
||||
|
@ -98,7 +98,6 @@ protected:
|
|||
m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1);
|
||||
}
|
||||
}
|
||||
virtual bool on_is_activable(const Selection& selection) const { return true; }
|
||||
virtual void on_enable_grabber(unsigned int id)
|
||||
{
|
||||
if ((0 <= id) && (id < 3))
|
||||
|
@ -109,25 +108,26 @@ protected:
|
|||
if ((0 <= id) && (id < 3))
|
||||
m_gizmos[id].disable_grabber(0);
|
||||
}
|
||||
virtual void on_start_dragging(const Selection& selection);
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_stop_dragging();
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection)
|
||||
virtual void on_update(const UpdateData& data)
|
||||
{
|
||||
for (GLGizmoRotate& g : m_gizmos)
|
||||
{
|
||||
g.update(data, selection);
|
||||
g.update(data);
|
||||
}
|
||||
}
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const
|
||||
{
|
||||
for (const GLGizmoRotate& g : m_gizmos)
|
||||
{
|
||||
g.render_for_picking(selection);
|
||||
g.render_for_picking();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit, const Selection& selection);
|
||||
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit);
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
|
||||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
#include "GLGizmoScale.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
@ -48,13 +47,18 @@ std::string GLGizmoScale3D::on_get_name() const
|
|||
return (_(L("Scale")) + " [S]").ToUTF8().data();
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_start_dragging(const Selection& selection)
|
||||
bool GLGizmoScale3D::on_is_activable() const
|
||||
{
|
||||
return !m_parent.get_selection().is_wipe_tower();
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1)
|
||||
{
|
||||
m_starting.drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
|
||||
m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : selection.get_bounding_box();
|
||||
m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : m_parent.get_selection().get_bounding_box();
|
||||
|
||||
const Vec3d& center = m_starting.box.center();
|
||||
m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max(0), center(1), center(2));
|
||||
|
@ -66,7 +70,7 @@ void GLGizmoScale3D::on_start_dragging(const Selection& selection)
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_update(const UpdateData& data, const Selection& selection)
|
||||
void GLGizmoScale3D::on_update(const UpdateData& data)
|
||||
{
|
||||
if ((m_hover_id == 0) || (m_hover_id == 1))
|
||||
do_scale_along_axis(X, data);
|
||||
|
@ -78,8 +82,10 @@ void GLGizmoScale3D::on_update(const UpdateData& data, const Selection& selectio
|
|||
do_scale_uniform(data);
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_render(const Selection& selection) const
|
||||
void GLGizmoScale3D::on_render() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
bool single_instance = selection.is_single_full_instance();
|
||||
bool single_volume = selection.is_single_modifier() || selection.is_single_volume();
|
||||
bool single_selection = single_instance || single_volume;
|
||||
|
@ -272,16 +278,16 @@ void GLGizmoScale3D::on_render(const Selection& selection) const
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_render_for_picking(const Selection& selection) const
|
||||
void GLGizmoScale3D::on_render_for_picking() const
|
||||
{
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
render_grabbers_for_picking(selection.get_bounding_box());
|
||||
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection)
|
||||
{
|
||||
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
void GLGizmoScale3D::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
bool single_instance = selection.is_single_full_instance();
|
||||
wxString label = _(L("Scale (%)"));
|
||||
|
||||
|
@ -290,8 +296,8 @@ void GLGizmoScale3D::on_render_input_window(float x, float y, float bottom_limit
|
|||
m_imgui->begin(label, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
m_imgui->input_vec3("", m_scale * 100.f, 100.0f, "%.2f");
|
||||
m_imgui->end();
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
}
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
|
||||
void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2) const
|
||||
{
|
||||
|
|
|
@ -45,12 +45,14 @@ public:
|
|||
protected:
|
||||
virtual bool on_init();
|
||||
virtual std::string on_get_name() const;
|
||||
virtual bool on_is_activable(const Selection& selection) const { return !selection.is_wipe_tower(); }
|
||||
virtual void on_start_dragging(const Selection& selection);
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection);
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit, const Selection& selection);
|
||||
virtual bool on_is_activable() const;
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_update(const UpdateData& data);
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit);
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
|
||||
private:
|
||||
void render_grabbers_connection(unsigned int id_1, unsigned int id_2) const;
|
||||
|
|
|
@ -94,8 +94,10 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmoSlaSupports::on_render(const Selection& selection) const
|
||||
void GLGizmoSlaSupports::on_render() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
// If current m_model_object does not match selection, ask GLCanvas3D to turn us off
|
||||
if (m_state == On
|
||||
&& (m_model_object != selection.get_model()->objects[selection.get_object_idx()]
|
||||
|
@ -252,8 +254,9 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
|
|||
}
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::on_render_for_picking(const Selection& selection) const
|
||||
void GLGizmoSlaSupports::on_render_for_picking() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
#if ENABLE_RENDER_PICKING_PASS
|
||||
m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z();
|
||||
#endif
|
||||
|
@ -379,7 +382,7 @@ bool GLGizmoSlaSupports::is_point_clipped(const Vec3d& point) const
|
|||
bool GLGizmoSlaSupports::is_mesh_update_necessary() const
|
||||
{
|
||||
return ((m_state == On) && (m_model_object != nullptr) && !m_model_object->instances.empty())
|
||||
&& ((m_model_object->id() != m_current_mesh_model_id) || m_its == nullptr);
|
||||
&& ((m_model_object->id() != m_current_mesh_object_id) || m_its == nullptr);
|
||||
}
|
||||
|
||||
void GLGizmoSlaSupports::update_mesh()
|
||||
|
@ -389,7 +392,7 @@ void GLGizmoSlaSupports::update_mesh()
|
|||
// This mesh does not account for the possible Z up SLA offset.
|
||||
m_mesh = &m_model_object->volumes.front()->mesh();
|
||||
m_its = &m_mesh->its;
|
||||
m_current_mesh_model_id = m_model_object->id();
|
||||
m_current_mesh_object_id = m_model_object->id();
|
||||
m_editing_mode = false;
|
||||
|
||||
m_AABB.deinit();
|
||||
|
@ -702,12 +705,12 @@ void GLGizmoSlaSupports::delete_selected_points(bool force)
|
|||
//m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
|
||||
void GLGizmoSlaSupports::on_update(const UpdateData& data, const Selection& selection)
|
||||
void GLGizmoSlaSupports::on_update(const UpdateData& data)
|
||||
{
|
||||
if (m_editing_mode && m_hover_id != -1 && data.mouse_pos && (!m_editing_mode_cache[m_hover_id].support_point.is_new_island || !m_lock_unique_islands)) {
|
||||
if (m_editing_mode && m_hover_id != -1 && (!m_editing_mode_cache[m_hover_id].support_point.is_new_island || !m_lock_unique_islands)) {
|
||||
std::pair<Vec3f, Vec3f> pos_and_normal;
|
||||
try {
|
||||
pos_and_normal = unproject_on_mesh(Vec2d((*data.mouse_pos)(0), (*data.mouse_pos)(1)));
|
||||
pos_and_normal = unproject_on_mesh(data.mouse_pos.cast<double>());
|
||||
}
|
||||
catch (...) { return; }
|
||||
m_editing_mode_cache[m_hover_id].support_point.pos = pos_and_normal.first;
|
||||
|
@ -822,7 +825,7 @@ void GLGizmoSlaSupports::make_line_segments() const
|
|||
*/
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection)
|
||||
void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
if (!m_model_object)
|
||||
return;
|
||||
|
@ -923,10 +926,12 @@ RENDER_AGAIN:
|
|||
}
|
||||
|
||||
if (value_changed) { // Update side panel
|
||||
wxTheApp->CallAfter([]() {
|
||||
wxGetApp().obj_settings()->UpdateAndShow(true);
|
||||
wxGetApp().obj_list()->update_settings_items();
|
||||
});
|
||||
/* wxTheApp->CallAfter([]() {
|
||||
* wxGetApp().obj_settings()->UpdateAndShow(true);
|
||||
* wxGetApp().obj_list()->update_settings_items();
|
||||
* });
|
||||
* #lm_FIXME_delete_after_testing */
|
||||
wxGetApp().obj_list()->update_and_show_object_settings_item();
|
||||
}
|
||||
|
||||
bool generate = m_imgui->button(m_desc.at("auto_generate"));
|
||||
|
@ -1000,8 +1005,10 @@ RENDER_AGAIN:
|
|||
m_parent.set_as_dirty();
|
||||
}
|
||||
|
||||
bool GLGizmoSlaSupports::on_is_activable(const Selection& selection) const
|
||||
bool GLGizmoSlaSupports::on_is_activable() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA
|
||||
|| !selection.is_from_single_instance())
|
||||
return false;
|
||||
|
@ -1073,7 +1080,7 @@ void GLGizmoSlaSupports::on_set_state()
|
|||
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::on_start_dragging(const Selection& selection)
|
||||
void GLGizmoSlaSupports::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1) {
|
||||
select_point(NoPoints);
|
||||
|
|
|
@ -26,7 +26,7 @@ class GLGizmoSlaSupports : public GLGizmoBase
|
|||
{
|
||||
private:
|
||||
ModelObject* m_model_object = nullptr;
|
||||
ModelID m_current_mesh_model_id = 0;
|
||||
ObjectID m_current_mesh_object_id = 0;
|
||||
int m_active_instance = -1;
|
||||
float m_active_instance_bb_radius; // to cache the bb
|
||||
mutable float m_z_shift = 0.f;
|
||||
|
@ -70,9 +70,9 @@ public:
|
|||
|
||||
private:
|
||||
bool on_init();
|
||||
void on_update(const UpdateData& data, const Selection& selection);
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const;
|
||||
void on_update(const UpdateData& data);
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
|
||||
//void render_selection_rectangle() const;
|
||||
void render_points(const Selection& selection, bool picking = false) const;
|
||||
|
@ -133,11 +133,11 @@ protected:
|
|||
if ((int)m_editing_mode_cache.size() <= m_hover_id)
|
||||
m_hover_id = -1;
|
||||
}
|
||||
void on_start_dragging(const Selection& selection) override;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit, const Selection& selection) override;
|
||||
void on_start_dragging() override;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
|
||||
virtual std::string on_get_name() const;
|
||||
virtual bool on_is_activable(const Selection& selection) const;
|
||||
virtual bool on_is_activable() const;
|
||||
virtual bool on_is_selectable() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -14,8 +14,9 @@ namespace GUI {
|
|||
|
||||
const float GLGizmosManager::Default_Icons_Size = 64;
|
||||
|
||||
GLGizmosManager::GLGizmosManager()
|
||||
: m_enabled(false)
|
||||
GLGizmosManager::GLGizmosManager(GLCanvas3D& parent)
|
||||
: m_parent(parent)
|
||||
, m_enabled(false)
|
||||
, m_icons_texture_dirty(true)
|
||||
, m_current(Undefined)
|
||||
, m_overlay_icons_size(Default_Icons_Size)
|
||||
|
@ -23,6 +24,7 @@ GLGizmosManager::GLGizmosManager()
|
|||
, m_overlay_border(5.0f)
|
||||
, m_overlay_gap_y(5.0f)
|
||||
, m_tooltip("")
|
||||
, m_serializing(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -31,7 +33,7 @@ GLGizmosManager::~GLGizmosManager()
|
|||
reset();
|
||||
}
|
||||
|
||||
bool GLGizmosManager::init(GLCanvas3D& parent)
|
||||
bool GLGizmosManager::init()
|
||||
{
|
||||
m_background_texture.metadata.filename = "toolbar_background.png";
|
||||
m_background_texture.metadata.left = 16;
|
||||
|
@ -48,7 +50,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent)
|
|||
}
|
||||
}
|
||||
|
||||
GLGizmoBase* gizmo = new GLGizmoMove3D(parent, "move.svg", 0);
|
||||
GLGizmoBase* gizmo = new GLGizmoMove3D(m_parent, "move.svg", 0);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
|
@ -57,7 +59,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent)
|
|||
|
||||
m_gizmos.insert(GizmosMap::value_type(Move, gizmo));
|
||||
|
||||
gizmo = new GLGizmoScale3D(parent, "scale.svg", 1);
|
||||
gizmo = new GLGizmoScale3D(m_parent, "scale.svg", 1);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
|
@ -66,7 +68,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent)
|
|||
|
||||
m_gizmos.insert(GizmosMap::value_type(Scale, gizmo));
|
||||
|
||||
gizmo = new GLGizmoRotate3D(parent, "rotate.svg", 2);
|
||||
gizmo = new GLGizmoRotate3D(m_parent, "rotate.svg", 2);
|
||||
if (gizmo == nullptr)
|
||||
{
|
||||
reset();
|
||||
|
@ -81,7 +83,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent)
|
|||
|
||||
m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo));
|
||||
|
||||
gizmo = new GLGizmoFlatten(parent, "place.svg", 3);
|
||||
gizmo = new GLGizmoFlatten(m_parent, "place.svg", 3);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
|
@ -92,7 +94,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent)
|
|||
|
||||
m_gizmos.insert(GizmosMap::value_type(Flatten, gizmo));
|
||||
|
||||
gizmo = new GLGizmoCut(parent, "cut.svg", 4);
|
||||
gizmo = new GLGizmoCut(m_parent, "cut.svg", 4);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
|
@ -103,7 +105,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent)
|
|||
|
||||
m_gizmos.insert(GizmosMap::value_type(Cut, gizmo));
|
||||
|
||||
gizmo = new GLGizmoSlaSupports(parent, "sla_supports.svg", 5);
|
||||
gizmo = new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 5);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
|
@ -135,12 +137,15 @@ void GLGizmosManager::set_overlay_scale(float scale)
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmosManager::refresh_on_off_state(const Selection& selection)
|
||||
void GLGizmosManager::refresh_on_off_state()
|
||||
{
|
||||
if (m_serializing)
|
||||
return;
|
||||
|
||||
GizmosMap::iterator it = m_gizmos.find(m_current);
|
||||
if ((it != m_gizmos.end()) && (it->second != nullptr))
|
||||
{
|
||||
if (!it->second->is_activable(selection))
|
||||
if (!it->second->is_activable())
|
||||
{
|
||||
it->second->set_state(GLGizmoBase::Off);
|
||||
m_current = Undefined;
|
||||
|
@ -153,6 +158,9 @@ void GLGizmosManager::reset_all_states()
|
|||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
if (m_serializing)
|
||||
return;
|
||||
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if (it->second != nullptr)
|
||||
|
@ -192,22 +200,22 @@ void GLGizmosManager::enable_grabber(EType type, unsigned int id, bool enable)
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmosManager::update(const Linef3& mouse_ray, const Selection& selection, const Point* mouse_pos)
|
||||
void GLGizmosManager::update(const Linef3& mouse_ray, const Point& mouse_pos)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->update(GLGizmoBase::UpdateData(mouse_ray, mouse_pos), selection);
|
||||
curr->update(GLGizmoBase::UpdateData(mouse_ray, mouse_pos));
|
||||
}
|
||||
|
||||
void GLGizmosManager::update_data(GLCanvas3D& canvas)
|
||||
void GLGizmosManager::update_data()
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
const Selection& selection = canvas.get_selection();
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
bool is_wipe_tower = selection.is_wipe_tower();
|
||||
enable_grabber(Move, 2, !is_wipe_tower);
|
||||
|
@ -228,7 +236,7 @@ void GLGizmosManager::update_data(GLCanvas3D& canvas)
|
|||
set_rotation(Vec3d::Zero());
|
||||
ModelObject* model_object = selection.get_model()->objects[selection.get_object_idx()];
|
||||
set_flattening_data(model_object);
|
||||
set_sla_support_data(model_object, selection);
|
||||
set_sla_support_data(model_object);
|
||||
}
|
||||
else if (selection.is_single_volume() || selection.is_single_modifier())
|
||||
{
|
||||
|
@ -236,7 +244,7 @@ void GLGizmosManager::update_data(GLCanvas3D& canvas)
|
|||
set_scale(volume->get_volume_scaling_factor());
|
||||
set_rotation(Vec3d::Zero());
|
||||
set_flattening_data(nullptr);
|
||||
set_sla_support_data(nullptr, selection);
|
||||
set_sla_support_data(nullptr);
|
||||
}
|
||||
else if (is_wipe_tower)
|
||||
{
|
||||
|
@ -244,14 +252,14 @@ void GLGizmosManager::update_data(GLCanvas3D& canvas)
|
|||
set_scale(Vec3d::Ones());
|
||||
set_rotation(Vec3d(0., 0., (M_PI/180.) * dynamic_cast<const ConfigOptionFloat*>(config.option("wipe_tower_rotation_angle"))->value));
|
||||
set_flattening_data(nullptr);
|
||||
set_sla_support_data(nullptr, selection);
|
||||
set_sla_support_data(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_scale(Vec3d::Ones());
|
||||
set_rotation(Vec3d::Zero());
|
||||
set_flattening_data(selection.is_from_single_object() ? selection.get_model()->objects[selection.get_object_idx()] : nullptr);
|
||||
set_sla_support_data(nullptr, selection);
|
||||
set_sla_support_data(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,9 +272,12 @@ bool GLGizmosManager::is_running() const
|
|||
return (curr != nullptr) ? (curr->get_state() == GLGizmoBase::On) : false;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::handle_shortcut(int key, const Selection& selection)
|
||||
bool GLGizmosManager::handle_shortcut(int key)
|
||||
{
|
||||
if (!m_enabled || selection.is_empty())
|
||||
if (!m_enabled)
|
||||
return false;
|
||||
|
||||
if (m_parent.get_selection().is_empty())
|
||||
return false;
|
||||
|
||||
EType old_current = m_current;
|
||||
|
@ -278,7 +289,7 @@ bool GLGizmosManager::handle_shortcut(int key, const Selection& selection)
|
|||
|
||||
int it_key = it->second->get_shortcut_key();
|
||||
|
||||
if (it->second->is_activable(selection) && ((it_key == key - 64) || (it_key == key - 96)))
|
||||
if (it->second->is_activable() && ((it_key == key - 64) || (it_key == key - 96)))
|
||||
{
|
||||
if ((it->second->get_state() == GLGizmoBase::On))
|
||||
{
|
||||
|
@ -314,14 +325,14 @@ bool GLGizmosManager::is_dragging() const
|
|||
return (curr != nullptr) ? curr->is_dragging() : false;
|
||||
}
|
||||
|
||||
void GLGizmosManager::start_dragging(const Selection& selection)
|
||||
void GLGizmosManager::start_dragging()
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->start_dragging(selection);
|
||||
curr->start_dragging();
|
||||
}
|
||||
|
||||
void GLGizmosManager::stop_dragging()
|
||||
|
@ -409,14 +420,14 @@ void GLGizmosManager::set_flattening_data(const ModelObject* model_object)
|
|||
reinterpret_cast<GLGizmoFlatten*>(it->second)->set_flattening_data(model_object);
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_sla_support_data(ModelObject* model_object, const Selection& selection)
|
||||
void GLGizmosManager::set_sla_support_data(ModelObject* model_object)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(SlaSupports);
|
||||
if (it != m_gizmos.end())
|
||||
reinterpret_cast<GLGizmoSlaSupports*>(it->second)->set_sla_support_data(model_object, selection);
|
||||
reinterpret_cast<GLGizmoSlaSupports*>(it->second)->set_sla_support_data(model_object, m_parent.get_selection());
|
||||
}
|
||||
|
||||
// Returns true if the gizmo used the event to do something, false otherwise.
|
||||
|
@ -445,27 +456,27 @@ ClippingPlane GLGizmosManager::get_sla_clipping_plane() const
|
|||
}
|
||||
|
||||
|
||||
void GLGizmosManager::render_current_gizmo(const Selection& selection) const
|
||||
void GLGizmosManager::render_current_gizmo() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->render(selection);
|
||||
curr->render();
|
||||
}
|
||||
|
||||
void GLGizmosManager::render_current_gizmo_for_picking_pass(const Selection& selection) const
|
||||
void GLGizmosManager::render_current_gizmo_for_picking_pass() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->render_for_picking(selection);
|
||||
curr->render_for_picking();
|
||||
}
|
||||
|
||||
void GLGizmosManager::render_overlay(const GLCanvas3D& canvas, const Selection& selection) const
|
||||
void GLGizmosManager::render_overlay() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
@ -473,10 +484,10 @@ void GLGizmosManager::render_overlay(const GLCanvas3D& canvas, const Selection&
|
|||
if (m_icons_texture_dirty)
|
||||
generate_icons_texture();
|
||||
|
||||
do_render_overlay(canvas, selection);
|
||||
do_render_overlay();
|
||||
}
|
||||
|
||||
bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt, GLCanvas3D& canvas)
|
||||
bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt)
|
||||
{
|
||||
bool processed = false;
|
||||
|
||||
|
@ -489,14 +500,12 @@ bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
return processed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
||||
bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
||||
{
|
||||
Point pos(evt.GetX(), evt.GetY());
|
||||
Vec2d mouse_pos((double)evt.GetX(), (double)evt.GetY());
|
||||
|
||||
Selection& selection = canvas.get_selection();
|
||||
Selection& selection = m_parent.get_selection();
|
||||
int selected_object_idx = selection.get_object_idx();
|
||||
bool processed = false;
|
||||
|
||||
|
@ -512,7 +521,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
|
||||
// mouse anywhere
|
||||
if (evt.Moving())
|
||||
m_tooltip = update_hover_state(canvas, mouse_pos);
|
||||
m_tooltip = update_hover_state(mouse_pos);
|
||||
else if (evt.LeftUp())
|
||||
m_mouse_capture.left = false;
|
||||
else if (evt.MiddleUp())
|
||||
|
@ -523,7 +532,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
// if the button down was done on this toolbar, prevent from dragging into the scene
|
||||
processed = true;
|
||||
|
||||
if (!overlay_contains_mouse(canvas, mouse_pos))
|
||||
if (!overlay_contains_mouse(mouse_pos))
|
||||
{
|
||||
// mouse is outside the toolbar
|
||||
m_tooltip = "";
|
||||
|
@ -535,41 +544,40 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
processed = true;
|
||||
else if (!selection.is_empty() && grabber_contains_mouse())
|
||||
{
|
||||
update_data(canvas);
|
||||
update_data();
|
||||
selection.start_dragging();
|
||||
start_dragging(selection);
|
||||
start_dragging();
|
||||
|
||||
if (m_current == Flatten)
|
||||
{
|
||||
// Rotate the object so the normal points downward:
|
||||
selection.flattening_rotate(get_flattening_normal());
|
||||
canvas.do_flatten();
|
||||
m_parent.do_flatten(get_flattening_normal(), "Gizmo-Place on Face");
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
}
|
||||
|
||||
canvas.set_as_dirty();
|
||||
m_parent.set_as_dirty();
|
||||
processed = true;
|
||||
}
|
||||
}
|
||||
else if (evt.RightDown() && (selected_object_idx != -1) && (m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::RightDown))
|
||||
// event was taken care of by the SlaSupports gizmo
|
||||
processed = true;
|
||||
else if (evt.Dragging() && (canvas.get_move_volume_id() != -1) && (m_current == SlaSupports))
|
||||
else if (evt.Dragging() && (m_parent.get_move_volume_id() != -1) && (m_current == SlaSupports))
|
||||
// don't allow dragging objects with the Sla gizmo on
|
||||
processed = true;
|
||||
else if (evt.Dragging() && (m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()))
|
||||
{
|
||||
// the gizmo got the event and took some action, no need to do anything more here
|
||||
canvas.set_as_dirty();
|
||||
m_parent.set_as_dirty();
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.Dragging() && is_dragging())
|
||||
{
|
||||
if (!canvas.get_wxglcanvas()->HasCapture())
|
||||
canvas.get_wxglcanvas()->CaptureMouse();
|
||||
if (!m_parent.get_wxglcanvas()->HasCapture())
|
||||
m_parent.get_wxglcanvas()->CaptureMouse();
|
||||
|
||||
canvas.set_mouse_as_dragging();
|
||||
update(canvas.mouse_ray(pos), selection, &pos);
|
||||
m_parent.set_mouse_as_dragging();
|
||||
update(m_parent.mouse_ray(pos), pos);
|
||||
|
||||
switch (m_current)
|
||||
{
|
||||
|
@ -606,7 +614,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
break;
|
||||
}
|
||||
|
||||
canvas.set_as_dirty();
|
||||
m_parent.set_as_dirty();
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.LeftUp() && is_dragging())
|
||||
|
@ -615,18 +623,18 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
{
|
||||
case Move:
|
||||
{
|
||||
canvas.disable_regenerate_volumes();
|
||||
canvas.do_move();
|
||||
m_parent.disable_regenerate_volumes();
|
||||
m_parent.do_move("Gizmo-Move");
|
||||
break;
|
||||
}
|
||||
case Scale:
|
||||
{
|
||||
canvas.do_scale();
|
||||
m_parent.do_scale("Gizmo-Scale");
|
||||
break;
|
||||
}
|
||||
case Rotate:
|
||||
{
|
||||
canvas.do_rotate();
|
||||
m_parent.do_rotate("Gizmo-Rotate");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -634,25 +642,25 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
}
|
||||
|
||||
stop_dragging();
|
||||
update_data(canvas);
|
||||
update_data();
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
// Let the platter know that the dragging finished, so a delayed refresh
|
||||
// of the scene with the background processing data should be performed.
|
||||
canvas.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
||||
// updates camera target constraints
|
||||
canvas.refresh_camera_scene_box();
|
||||
m_parent.refresh_camera_scene_box();
|
||||
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.LeftUp() && (m_current == SlaSupports) && !canvas.is_mouse_dragging())
|
||||
else if (evt.LeftUp() && (m_current == SlaSupports) && !m_parent.is_mouse_dragging())
|
||||
{
|
||||
// in case SLA gizmo is selected, we just pass the LeftUp event and stop processing - neither
|
||||
// object moving or selecting is suppressed in that case
|
||||
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown());
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.LeftUp() && (m_current == Flatten) && ((canvas.get_first_hover_volume_idx() != -1) || grabber_contains_mouse()))
|
||||
else if (evt.LeftUp() && (m_current == Flatten) && ((m_parent.get_first_hover_volume_idx() != -1) || grabber_contains_mouse()))
|
||||
{
|
||||
// to avoid to loose the selection when user clicks an object while the Flatten gizmo is active
|
||||
processed = true;
|
||||
|
@ -664,24 +672,24 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
if (evt.LeftDown() || evt.LeftDClick())
|
||||
{
|
||||
m_mouse_capture.left = true;
|
||||
m_mouse_capture.parent = &canvas;
|
||||
m_mouse_capture.parent = &m_parent;
|
||||
processed = true;
|
||||
if (!selection.is_empty())
|
||||
{
|
||||
update_on_off_state(canvas, mouse_pos, selection);
|
||||
update_data(canvas);
|
||||
canvas.set_as_dirty();
|
||||
update_on_off_state(mouse_pos);
|
||||
update_data();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
else if (evt.MiddleDown())
|
||||
{
|
||||
m_mouse_capture.middle = true;
|
||||
m_mouse_capture.parent = &canvas;
|
||||
m_mouse_capture.parent = &m_parent;
|
||||
}
|
||||
else if (evt.RightDown())
|
||||
{
|
||||
m_mouse_capture.right = true;
|
||||
m_mouse_capture.parent = &canvas;
|
||||
m_mouse_capture.parent = &m_parent;
|
||||
}
|
||||
else if (evt.LeftUp())
|
||||
processed = true;
|
||||
|
@ -690,7 +698,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
return processed;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::on_char(wxKeyEvent& evt, GLCanvas3D& canvas)
|
||||
bool GLGizmosManager::on_char(wxKeyEvent& evt)
|
||||
{
|
||||
// see include/wx/defs.h enum wxKeyCode
|
||||
int keyCode = evt.GetKeyCode();
|
||||
|
@ -798,20 +806,20 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt, GLCanvas3D& canvas)
|
|||
|
||||
if (!processed && !evt.HasModifiers())
|
||||
{
|
||||
if (handle_shortcut(keyCode, canvas.get_selection()))
|
||||
if (handle_shortcut(keyCode))
|
||||
{
|
||||
update_data(canvas);
|
||||
update_data();
|
||||
processed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (processed)
|
||||
canvas.set_as_dirty();
|
||||
m_parent.set_as_dirty();
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::on_key(wxKeyEvent& evt, GLCanvas3D& canvas)
|
||||
bool GLGizmosManager::on_key(wxKeyEvent& evt)
|
||||
{
|
||||
const int keyCode = evt.GetKeyCode();
|
||||
bool processed = false;
|
||||
|
@ -837,23 +845,29 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt, GLCanvas3D& canvas)
|
|||
}
|
||||
|
||||
// if (processed)
|
||||
// canvas.set_cursor(GLCanvas3D::Standard);
|
||||
// m_parent.set_cursor(GLCanvas3D::Standard);
|
||||
}
|
||||
else if (evt.GetEventType() == wxEVT_KEY_DOWN)
|
||||
{
|
||||
if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) && reinterpret_cast<GLGizmoSlaSupports*>(get_current())->is_in_editing_mode())
|
||||
{
|
||||
// canvas.set_cursor(GLCanvas3D::Cross);
|
||||
// m_parent.set_cursor(GLCanvas3D::Cross);
|
||||
processed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (processed)
|
||||
canvas.set_as_dirty();
|
||||
m_parent.set_as_dirty();
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
void GLGizmosManager::update_after_undo_redo()
|
||||
{
|
||||
update_data();
|
||||
m_serializing = false;
|
||||
}
|
||||
|
||||
void GLGizmosManager::reset()
|
||||
{
|
||||
for (GizmosMap::value_type& gizmo : m_gizmos)
|
||||
|
@ -865,14 +879,14 @@ void GLGizmosManager::reset()
|
|||
m_gizmos.clear();
|
||||
}
|
||||
|
||||
void GLGizmosManager::do_render_overlay(const GLCanvas3D& canvas, const Selection& selection) const
|
||||
void GLGizmosManager::do_render_overlay() const
|
||||
{
|
||||
if (m_gizmos.empty())
|
||||
return;
|
||||
|
||||
float cnv_w = (float)canvas.get_canvas_size().get_width();
|
||||
float cnv_h = (float)canvas.get_canvas_size().get_height();
|
||||
float zoom = (float)canvas.get_camera().get_zoom();
|
||||
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 height = get_total_overlay_height();
|
||||
|
@ -985,8 +999,8 @@ void GLGizmosManager::do_render_overlay(const GLCanvas3D& canvas, const Selectio
|
|||
|
||||
GLTexture::render_sub_texture(icons_texture_id, top_x, top_x + scaled_icons_size, top_y - scaled_icons_size, top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } });
|
||||
if (it->second->get_state() == GLGizmoBase::On) {
|
||||
float toolbar_top = (float)cnv_h - canvas.get_view_toolbar_height();
|
||||
it->second->render_input_window(width, 0.5f * cnv_h - top_y * zoom, toolbar_top, selection);
|
||||
float toolbar_top = (float)cnv_h - m_parent.get_view_toolbar_height();
|
||||
it->second->render_input_window(width, 0.5f * cnv_h - top_y * zoom, toolbar_top);
|
||||
}
|
||||
top_y -= scaled_stride_y;
|
||||
}
|
||||
|
@ -1048,12 +1062,12 @@ bool GLGizmosManager::generate_icons_texture() const
|
|||
return res;
|
||||
}
|
||||
|
||||
void GLGizmosManager::update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection)
|
||||
void GLGizmosManager::update_on_off_state(const Vec2d& mouse_pos)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
float cnv_h = (float)canvas.get_canvas_size().get_height();
|
||||
float cnv_h = (float)m_parent.get_canvas_size().get_height();
|
||||
float height = get_total_overlay_height();
|
||||
|
||||
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
|
||||
|
@ -1068,7 +1082,7 @@ void GLGizmosManager::update_on_off_state(const GLCanvas3D& canvas, const Vec2d&
|
|||
continue;
|
||||
|
||||
bool inside = (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
|
||||
if (it->second->is_activable(selection) && inside)
|
||||
if (it->second->is_activable() && inside)
|
||||
{
|
||||
if ((it->second->get_state() == GLGizmoBase::On))
|
||||
{
|
||||
|
@ -1092,16 +1106,14 @@ void GLGizmosManager::update_on_off_state(const GLCanvas3D& canvas, const Vec2d&
|
|||
it->second->set_state(GLGizmoBase::On);
|
||||
}
|
||||
|
||||
std::string GLGizmosManager::update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos)
|
||||
std::string GLGizmosManager::update_hover_state(const Vec2d& mouse_pos)
|
||||
{
|
||||
std::string name = "";
|
||||
|
||||
if (!m_enabled)
|
||||
return name;
|
||||
|
||||
const Selection& selection = canvas.get_selection();
|
||||
|
||||
float cnv_h = (float)canvas.get_canvas_size().get_height();
|
||||
float cnv_h = (float)m_parent.get_canvas_size().get_height();
|
||||
float height = get_total_overlay_height();
|
||||
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
|
||||
float scaled_border = m_overlay_border * m_overlay_scale;
|
||||
|
@ -1118,7 +1130,7 @@ std::string GLGizmosManager::update_hover_state(const GLCanvas3D& canvas, const
|
|||
if (inside)
|
||||
name = it->second->get_name();
|
||||
|
||||
if (it->second->is_activable(selection) && (it->second->get_state() != GLGizmoBase::On))
|
||||
if (it->second->is_activable() && (it->second->get_state() != GLGizmoBase::On))
|
||||
it->second->set_state(inside ? GLGizmoBase::Hover : GLGizmoBase::Off);
|
||||
|
||||
top_y += scaled_stride_y;
|
||||
|
@ -1127,12 +1139,12 @@ std::string GLGizmosManager::update_hover_state(const GLCanvas3D& canvas, const
|
|||
return name;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const
|
||||
bool GLGizmosManager::overlay_contains_mouse(const Vec2d& mouse_pos) const
|
||||
{
|
||||
if (!m_enabled)
|
||||
return false;
|
||||
|
||||
float cnv_h = (float)canvas.get_canvas_size().get_height();
|
||||
float cnv_h = (float)m_parent.get_canvas_size().get_height();
|
||||
float height = get_total_overlay_height();
|
||||
|
||||
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
#include "slic3r/GUI/GLTexture.hpp"
|
||||
#include "slic3r/GUI/GLToolbar.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmos.hpp"
|
||||
#include "libslic3r/ObjectID.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
class Selection;
|
||||
class GLGizmoBase;
|
||||
class GLCanvas3D;
|
||||
class ClippingPlane;
|
||||
|
||||
|
@ -43,7 +42,7 @@ public:
|
|||
float get_height() const { return m_top - m_bottom; }
|
||||
};
|
||||
|
||||
class GLGizmosManager
|
||||
class GLGizmosManager : public Slic3r::ObjectBase
|
||||
{
|
||||
public:
|
||||
static const float Default_Icons_Size;
|
||||
|
@ -61,6 +60,7 @@ public:
|
|||
};
|
||||
|
||||
private:
|
||||
GLCanvas3D& m_parent;
|
||||
bool m_enabled;
|
||||
typedef std::map<EType, GLGizmoBase*> GizmosMap;
|
||||
GizmosMap m_gizmos;
|
||||
|
@ -89,12 +89,44 @@ private:
|
|||
|
||||
MouseCapture m_mouse_capture;
|
||||
std::string m_tooltip;
|
||||
bool m_serializing;
|
||||
|
||||
public:
|
||||
GLGizmosManager();
|
||||
explicit GLGizmosManager(GLCanvas3D& parent);
|
||||
~GLGizmosManager();
|
||||
|
||||
bool init(GLCanvas3D& parent);
|
||||
bool init();
|
||||
|
||||
template<class Archive>
|
||||
void load(Archive& ar)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
m_serializing = true;
|
||||
|
||||
ar(m_current);
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
{
|
||||
curr->set_state(GLGizmoBase::On);
|
||||
curr->load(ar);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void save(Archive& ar) const
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
ar(m_current);
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->save(ar);
|
||||
}
|
||||
|
||||
bool is_enabled() const { return m_enabled; }
|
||||
void set_enabled(bool enable) { m_enabled = enable; }
|
||||
|
@ -102,23 +134,22 @@ public:
|
|||
void set_overlay_icon_size(float size);
|
||||
void set_overlay_scale(float scale);
|
||||
|
||||
void refresh_on_off_state(const Selection& selection);
|
||||
void refresh_on_off_state();
|
||||
void reset_all_states();
|
||||
|
||||
void set_hover_id(int id);
|
||||
void enable_grabber(EType type, unsigned int id, bool enable);
|
||||
|
||||
void update(const Linef3& mouse_ray, const Selection& selection, const Point* mouse_pos = nullptr);
|
||||
void update_data(GLCanvas3D& canvas);
|
||||
void update(const Linef3& mouse_ray, const Point& mouse_pos);
|
||||
void update_data();
|
||||
|
||||
Rect get_reset_rect_viewport(const GLCanvas3D& canvas) const;
|
||||
EType get_current_type() const { return m_current; }
|
||||
|
||||
bool is_running() const;
|
||||
bool handle_shortcut(int key, const Selection& selection);
|
||||
bool handle_shortcut(int key);
|
||||
|
||||
bool is_dragging() const;
|
||||
void start_dragging(const Selection& selection);
|
||||
void start_dragging();
|
||||
void stop_dragging();
|
||||
|
||||
Vec3d get_displacement() const;
|
||||
|
@ -135,26 +166,28 @@ public:
|
|||
|
||||
void set_flattening_data(const ModelObject* model_object);
|
||||
|
||||
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
|
||||
void set_sla_support_data(ModelObject* model_object);
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false, bool alt_down = false, bool control_down = false);
|
||||
ClippingPlane get_sla_clipping_plane() const;
|
||||
|
||||
void render_current_gizmo(const Selection& selection) const;
|
||||
void render_current_gizmo_for_picking_pass(const Selection& selection) const;
|
||||
void render_current_gizmo() const;
|
||||
void render_current_gizmo_for_picking_pass() const;
|
||||
|
||||
void render_overlay(const GLCanvas3D& canvas, const Selection& selection) const;
|
||||
void render_overlay() const;
|
||||
|
||||
const std::string& get_tooltip() const { return m_tooltip; }
|
||||
|
||||
bool on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas);
|
||||
bool on_mouse_wheel(wxMouseEvent& evt, GLCanvas3D& canvas);
|
||||
bool on_char(wxKeyEvent& evt, GLCanvas3D& canvas);
|
||||
bool on_key(wxKeyEvent& evt, GLCanvas3D& canvas);
|
||||
bool on_mouse(wxMouseEvent& evt);
|
||||
bool on_mouse_wheel(wxMouseEvent& evt);
|
||||
bool on_char(wxKeyEvent& evt);
|
||||
bool on_key(wxKeyEvent& evt);
|
||||
|
||||
void update_after_undo_redo();
|
||||
|
||||
private:
|
||||
void reset();
|
||||
|
||||
void do_render_overlay(const GLCanvas3D& canvas, const Selection& selection) const;
|
||||
void do_render_overlay() const;
|
||||
|
||||
float get_total_overlay_height() const;
|
||||
float get_total_overlay_width() const;
|
||||
|
@ -163,13 +196,18 @@ private:
|
|||
|
||||
bool generate_icons_texture() const;
|
||||
|
||||
void update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection);
|
||||
std::string update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos);
|
||||
bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const;
|
||||
void update_on_off_state(const Vec2d& mouse_pos);
|
||||
std::string update_hover_state(const Vec2d& mouse_pos);
|
||||
bool overlay_contains_mouse(const Vec2d& mouse_pos) const;
|
||||
bool grabber_contains_mouse() const;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
template <class Archive> struct specialize<Archive, Slic3r::GUI::GLGizmosManager, cereal::specialization::member_load_save> {};
|
||||
}
|
||||
|
||||
#endif // slic3r_GUI_GLGizmosManager_hpp_
|
||||
|
|
|
@ -233,9 +233,9 @@ ImVec2 ImGuiWrapper::calc_text_size(const wxString &text)
|
|||
return size;
|
||||
}
|
||||
|
||||
void ImGuiWrapper::set_next_window_pos(float x, float y, int flag)
|
||||
void ImGuiWrapper::set_next_window_pos(float x, float y, int flag, float pivot_x, float pivot_y)
|
||||
{
|
||||
ImGui::SetNextWindowPos(ImVec2(x, y), (ImGuiCond)flag);
|
||||
ImGui::SetNextWindowPos(ImVec2(x, y), (ImGuiCond)flag, ImVec2(pivot_x, pivot_y));
|
||||
ImGui::SetNextWindowSize(ImVec2(0.0, 0.0));
|
||||
}
|
||||
|
||||
|
@ -342,6 +342,32 @@ bool ImGuiWrapper::combo(const wxString& label, const std::vector<std::string>&
|
|||
return res;
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool , int , const char**), int& hovered, int& selected)
|
||||
{
|
||||
bool is_hovered = false;
|
||||
ImGui::ListBoxHeader("", size);
|
||||
|
||||
int i=0;
|
||||
const char* item_text;
|
||||
while (items_getter(is_undo, i, &item_text))
|
||||
{
|
||||
ImGui::Selectable(item_text, i < hovered);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(item_text);
|
||||
hovered = i;
|
||||
is_hovered = true;
|
||||
}
|
||||
|
||||
if (ImGui::IsItemClicked())
|
||||
selected = i;
|
||||
i++;
|
||||
}
|
||||
|
||||
ImGui::ListBoxFooter();
|
||||
return is_hovered;
|
||||
}
|
||||
|
||||
void ImGuiWrapper::disabled_begin(bool disabled)
|
||||
{
|
||||
wxCHECK_RET(!m_disabled, "ImGUI: Unbalanced disabled_begin() call");
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size, y * m_font_size); }
|
||||
ImVec2 calc_text_size(const wxString &text);
|
||||
|
||||
void set_next_window_pos(float x, float y, int flag);
|
||||
void set_next_window_pos(float x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f);
|
||||
void set_next_window_bg_alpha(float alpha);
|
||||
|
||||
bool begin(const std::string &name, int flags = 0);
|
||||
|
@ -67,6 +67,7 @@ public:
|
|||
void text(const std::string &label);
|
||||
void text(const wxString &label);
|
||||
bool combo(const wxString& label, const std::vector<std::string>& options, int& selection); // Use -1 to not mark any option as selected
|
||||
bool undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool, int, const char**), int& hovered, int& selected);
|
||||
|
||||
void disabled_begin(bool disabled);
|
||||
void disabled_end();
|
||||
|
|
|
@ -537,6 +537,14 @@ void MainFrame::init_menubar()
|
|||
_(L("Deletes all objects")), [this](wxCommandEvent&) { m_plater->reset_with_confirm(); },
|
||||
menu_icon("delete_all_menu"), nullptr, [this](){return can_delete_all(); }, this);
|
||||
|
||||
editMenu->AppendSeparator();
|
||||
append_menu_item(editMenu, wxID_ANY, _(L("&Undo")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "Z",
|
||||
_(L("Undo")), [this](wxCommandEvent&) { m_plater->undo(); },
|
||||
"undo", nullptr, [this](){return m_plater->can_undo(); }, this);
|
||||
append_menu_item(editMenu, wxID_ANY, _(L("&Redo")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "Y",
|
||||
_(L("Redo")), [this](wxCommandEvent&) { m_plater->redo(); },
|
||||
"redo", nullptr, [this](){return m_plater->can_redo(); }, this);
|
||||
|
||||
editMenu->AppendSeparator();
|
||||
append_menu_item(editMenu, wxID_ANY, _(L("&Copy")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "C",
|
||||
_(L("Copy selection to clipboard")), [this](wxCommandEvent&) { m_plater->copy_selection_to_clipboard(); },
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
#include "../Utils/ASCIIFolding.hpp"
|
||||
#include "../Utils/PrintHost.hpp"
|
||||
#include "../Utils/FixModelByWin10.hpp"
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
|
||||
#include <wx/glcanvas.h> // Needs to be last because reasons :-/
|
||||
#include "WipeTowerDialog.hpp"
|
||||
|
@ -1254,6 +1255,8 @@ const std::regex PlaterDropTarget::pattern_drop(".*[.](stl|obj|amf|3mf|prusa)",
|
|||
|
||||
bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames)
|
||||
{
|
||||
plater->take_snapshot(_(L("Load Files")));
|
||||
|
||||
std::vector<fs::path> paths;
|
||||
|
||||
for (const auto &filename : filenames) {
|
||||
|
@ -1319,7 +1322,12 @@ struct Plater::priv
|
|||
Slic3r::Model model;
|
||||
PrinterTechnology printer_technology = ptFFF;
|
||||
Slic3r::GCodePreviewData gcode_preview_data;
|
||||
|
||||
Slic3r::UndoRedo::Stack undo_redo_stack;
|
||||
int m_prevent_snapshots = 0; /* Used for avoid of excess "snapshoting".
|
||||
* Like for "delete selected" or "set numbers of copies"
|
||||
* we should call tack_snapshot just ones
|
||||
* instead of calls for each action separately
|
||||
* */
|
||||
// GUI elements
|
||||
wxSizer* panel_sizer{ nullptr };
|
||||
wxPanel* current_panel{ nullptr };
|
||||
|
@ -1619,6 +1627,23 @@ struct Plater::priv
|
|||
void split_object();
|
||||
void split_volume();
|
||||
void scale_selection_to_fit_print_volume();
|
||||
|
||||
void take_snapshot(const std::string& snapshot_name)
|
||||
{
|
||||
if (this->m_prevent_snapshots > 0)
|
||||
return;
|
||||
assert(this->m_prevent_snapshots >= 0);
|
||||
this->undo_redo_stack.take_snapshot(snapshot_name, model, view3D->get_canvas3d()->get_selection(), view3D->get_canvas3d()->get_gizmos_manager());
|
||||
}
|
||||
void take_snapshot(const wxString& snapshot_name) { this->take_snapshot(std::string(snapshot_name.ToUTF8().data())); }
|
||||
int get_active_snapshot_index();
|
||||
void undo();
|
||||
void redo();
|
||||
void undo_to(size_t time_to_load);
|
||||
void redo_to(size_t time_to_load);
|
||||
void suppress_snapshots() { this->m_prevent_snapshots++; }
|
||||
void allow_snapshots() { this->m_prevent_snapshots--; }
|
||||
|
||||
bool background_processing_enabled() const { return this->get_config("background_processing") == "1"; }
|
||||
void update_print_volume_state();
|
||||
void schedule_background_process();
|
||||
|
@ -1709,6 +1734,7 @@ private:
|
|||
|
||||
void update_fff_scene();
|
||||
void update_sla_scene();
|
||||
void update_after_undo_redo();
|
||||
|
||||
// path to project file stored with no extension
|
||||
wxString m_project_filename;
|
||||
|
@ -1811,6 +1837,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
view3D_canvas->Bind(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, &priv::on_3dcanvas_mouse_dragging_finished, this);
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_TAB, [this](SimpleEvent&) { select_next_view_3D(); });
|
||||
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(); });
|
||||
|
||||
// 3DScene/Toolbar:
|
||||
view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this);
|
||||
|
@ -1849,6 +1877,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
|
||||
// updates camera type from .ini file
|
||||
camera.set_type(get_config("use_perspective_camera"));
|
||||
|
||||
// Initialize the Undo / Redo stack with a first snapshot.
|
||||
this->take_snapshot(_(L("New Project")));
|
||||
}
|
||||
|
||||
Plater::priv::~priv()
|
||||
|
@ -2219,7 +2250,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
|
|||
// the size of the object is too big -> this could lead to overflow when moving to clipper coordinates,
|
||||
// so scale down the mesh
|
||||
double inv = 1. / max_ratio;
|
||||
object->scale_mesh(Vec3d(inv, inv, inv));
|
||||
object->scale_mesh_after_creation(Vec3d(inv, inv, inv));
|
||||
object->origin_translation = Vec3d::Zero();
|
||||
object->center_around_origin();
|
||||
scaled_down = true;
|
||||
|
@ -2398,12 +2429,15 @@ void Plater::priv::object_list_changed()
|
|||
|
||||
void Plater::priv::select_all()
|
||||
{
|
||||
// this->take_snapshot(_(L("Select All")));
|
||||
|
||||
view3D->select_all();
|
||||
this->sidebar->obj_list()->update_selections();
|
||||
}
|
||||
|
||||
void Plater::priv::deselect_all()
|
||||
{
|
||||
// this->take_snapshot(_(L("Deselect All")));
|
||||
view3D->deselect_all();
|
||||
}
|
||||
|
||||
|
@ -2425,6 +2459,7 @@ void Plater::priv::remove(size_t obj_idx)
|
|||
|
||||
void Plater::priv::delete_object_from_model(size_t obj_idx)
|
||||
{
|
||||
this->take_snapshot(_(L("Delete Object")));
|
||||
model.delete_object(obj_idx);
|
||||
update();
|
||||
object_list_changed();
|
||||
|
@ -2432,6 +2467,8 @@ void Plater::priv::delete_object_from_model(size_t obj_idx)
|
|||
|
||||
void Plater::priv::reset()
|
||||
{
|
||||
this->take_snapshot(_(L("Reset Project")));
|
||||
|
||||
set_project_filename(wxEmptyString);
|
||||
|
||||
// Prevent toolpaths preview from rendering while we modify the Print object
|
||||
|
@ -2457,17 +2494,20 @@ void Plater::priv::reset()
|
|||
|
||||
void Plater::priv::mirror(Axis axis)
|
||||
{
|
||||
this->take_snapshot(_(L("Mirror")));
|
||||
view3D->mirror_selection(axis);
|
||||
}
|
||||
|
||||
void Plater::priv::arrange()
|
||||
{
|
||||
this->take_snapshot(_(L("Arrange")));
|
||||
m_ui_jobs.start(Jobs::Arrange);
|
||||
}
|
||||
|
||||
// This method will find an optimal orientation for the currently selected item
|
||||
// Very similar in nature to the arrange method above...
|
||||
void Plater::priv::sla_optimize_rotation() {
|
||||
this->take_snapshot(_(L("Optimize Rotation")));
|
||||
m_ui_jobs.start(Jobs::Rotoptimize);
|
||||
}
|
||||
|
||||
|
@ -2623,6 +2663,8 @@ void Plater::priv::split_object()
|
|||
Slic3r::GUI::warning_catcher(q, _(L("The selected object couldn't be split because it contains only one part.")));
|
||||
else
|
||||
{
|
||||
this->take_snapshot(_(L("Split to Objects")));
|
||||
|
||||
unsigned int counter = 1;
|
||||
for (ModelObject* m : new_objects)
|
||||
m->name = current_model_object->name + "_" + std::to_string(counter++);
|
||||
|
@ -2861,6 +2903,8 @@ void Plater::priv::update_sla_scene()
|
|||
|
||||
void Plater::priv::reload_from_disk()
|
||||
{
|
||||
this->take_snapshot(_(L("Reload from Disk")));
|
||||
|
||||
const auto &selection = get_selection();
|
||||
const auto obj_orig_idx = selection.get_object_idx();
|
||||
if (selection.is_wipe_tower() || obj_orig_idx == -1) { return; }
|
||||
|
@ -2894,6 +2938,9 @@ void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* =
|
|||
{
|
||||
if (obj_idx < 0)
|
||||
return;
|
||||
|
||||
this->take_snapshot(_(L("Fix Throught NetFabb")));
|
||||
|
||||
fix_model_by_win10_sdk_gui(*model.objects[obj_idx], vol_idx);
|
||||
this->update();
|
||||
this->object_list_changed();
|
||||
|
@ -3139,6 +3186,8 @@ void Plater::priv::on_action_layersediting(SimpleEvent&)
|
|||
|
||||
void Plater::priv::on_object_select(SimpleEvent& evt)
|
||||
{
|
||||
// this->take_snapshot(_(L("Object Selection")));
|
||||
|
||||
wxGetApp().obj_list()->update_selections();
|
||||
selection_changed();
|
||||
}
|
||||
|
@ -3414,8 +3463,7 @@ void Plater::priv::init_view_toolbar()
|
|||
item.icon_filename = "editor.svg";
|
||||
item.tooltip = _utf8(L("3D editor view")) + " [" + GUI::shortkey_ctrl_prefix() + "5]";
|
||||
item.sprite_id = 0;
|
||||
item.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_3D)); };
|
||||
item.is_toggable = false;
|
||||
item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_3D)); };
|
||||
if (!view_toolbar.add_item(item))
|
||||
return;
|
||||
|
||||
|
@ -3423,8 +3471,7 @@ void Plater::priv::init_view_toolbar()
|
|||
item.icon_filename = "preview.svg";
|
||||
item.tooltip = _utf8(L("Preview")) + " [" + GUI::shortkey_ctrl_prefix() + "6]";
|
||||
item.sprite_id = 1;
|
||||
item.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); };
|
||||
item.is_toggable = false;
|
||||
item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); };
|
||||
if (!view_toolbar.add_item(item))
|
||||
return;
|
||||
|
||||
|
@ -3554,6 +3601,52 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const
|
|||
}
|
||||
}
|
||||
|
||||
int Plater::priv::get_active_snapshot_index()
|
||||
{
|
||||
const size_t& active_snapshot_time = this->undo_redo_stack.active_snapshot_time();
|
||||
const std::vector<UndoRedo::Snapshot>& ss_stack = this->undo_redo_stack.snapshots();
|
||||
const auto it = std::lower_bound(ss_stack.begin(), ss_stack.end(), UndoRedo::Snapshot(active_snapshot_time));
|
||||
return it - ss_stack.begin();
|
||||
}
|
||||
|
||||
void Plater::priv::undo()
|
||||
{
|
||||
if (this->undo_redo_stack.undo(model, this->view3D->get_canvas3d()->get_selection(), this->view3D->get_canvas3d()->get_gizmos_manager()))
|
||||
this->update_after_undo_redo();
|
||||
}
|
||||
|
||||
void Plater::priv::redo()
|
||||
{
|
||||
if (this->undo_redo_stack.redo(model, this->view3D->get_canvas3d()->get_gizmos_manager()))
|
||||
this->update_after_undo_redo();
|
||||
}
|
||||
|
||||
void Plater::priv::undo_to(size_t time_to_load)
|
||||
{
|
||||
if (this->undo_redo_stack.undo(model, this->view3D->get_canvas3d()->get_selection(), this->view3D->get_canvas3d()->get_gizmos_manager(), time_to_load))
|
||||
this->update_after_undo_redo();
|
||||
}
|
||||
|
||||
void Plater::priv::redo_to(size_t time_to_load)
|
||||
{
|
||||
if (this->undo_redo_stack.redo(model, this->view3D->get_canvas3d()->get_gizmos_manager(), time_to_load))
|
||||
this->update_after_undo_redo();
|
||||
}
|
||||
|
||||
void Plater::priv::update_after_undo_redo()
|
||||
{
|
||||
this->view3D->get_canvas3d()->get_selection().clear();
|
||||
this->update(false); // update volumes from the deserializd model
|
||||
//YS_FIXME update obj_list from the deserialized model (maybe store ObjectIDs into the tree?) (no selections at this point of time)
|
||||
this->view3D->get_canvas3d()->get_selection().set_deserialized(GUI::Selection::EMode(this->undo_redo_stack.selection_deserialized().mode), this->undo_redo_stack.selection_deserialized().volumes_and_instances);
|
||||
this->view3D->get_canvas3d()->get_gizmos_manager().update_after_undo_redo();
|
||||
|
||||
wxGetApp().obj_list()->update_after_undo_redo();
|
||||
|
||||
//FIXME what about the state of the manipulators?
|
||||
//FIXME what about the focus? Cursor in the side panel?
|
||||
}
|
||||
|
||||
void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& label) const
|
||||
{
|
||||
switch (btn_type)
|
||||
|
@ -3591,6 +3684,8 @@ void Plater::new_project()
|
|||
|
||||
void Plater::load_project()
|
||||
{
|
||||
this->take_snapshot(_(L("Load Project")));
|
||||
|
||||
wxString input_file;
|
||||
wxGetApp().load_project(this, input_file);
|
||||
load_project(input_file);
|
||||
|
@ -3616,6 +3711,8 @@ void Plater::add_model()
|
|||
if (input_files.empty())
|
||||
return;
|
||||
|
||||
this->take_snapshot(_(L("Add object(s)")));
|
||||
|
||||
std::vector<fs::path> input_paths;
|
||||
for (const auto &file : input_files) {
|
||||
input_paths.push_back(into_path(file));
|
||||
|
@ -3673,13 +3770,18 @@ void Plater::delete_object_from_model(size_t obj_idx) { p->delete_object_from_mo
|
|||
|
||||
void Plater::remove_selected()
|
||||
{
|
||||
this->take_snapshot(_(L("Delete Selected Objects")));
|
||||
this->suppress_snapshots();
|
||||
this->p->view3D->delete_selected();
|
||||
this->allow_snapshots();
|
||||
}
|
||||
|
||||
void Plater::increase_instances(size_t num)
|
||||
{
|
||||
if (! can_increase_instances()) { return; }
|
||||
|
||||
this->take_snapshot(_(L("Increase Instances")));
|
||||
|
||||
int obj_idx = p->get_selected_object_idx();
|
||||
|
||||
ModelObject* model_object = p->model.objects[obj_idx];
|
||||
|
@ -3714,6 +3816,8 @@ void Plater::decrease_instances(size_t num)
|
|||
{
|
||||
if (! can_decrease_instances()) { return; }
|
||||
|
||||
this->take_snapshot(_(L("Decrease Instances")));
|
||||
|
||||
int obj_idx = p->get_selected_object_idx();
|
||||
|
||||
ModelObject* model_object = p->model.objects[obj_idx];
|
||||
|
@ -3748,11 +3852,16 @@ void Plater::set_number_of_copies(/*size_t num*/)
|
|||
if (num < 0)
|
||||
return;
|
||||
|
||||
this->take_snapshot(wxString::Format(_(L("Set numbers of copies to %d")), num));
|
||||
this->suppress_snapshots();
|
||||
|
||||
int diff = (int)num - (int)model_object->instances.size();
|
||||
if (diff > 0)
|
||||
increase_instances(diff);
|
||||
else if (diff < 0)
|
||||
decrease_instances(-diff);
|
||||
|
||||
this->allow_snapshots();
|
||||
}
|
||||
|
||||
bool Plater::is_selection_empty() const
|
||||
|
@ -3776,6 +3885,8 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_uppe
|
|||
return;
|
||||
}
|
||||
|
||||
this->take_snapshot(_(L("Gizmo-Cut")));
|
||||
|
||||
wxBusyCursor wait;
|
||||
const auto new_objects = object->cut(instance_idx, z, keep_upper, keep_lower, rotate_lower);
|
||||
|
||||
|
@ -4065,6 +4176,45 @@ void Plater::send_gcode()
|
|||
}
|
||||
}
|
||||
|
||||
void Plater::take_snapshot(const std::string &snapshot_name) { p->take_snapshot(snapshot_name); }
|
||||
void Plater::take_snapshot(const wxString &snapshot_name) { p->take_snapshot(snapshot_name); }
|
||||
void Plater::suppress_snapshots() { p->suppress_snapshots(); }
|
||||
void Plater::allow_snapshots() { p->allow_snapshots(); }
|
||||
void Plater::undo() { p->undo(); }
|
||||
void Plater::redo() { p->redo(); }
|
||||
void Plater::undo_to(int selection)
|
||||
{
|
||||
if (selection == 0) {
|
||||
p->undo();
|
||||
return;
|
||||
}
|
||||
|
||||
const int idx = p->get_active_snapshot_index() - selection - 1;
|
||||
p->undo_to(p->undo_redo_stack.snapshots()[idx].timestamp);
|
||||
}
|
||||
void Plater::redo_to(int selection)
|
||||
{
|
||||
if (selection == 0) {
|
||||
p->redo();
|
||||
return;
|
||||
}
|
||||
|
||||
const int idx = p->get_active_snapshot_index() + selection + 1;
|
||||
p->redo_to(p->undo_redo_stack.snapshots()[idx].timestamp);
|
||||
}
|
||||
bool Plater::undo_redo_string_getter(const bool is_undo, int idx, const char** out_text)
|
||||
{
|
||||
const std::vector<UndoRedo::Snapshot>& ss_stack = p->undo_redo_stack.snapshots();
|
||||
const int idx_in_ss_stack = p->get_active_snapshot_index() + (is_undo ? -(++idx) : idx);
|
||||
|
||||
if (0 < idx_in_ss_stack && idx_in_ss_stack < ss_stack.size() - 1) {
|
||||
*out_text = ss_stack[idx_in_ss_stack].name.c_str();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Plater::on_extruders_change(int num_extruders)
|
||||
{
|
||||
auto& choices = sidebar().combos_filament();
|
||||
|
@ -4290,7 +4440,10 @@ void Plater::copy_selection_to_clipboard()
|
|||
|
||||
void Plater::paste_from_clipboard()
|
||||
{
|
||||
if (can_paste_from_clipboard())
|
||||
if (!can_paste_from_clipboard())
|
||||
return;
|
||||
|
||||
this->take_snapshot(_(L("Paste From Clipboard")));
|
||||
p->view3D->get_canvas3d()->get_selection().paste_from_clipboard();
|
||||
}
|
||||
|
||||
|
@ -4356,6 +4509,16 @@ bool Plater::can_copy_to_clipboard() const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Plater::can_undo() const
|
||||
{
|
||||
return p->undo_redo_stack.has_undo_snapshot();
|
||||
}
|
||||
|
||||
bool Plater::can_redo() const
|
||||
{
|
||||
return p->undo_redo_stack.has_redo_snapshot();
|
||||
}
|
||||
|
||||
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
|
||||
m_was_running(wxGetApp().plater()->is_background_process_running())
|
||||
{
|
||||
|
|
|
@ -184,6 +184,16 @@ public:
|
|||
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
|
||||
void send_gcode();
|
||||
|
||||
void take_snapshot(const std::string &snapshot_name);
|
||||
void take_snapshot(const wxString &snapshot_name);
|
||||
void suppress_snapshots();
|
||||
void allow_snapshots();
|
||||
void undo();
|
||||
void redo();
|
||||
void undo_to(int selection);
|
||||
void redo_to(int selection);
|
||||
bool undo_redo_string_getter(const bool is_undo, int idx, const char** out_text);
|
||||
|
||||
void on_extruders_change(int extruders_count);
|
||||
void on_config_change(const DynamicPrintConfig &config);
|
||||
// On activating the parent window.
|
||||
|
@ -218,6 +228,8 @@ public:
|
|||
bool can_layers_editing() const;
|
||||
bool can_paste_from_clipboard() const;
|
||||
bool can_copy_to_clipboard() const;
|
||||
bool can_undo() const;
|
||||
bool can_redo() const;
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
|
|
|
@ -1366,7 +1366,7 @@ void PresetBundle::export_configbundle(const std::string &path, bool export_syst
|
|||
continue;
|
||||
c << std::endl << "[" << presets->section_name() << ":" << preset.name << "]" << std::endl;
|
||||
for (const std::string &opt_key : preset.config.keys())
|
||||
c << opt_key << " = " << preset.config.serialize(opt_key) << std::endl;
|
||||
c << opt_key << " = " << preset.config.opt_serialize(opt_key) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -312,6 +312,22 @@ void Selection::add_all()
|
|||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
|
||||
void Selection::set_deserialized(EMode mode, const std::vector<std::pair<size_t, size_t>> &volumes_and_instances)
|
||||
{
|
||||
if (! m_valid)
|
||||
return;
|
||||
|
||||
m_mode = mode;
|
||||
for (unsigned int i : m_list)
|
||||
(*m_volumes)[i]->selected = false;
|
||||
m_list.clear();
|
||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++ i)
|
||||
if (std::binary_search(volumes_and_instances.begin(), volumes_and_instances.end(), (*m_volumes)[i]->geometry_id))
|
||||
this->do_add_volume(i);
|
||||
update_type();
|
||||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
|
||||
void Selection::clear()
|
||||
{
|
||||
if (!m_valid)
|
||||
|
@ -790,6 +806,8 @@ void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
|
|||
double s = std::min(sx, std::min(sy, sz));
|
||||
if (s != 1.0)
|
||||
{
|
||||
wxGetApp().plater()->take_snapshot(_(L("Scale To Fit")));
|
||||
|
||||
TransformationType type;
|
||||
type.set_world();
|
||||
type.set_relative();
|
||||
|
@ -798,12 +816,12 @@ void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
|
|||
// apply scale
|
||||
start_dragging();
|
||||
scale(s * Vec3d::Ones(), type);
|
||||
wxGetApp().plater()->canvas3D()->do_scale();
|
||||
wxGetApp().plater()->canvas3D()->do_scale(""); // avoid storing another snapshot
|
||||
|
||||
// center selection on print bed
|
||||
start_dragging();
|
||||
translate(print_volume.center() - get_bounding_box().center());
|
||||
wxGetApp().plater()->canvas3D()->do_move();
|
||||
wxGetApp().plater()->canvas3D()->do_move(""); // avoid storing another snapshot
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
}
|
||||
|
@ -1177,7 +1195,7 @@ void Selection::copy_to_clipboard()
|
|||
ModelObject* dst_object = m_clipboard.add_object();
|
||||
dst_object->name = src_object->name;
|
||||
dst_object->input_file = src_object->input_file;
|
||||
dst_object->config = src_object->config;
|
||||
static_cast<DynamicPrintConfig&>(dst_object->config) = static_cast<const DynamicPrintConfig&>(src_object->config);
|
||||
dst_object->sla_support_points = src_object->sla_support_points;
|
||||
dst_object->sla_points_status = src_object->sla_points_status;
|
||||
dst_object->layer_config_ranges = src_object->layer_config_ranges; // #ys_FIXME_experiment
|
||||
|
@ -2016,6 +2034,10 @@ bool Selection::is_from_fully_selected_instance(unsigned int volume_idx) const
|
|||
|
||||
void Selection::paste_volumes_from_clipboard()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
check_model_ids_validity(*m_model);
|
||||
#endif /* _DEBUG */
|
||||
|
||||
int dst_obj_idx = get_object_idx();
|
||||
if ((dst_obj_idx < 0) || ((int)m_model->objects.size() <= dst_obj_idx))
|
||||
return;
|
||||
|
@ -2057,6 +2079,9 @@ void Selection::paste_volumes_from_clipboard()
|
|||
}
|
||||
|
||||
volumes.push_back(dst_volume);
|
||||
#ifdef _DEBUG
|
||||
check_model_ids_validity(*m_model);
|
||||
#endif /* _DEBUG */
|
||||
}
|
||||
|
||||
// keeps relative position of multivolume selections
|
||||
|
@ -2070,10 +2095,18 @@ void Selection::paste_volumes_from_clipboard()
|
|||
|
||||
wxGetApp().obj_list()->paste_volumes_into_list(dst_obj_idx, volumes);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
check_model_ids_validity(*m_model);
|
||||
#endif /* _DEBUG */
|
||||
}
|
||||
|
||||
void Selection::paste_objects_from_clipboard()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
check_model_ids_validity(*m_model);
|
||||
#endif /* _DEBUG */
|
||||
|
||||
std::vector<size_t> object_idxs;
|
||||
const ModelObjectPtrs& src_objects = m_clipboard.get_objects();
|
||||
for (const ModelObject* src_object : src_objects)
|
||||
|
@ -2087,9 +2120,16 @@ void Selection::paste_objects_from_clipboard()
|
|||
}
|
||||
|
||||
object_idxs.push_back(m_model->objects.size() - 1);
|
||||
#ifdef _DEBUG
|
||||
check_model_ids_validity(*m_model);
|
||||
#endif /* _DEBUG */
|
||||
}
|
||||
|
||||
wxGetApp().obj_list()->paste_objects_into_list(object_idxs);
|
||||
|
||||
#ifdef _DEBUG
|
||||
check_model_ids_validity(*m_model);
|
||||
#endif /* _DEBUG */
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
|
|
|
@ -171,7 +171,7 @@ private:
|
|||
Vec3d dragging_center;
|
||||
// Map from indices of ModelObject instances in Model::objects
|
||||
// to a set of indices of ModelVolume instances in ModelObject::instances
|
||||
// Here the index means a position inside the respective std::vector, not ModelID.
|
||||
// Here the index means a position inside the respective std::vector, not ObjectID.
|
||||
ObjectIdxsToInstanceIdxsMap content;
|
||||
};
|
||||
|
||||
|
@ -237,6 +237,9 @@ public:
|
|||
|
||||
void add_all();
|
||||
|
||||
// To be called after Undo or Redo once the volumes are updated.
|
||||
void set_deserialized(EMode mode, const std::vector<std::pair<size_t, size_t>> &volumes_and_instances);
|
||||
|
||||
// Update the selection based on the new instance IDs.
|
||||
void instances_changed(const std::vector<size_t> &instance_ids_selected);
|
||||
// Update the selection based on the map from old indices to new indices after m_volumes changed.
|
||||
|
|
|
@ -874,11 +874,10 @@ void Tab::update_wiping_button_visibility() {
|
|||
return; // ys_FIXME
|
||||
bool wipe_tower_enabled = dynamic_cast<ConfigOptionBool*>( (m_preset_bundle->prints.get_edited_preset().config ).option("wipe_tower"))->value;
|
||||
bool multiple_extruders = dynamic_cast<ConfigOptionFloats*>((m_preset_bundle->printers.get_edited_preset().config).option("nozzle_diameter"))->values.size() > 1;
|
||||
bool single_extruder_mm = dynamic_cast<ConfigOptionBool*>( (m_preset_bundle->printers.get_edited_preset().config).option("single_extruder_multi_material"))->value;
|
||||
|
||||
auto wiping_dialog_button = wxGetApp().sidebar().get_wiping_dialog_button();
|
||||
if (wiping_dialog_button) {
|
||||
wiping_dialog_button->Show(wipe_tower_enabled && multiple_extruders && single_extruder_mm);
|
||||
wiping_dialog_button->Show(wipe_tower_enabled && multiple_extruders);
|
||||
wiping_dialog_button->GetParent()->Layout();
|
||||
}
|
||||
}
|
||||
|
@ -1557,6 +1556,9 @@ void TabFilament::build()
|
|||
};
|
||||
optgroup->append_line(line);
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Wipe tower parameters")));
|
||||
optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower");
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Toolchange parameters with single extruder MM printers")));
|
||||
optgroup->append_single_option_line("filament_loading_speed_start");
|
||||
optgroup->append_single_option_line("filament_loading_speed");
|
||||
|
@ -1568,7 +1570,6 @@ void TabFilament::build()
|
|||
optgroup->append_single_option_line("filament_cooling_moves");
|
||||
optgroup->append_single_option_line("filament_cooling_initial_speed");
|
||||
optgroup->append_single_option_line("filament_cooling_final_speed");
|
||||
optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower");
|
||||
|
||||
line = optgroup->create_single_option_line("filament_ramming_parameters");// { _(L("Ramming")), "" };
|
||||
line.widget = [this](wxWindow* parent) {
|
||||
|
|
|
@ -172,7 +172,7 @@ void WipingPanel::format_sizer(wxSizer* sizer, wxPanel* page, wxGridSizer* grid_
|
|||
wxSize text_size = GetTextExtent(info);
|
||||
auto info_str = new wxStaticText(page, wxID_ANY, info ,wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
|
||||
info_str->Wrap(int(0.6*text_size.x));
|
||||
sizer->Add( info_str, 0, wxALIGN_CENTER_HORIZONTAL | wxEXPAND);
|
||||
sizer->Add( info_str, 0, wxEXPAND);
|
||||
auto table_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(table_sizer, 0, wxALIGN_CENTER | wxCENTER, table_lshift);
|
||||
table_sizer->Add(new wxStaticText(page, wxID_ANY, table_title), 0, wxALIGN_CENTER | wxTOP, 50);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue