mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-11-02 20:51:23 -07:00
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_gcode_window
This commit is contained in:
commit
da7d7ae11b
61 changed files with 6895 additions and 646 deletions
|
|
@ -68,14 +68,12 @@ void AppConfig::set_defaults()
|
|||
if (get("export_sources_full_pathnames").empty())
|
||||
set("export_sources_full_pathnames", "0");
|
||||
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#ifdef _WIN32
|
||||
if (get("associate_3mf").empty())
|
||||
set("associate_3mf", "0");
|
||||
if (get("associate_stl").empty())
|
||||
set("associate_stl", "0");
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
|
||||
// remove old 'use_legacy_opengl' parameter from this config, if present
|
||||
if (!get("use_legacy_opengl").empty())
|
||||
|
|
@ -127,14 +125,12 @@ void AppConfig::set_defaults()
|
|||
if (get("color_mapinulation_panel").empty())
|
||||
set("color_mapinulation_panel", "0");
|
||||
}
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
else {
|
||||
#ifdef _WIN32
|
||||
if (get("associate_gcode").empty())
|
||||
set("associate_gcode", "0");
|
||||
#endif // _WIN32
|
||||
}
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
|
||||
if (get("seq_top_layer_only").empty())
|
||||
set("seq_top_layer_only", "1");
|
||||
|
|
@ -156,12 +152,10 @@ void AppConfig::set_defaults()
|
|||
if (get("show_splash_screen").empty())
|
||||
set("show_splash_screen", "1");
|
||||
|
||||
#if ENABLE_CTRL_M_ON_WINDOWS
|
||||
#ifdef _WIN32
|
||||
if (get("use_legacy_3DConnexion").empty())
|
||||
set("use_legacy_3DConnexion", "0");
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CTRL_M_ON_WINDOWS
|
||||
|
||||
// Remove legacy window positions/sizes
|
||||
erase("", "main_frame_maximized");
|
||||
|
|
|
|||
|
|
@ -145,6 +145,8 @@ add_library(libslic3r STATIC
|
|||
Point.hpp
|
||||
Polygon.cpp
|
||||
Polygon.hpp
|
||||
MutablePolygon.cpp
|
||||
MutablePolygon.hpp
|
||||
PolygonTrimmer.cpp
|
||||
PolygonTrimmer.hpp
|
||||
Polyline.cpp
|
||||
|
|
|
|||
|
|
@ -667,6 +667,14 @@ namespace DoExport {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (ret.size() < MAX_TAGS_COUNT) {
|
||||
const CustomGCode::Info& custom_gcode_per_print_z = print.model().custom_gcode_per_print_z;
|
||||
for (const auto& gcode : custom_gcode_per_print_z.gcodes) {
|
||||
check(_(L("Custom G-code")), gcode.extra);
|
||||
if (ret.size() == MAX_TAGS_COUNT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1705,7 +1713,9 @@ namespace ProcessLayer
|
|||
{
|
||||
|
||||
static std::string emit_custom_gcode_per_print_z(
|
||||
GCode &gcodegen,
|
||||
const CustomGCode::Item *custom_gcode,
|
||||
unsigned int current_extruder_id,
|
||||
// ID of the first extruder printing this layer.
|
||||
unsigned int first_extruder_id,
|
||||
const PrintConfig &config)
|
||||
|
|
@ -1746,12 +1756,14 @@ namespace ProcessLayer
|
|||
// && !MMU1
|
||||
) {
|
||||
//! FIXME_in_fw show message during print pause
|
||||
gcode += config.pause_print_gcode;// pause print
|
||||
DynamicConfig cfg;
|
||||
cfg.set_key_value("color_change_extruder", new ConfigOptionInt(m600_extruder_before_layer));
|
||||
gcode += gcodegen.placeholder_parser_process("pause_print_gcode", config.pause_print_gcode, current_extruder_id, &cfg);
|
||||
gcode += "\n";
|
||||
gcode += "M117 Change filament for Extruder " + std::to_string(m600_extruder_before_layer) + "\n";
|
||||
}
|
||||
else {
|
||||
gcode += config.color_change_gcode;//ColorChangeCode;
|
||||
gcode += gcodegen.placeholder_parser_process("color_change_gcode", config.color_change_gcode, current_extruder_id);
|
||||
gcode += "\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -1767,7 +1779,7 @@ namespace ProcessLayer
|
|||
//! FIXME_in_fw show message during print pause
|
||||
if (!pause_print_msg.empty())
|
||||
gcode += "M117 " + pause_print_msg + "\n";
|
||||
gcode += config.pause_print_gcode;
|
||||
gcode += gcodegen.placeholder_parser_process("pause_print_gcode", config.pause_print_gcode, current_extruder_id);
|
||||
}
|
||||
else {
|
||||
// add tag for processor
|
||||
|
|
@ -1776,8 +1788,8 @@ namespace ProcessLayer
|
|||
#else
|
||||
gcode += ";" + GCodeProcessor::Custom_Code_Tag + "\n";
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
if (gcode_type == CustomGCode::Template) // Template Cistom Gcode
|
||||
gcode += config.template_custom_gcode;
|
||||
if (gcode_type == CustomGCode::Template) // Template Custom Gcode
|
||||
gcode += gcodegen.placeholder_parser_process("template_custom_gcode", config.template_custom_gcode, current_extruder_id);
|
||||
else // custom Gcode
|
||||
gcode += custom_gcode->extra;
|
||||
|
||||
|
|
@ -1803,7 +1815,6 @@ namespace Skirt {
|
|||
|
||||
static std::map<unsigned int, std::pair<size_t, size_t>> make_skirt_loops_per_extruder_1st_layer(
|
||||
const Print &print,
|
||||
const std::vector<GCode::LayerToPrint> & /*layers */,
|
||||
const LayerTools &layer_tools,
|
||||
// Heights (print_z) at which the skirt has already been extruded.
|
||||
std::vector<coordf_t> &skirt_done)
|
||||
|
|
@ -1811,7 +1822,8 @@ namespace Skirt {
|
|||
// Extrude skirt at the print_z of the raft layers and normal object layers
|
||||
// not at the print_z of the interlaced support material layers.
|
||||
std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder_out;
|
||||
if (skirt_done.empty() && print.has_skirt() && ! print.skirt().entities.empty()) {
|
||||
assert(skirt_done.empty());
|
||||
if (skirt_done.empty() && print.has_skirt() && ! print.skirt().entities.empty() && layer_tools.has_skirt) {
|
||||
skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out);
|
||||
skirt_done.emplace_back(layer_tools.print_z);
|
||||
}
|
||||
|
|
@ -1820,36 +1832,34 @@ namespace Skirt {
|
|||
|
||||
static std::map<unsigned int, std::pair<size_t, size_t>> make_skirt_loops_per_extruder_other_layers(
|
||||
const Print &print,
|
||||
const std::vector<GCode::LayerToPrint> &layers,
|
||||
const LayerTools &layer_tools,
|
||||
// First non-empty support layer.
|
||||
const SupportLayer *support_layer,
|
||||
// Heights (print_z) at which the skirt has already been extruded.
|
||||
std::vector<coordf_t> &skirt_done)
|
||||
{
|
||||
// Extrude skirt at the print_z of the raft layers and normal object layers
|
||||
// not at the print_z of the interlaced support material layers.
|
||||
std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder_out;
|
||||
if (print.has_skirt() && ! print.skirt().entities.empty() &&
|
||||
if (print.has_skirt() && ! print.skirt().entities.empty() && layer_tools.has_skirt &&
|
||||
// Not enough skirt layers printed yet.
|
||||
//FIXME infinite or high skirt does not make sense for sequential print!
|
||||
(skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt()) &&
|
||||
(skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt())) {
|
||||
bool valid = ! skirt_done.empty() && skirt_done.back() < layer_tools.print_z - EPSILON;
|
||||
assert(valid);
|
||||
// This print_z has not been extruded yet (sequential print)
|
||||
// FIXME: The skirt_done should not be empty at this point. The check is a workaround
|
||||
// of https://github.com/prusa3d/PrusaSlicer/issues/5652, but it deserves a real fix.
|
||||
(! skirt_done.empty() && skirt_done.back() < layer_tools.print_z - EPSILON) &&
|
||||
// and this layer is an object layer, or it is a raft layer.
|
||||
(layer_tools.has_object || support_layer->id() < (size_t)support_layer->object()->config().raft_layers.value)) {
|
||||
if (valid) {
|
||||
#if 0
|
||||
// Prime just the first printing extruder. This is original Slic3r's implementation.
|
||||
skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair<size_t, size_t>(0, print.config().skirts.value);
|
||||
// Prime just the first printing extruder. This is original Slic3r's implementation.
|
||||
skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair<size_t, size_t>(0, print.config().skirts.value);
|
||||
#else
|
||||
// Prime all extruders planned for this layer, see
|
||||
// https://github.com/prusa3d/PrusaSlicer/issues/469#issuecomment-322450619
|
||||
skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out);
|
||||
// Prime all extruders planned for this layer, see
|
||||
// https://github.com/prusa3d/PrusaSlicer/issues/469#issuecomment-322450619
|
||||
skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out);
|
||||
#endif
|
||||
assert(!skirt_done.empty());
|
||||
skirt_done.emplace_back(layer_tools.print_z);
|
||||
assert(!skirt_done.empty());
|
||||
skirt_done.emplace_back(layer_tools.print_z);
|
||||
}
|
||||
}
|
||||
return skirt_loops_per_extruder_out;
|
||||
}
|
||||
|
|
@ -1987,13 +1997,13 @@ void GCode::process_layer(
|
|||
|
||||
if (single_object_instance_idx == size_t(-1)) {
|
||||
// Normal (non-sequential) print.
|
||||
gcode += ProcessLayer::emit_custom_gcode_per_print_z(layer_tools.custom_gcode, first_extruder_id, print.config());
|
||||
gcode += ProcessLayer::emit_custom_gcode_per_print_z(*this, layer_tools.custom_gcode, m_writer.extruder()->id(), first_extruder_id, print.config());
|
||||
}
|
||||
// Extrude skirt at the print_z of the raft layers and normal object layers
|
||||
// not at the print_z of the interlaced support material layers.
|
||||
skirt_loops_per_extruder = first_layer ?
|
||||
Skirt::make_skirt_loops_per_extruder_1st_layer(print, layers, layer_tools, m_skirt_done) :
|
||||
Skirt::make_skirt_loops_per_extruder_other_layers(print, layers, layer_tools, support_layer, m_skirt_done);
|
||||
Skirt::make_skirt_loops_per_extruder_1st_layer(print, layer_tools, m_skirt_done) :
|
||||
Skirt::make_skirt_loops_per_extruder_other_layers(print, layer_tools, m_skirt_done);
|
||||
|
||||
// Group extrusions by an extruder, then by an object, an island and a region.
|
||||
std::map<unsigned int, std::vector<ObjectByExtruder>> by_extruder;
|
||||
|
|
@ -2840,9 +2850,11 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
|
|||
Polyline travel { this->last_pos(), point };
|
||||
|
||||
// check whether a straight travel move would need retraction
|
||||
bool needs_retraction = this->needs_retraction(travel, role);
|
||||
bool needs_retraction = this->needs_retraction(travel, role);
|
||||
// check whether wipe could be disabled without causing visible stringing
|
||||
bool could_be_wipe_disabled = false;
|
||||
bool could_be_wipe_disabled = false;
|
||||
// Save state of use_external_mp_once for the case that will be needed to call twice m_avoid_crossing_perimeters.travel_to.
|
||||
const bool used_external_mp_once = m_avoid_crossing_perimeters.used_external_mp_once();
|
||||
|
||||
// if a retraction would be needed, try to use avoid_crossing_perimeters to plan a
|
||||
// multi-hop travel path inside the configuration space
|
||||
|
|
@ -2870,8 +2882,13 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
|
|||
// Because of it, it is necessary to call avoid crossing perimeters again with new starting point after calling retraction()
|
||||
// FIXME Lukas H.: Try to predict if this second calling of avoid crossing perimeters will be needed or not. It could save computations.
|
||||
if (last_post_before_retract != this->last_pos() && m_config.avoid_crossing_perimeters) {
|
||||
Polyline retract_travel = m_avoid_crossing_perimeters.travel_to(*this, point);
|
||||
travel = std::move(retract_travel);
|
||||
// If in the previous call of m_avoid_crossing_perimeters.travel_to was use_external_mp_once set to true restore this value for next call.
|
||||
if (used_external_mp_once)
|
||||
m_avoid_crossing_perimeters.use_external_mp_once();
|
||||
travel = m_avoid_crossing_perimeters.travel_to(*this, point);
|
||||
// If state of use_external_mp_once was changed reset it to right value.
|
||||
if (used_external_mp_once)
|
||||
m_avoid_crossing_perimeters.reset_once_modifiers();
|
||||
}
|
||||
} else
|
||||
// Reset the wipe path when traveling, so one would not wipe along an old path.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ public:
|
|||
// Routing around the objects vs. inside a single object.
|
||||
void use_external_mp(bool use = true) { m_use_external_mp = use; };
|
||||
void use_external_mp_once() { m_use_external_mp_once = true; }
|
||||
bool used_external_mp_once() { return m_use_external_mp_once; }
|
||||
void disable_once() { m_disabled_once = true; }
|
||||
bool disabled_once() const { return m_disabled_once; }
|
||||
void reset_once_modifiers() { m_use_external_mp_once = false; m_disabled_once = false; }
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
#include "GCodeProcessor.hpp"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#if ENABLE_GCODE_WINDOW
|
||||
|
|
@ -597,12 +600,6 @@ const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> GCodeProces
|
|||
unsigned int GCodeProcessor::s_result_id = 0;
|
||||
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
static inline bool starts_with(const std::string_view comment, const std::string_view tag)
|
||||
{
|
||||
size_t tag_len = tag.size();
|
||||
return comment.size() >= tag_len && comment.substr(0, tag_len) == tag;
|
||||
}
|
||||
|
||||
bool GCodeProcessor::contains_reserved_tag(const std::string& gcode, std::string& found_tag)
|
||||
{
|
||||
bool ret = false;
|
||||
|
|
@ -613,7 +610,7 @@ bool GCodeProcessor::contains_reserved_tag(const std::string& gcode, std::string
|
|||
if (comment.length() > 2 && comment.front() == ';') {
|
||||
comment = comment.substr(1);
|
||||
for (const std::string& s : Reserved_Tags) {
|
||||
if (starts_with(comment, s)) {
|
||||
if (boost::starts_with(comment, s)) {
|
||||
ret = true;
|
||||
found_tag = comment;
|
||||
parser.quit_parsing();
|
||||
|
|
@ -638,7 +635,7 @@ bool GCodeProcessor::contains_reserved_tags(const std::string& gcode, unsigned i
|
|||
if (comment.length() > 2 && comment.front() == ';') {
|
||||
comment = comment.substr(1);
|
||||
for (const std::string& s : Reserved_Tags) {
|
||||
if (starts_with(comment, s)) {
|
||||
if (boost::starts_with(comment, s)) {
|
||||
ret = true;
|
||||
found_tag.push_back(comment);
|
||||
if (found_tag.size() == max_count) {
|
||||
|
|
@ -681,6 +678,8 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
|||
m_extruder_colors[i] = static_cast<unsigned char>(i);
|
||||
}
|
||||
|
||||
m_extruder_temps.resize(extruders_count);
|
||||
|
||||
m_filament_diameters.resize(config.filament_diameter.values.size());
|
||||
for (size_t i = 0; i < config.filament_diameter.values.size(); ++i) {
|
||||
m_filament_diameters[i] = static_cast<float>(config.filament_diameter.values[i]);
|
||||
|
|
@ -708,10 +707,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
|||
}
|
||||
|
||||
m_time_processor.export_remaining_time_enabled = config.remaining_times.value;
|
||||
|
||||
#if ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
m_use_volumetric_e = config.use_volumetric_e;
|
||||
#endif // ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
}
|
||||
|
||||
void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
|
|
@ -782,6 +778,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
|||
m_extruder_colors[i] = static_cast<unsigned char>(i);
|
||||
}
|
||||
|
||||
m_extruder_temps.resize(m_result.extruders_count);
|
||||
|
||||
const ConfigOptionFloats* filament_load_time = config.option<ConfigOptionFloats>("filament_load_time");
|
||||
if (filament_load_time != nullptr) {
|
||||
m_time_processor.filament_load_times.resize(filament_load_time->values.size());
|
||||
|
|
@ -873,11 +871,9 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
|||
if (m_time_processor.machine_limits.machine_max_acceleration_x.values.size() > 1)
|
||||
enable_stealth_time_estimator(true);
|
||||
|
||||
#if ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
const ConfigOptionBool* use_volumetric_e = config.option<ConfigOptionBool>("use_volumetric_e");
|
||||
if (use_volumetric_e != nullptr)
|
||||
m_use_volumetric_e = use_volumetric_e->value;
|
||||
#endif // ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
}
|
||||
|
||||
void GCodeProcessor::enable_stealth_time_estimator(bool enabled)
|
||||
|
|
@ -918,6 +914,10 @@ void GCodeProcessor::reset()
|
|||
for (size_t i = 0; i < Min_Extruder_Count; ++i) {
|
||||
m_extruder_colors[i] = static_cast<unsigned char>(i);
|
||||
}
|
||||
m_extruder_temps.resize(Min_Extruder_Count);
|
||||
for (size_t i = 0; i < Min_Extruder_Count; ++i) {
|
||||
m_extruder_temps[i] = 0.0f;
|
||||
}
|
||||
|
||||
m_filament_diameters = std::vector<float>(Min_Extruder_Count, 1.75f);
|
||||
m_extruded_last_z = 0.0f;
|
||||
|
|
@ -933,9 +933,7 @@ void GCodeProcessor::reset()
|
|||
m_result.reset();
|
||||
m_result.id = ++s_result_id;
|
||||
|
||||
#if ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
m_use_volumetric_e = false;
|
||||
#endif // ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
m_mm3_per_mm_compare.reset();
|
||||
|
|
@ -1136,9 +1134,11 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
|
|||
case 1: { process_M1(line); break; } // Sleep or Conditional stop
|
||||
case 82: { process_M82(line); break; } // Set extruder to absolute mode
|
||||
case 83: { process_M83(line); break; } // Set extruder to relative mode
|
||||
case 104: { process_M104(line); break; } // Set extruder temperature
|
||||
case 106: { process_M106(line); break; } // Set fan speed
|
||||
case 107: { process_M107(line); break; } // Disable fan
|
||||
case 108: { process_M108(line); break; } // Set tool (Sailfish)
|
||||
case 109: { process_M109(line); break; } // Set extruder temperature and wait
|
||||
case 132: { process_M132(line); break; } // Recall stored home offsets
|
||||
case 135: { process_M135(line); break; } // Set tool (MakerWare)
|
||||
case 201: { process_M201(line); break; } // Set max printing acceleration
|
||||
|
|
@ -1171,14 +1171,6 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
|
|||
}
|
||||
}
|
||||
|
||||
#if !ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
static inline bool starts_with(const std::string_view comment, const std::string_view tag)
|
||||
{
|
||||
size_t tag_len = tag.size();
|
||||
return comment.size() >= tag_len && comment.substr(0, tag_len) == tag;
|
||||
}
|
||||
#endif // !ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
#if __has_include(<charconv>)
|
||||
template <typename T, typename = void>
|
||||
struct is_from_chars_convertible : std::false_type {};
|
||||
|
|
@ -1232,37 +1224,37 @@ void GCodeProcessor::process_tags(const std::string_view comment)
|
|||
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
// extrusion role tag
|
||||
if (starts_with(comment, reserved_tag(ETags::Role))) {
|
||||
if (boost::starts_with(comment, reserved_tag(ETags::Role))) {
|
||||
m_extrusion_role = ExtrusionEntity::string_to_role(comment.substr(reserved_tag(ETags::Role).length()));
|
||||
return;
|
||||
}
|
||||
|
||||
// wipe start tag
|
||||
if (starts_with(comment, reserved_tag(ETags::Wipe_Start))) {
|
||||
if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Start))) {
|
||||
m_wiping = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// wipe end tag
|
||||
if (starts_with(comment, reserved_tag(ETags::Wipe_End))) {
|
||||
if (boost::starts_with(comment, reserved_tag(ETags::Wipe_End))) {
|
||||
m_wiping = false;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
// extrusion role tag
|
||||
if (starts_with(comment, Extrusion_Role_Tag)) {
|
||||
if (boost::starts_with(comment, Extrusion_Role_Tag)) {
|
||||
m_extrusion_role = ExtrusionEntity::string_to_role(comment.substr(Extrusion_Role_Tag.length()));
|
||||
return;
|
||||
}
|
||||
|
||||
// wipe start tag
|
||||
if (starts_with(comment, Wipe_Start_Tag)) {
|
||||
if (boost::starts_with(comment, Wipe_Start_Tag)) {
|
||||
m_wiping = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// wipe end tag
|
||||
if (starts_with(comment, Wipe_End_Tag)) {
|
||||
if (boost::starts_with(comment, Wipe_End_Tag)) {
|
||||
m_wiping = false;
|
||||
return;
|
||||
}
|
||||
|
|
@ -1271,26 +1263,26 @@ void GCodeProcessor::process_tags(const std::string_view comment)
|
|||
if (!m_producers_enabled || m_producer == EProducer::PrusaSlicer) {
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
// height tag
|
||||
if (starts_with(comment, reserved_tag(ETags::Height))) {
|
||||
if (boost::starts_with(comment, reserved_tag(ETags::Height))) {
|
||||
if (!parse_number(comment.substr(reserved_tag(ETags::Height).size()), m_forced_height))
|
||||
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ").";
|
||||
return;
|
||||
}
|
||||
// width tag
|
||||
if (starts_with(comment, reserved_tag(ETags::Width))) {
|
||||
if (boost::starts_with(comment, reserved_tag(ETags::Width))) {
|
||||
if (!parse_number(comment.substr(reserved_tag(ETags::Width).size()), m_forced_width))
|
||||
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
|
||||
return;
|
||||
}
|
||||
#else
|
||||
// height tag
|
||||
if (starts_with(comment, Height_Tag)) {
|
||||
if (boost::starts_with(comment, Height_Tag)) {
|
||||
if (!parse_number(comment.substr(Height_Tag.size()), m_forced_height))
|
||||
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ").";
|
||||
return;
|
||||
}
|
||||
// width tag
|
||||
if (starts_with(comment, Width_Tag)) {
|
||||
if (boost::starts_with(comment, Width_Tag)) {
|
||||
if (!parse_number(comment.substr(Width_Tag.size()), m_forced_width))
|
||||
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
|
||||
return;
|
||||
|
|
@ -1300,9 +1292,9 @@ void GCodeProcessor::process_tags(const std::string_view comment)
|
|||
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
// color change tag
|
||||
if (starts_with(comment, reserved_tag(ETags::Color_Change))) {
|
||||
if (boost::starts_with(comment, reserved_tag(ETags::Color_Change))) {
|
||||
unsigned char extruder_id = 0;
|
||||
if (starts_with(comment.substr(reserved_tag(ETags::Color_Change).size()), ",T")) {
|
||||
if (boost::starts_with(comment.substr(reserved_tag(ETags::Color_Change).size()), ",T")) {
|
||||
int eid;
|
||||
if (!parse_number(comment.substr(reserved_tag(ETags::Color_Change).size() + 2), eid) || eid < 0 || eid > 255) {
|
||||
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Color_Change (" << comment << ").";
|
||||
|
|
@ -1346,9 +1338,9 @@ void GCodeProcessor::process_tags(const std::string_view comment)
|
|||
}
|
||||
#else
|
||||
// color change tag
|
||||
if (starts_with(comment, Color_Change_Tag)) {
|
||||
if (boost::starts_with(comment, Color_Change_Tag)) {
|
||||
unsigned char extruder_id = 0;
|
||||
if (starts_with(comment.substr(Color_Change_Tag.size()), ",T")) {
|
||||
if (boost::starts_with(comment.substr(Color_Change_Tag.size()), ",T")) {
|
||||
int eid;
|
||||
if (! parse_number(comment.substr(Color_Change_Tag.size() + 2), eid) || eid < 0 || eid > 255) {
|
||||
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Color_Change (" << comment << ").";
|
||||
|
|
@ -1394,7 +1386,7 @@ void GCodeProcessor::process_tags(const std::string_view comment)
|
|||
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
// mm3_per_mm print tag
|
||||
if (starts_with(comment, Mm3_Per_Mm_Tag)) {
|
||||
if (boost::starts_with(comment, Mm3_Per_Mm_Tag)) {
|
||||
if (! parse_number(comment.substr(Mm3_Per_Mm_Tag.size()), m_mm3_per_mm_compare.last_tag_value))
|
||||
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Mm3_Per_Mm (" << comment << ").";
|
||||
return;
|
||||
|
|
@ -1846,14 +1838,10 @@ void GCodeProcessor::process_G0(const GCodeReader::GCodeLine& line)
|
|||
|
||||
void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
#if ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
float filament_diameter = (static_cast<size_t>(m_extruder_id) < m_filament_diameters.size()) ? m_filament_diameters[m_extruder_id] : m_filament_diameters.back();
|
||||
float filament_radius = 0.5f * filament_diameter;
|
||||
float area_filament_cross_section = static_cast<float>(M_PI) * sqr(filament_radius);
|
||||
auto absolute_position = [this, area_filament_cross_section](Axis axis, const GCodeReader::GCodeLine& lineG1) {
|
||||
#else
|
||||
auto absolute_position = [this](Axis axis, const GCodeReader::GCodeLine& lineG1) {
|
||||
#endif // ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
bool is_relative = (m_global_positioning_type == EPositioningType::Relative);
|
||||
if (axis == E)
|
||||
is_relative |= (m_e_local_positioning_type == EPositioningType::Relative);
|
||||
|
|
@ -1861,10 +1849,8 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
|
|||
if (lineG1.has(Slic3r::Axis(axis))) {
|
||||
float lengthsScaleFactor = (m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f;
|
||||
float ret = lineG1.value(Slic3r::Axis(axis)) * lengthsScaleFactor;
|
||||
#if ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
if (axis == E && m_use_volumetric_e)
|
||||
ret /= area_filament_cross_section;
|
||||
#endif // ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
return is_relative ? m_start_position[axis] + ret : m_origin[axis] + ret;
|
||||
}
|
||||
else
|
||||
|
|
@ -1922,11 +1908,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
|
|||
|
||||
if (type == EMoveType::Extrude) {
|
||||
float delta_xyz = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]));
|
||||
#if !ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
float filament_diameter = (static_cast<size_t>(m_extruder_id) < m_filament_diameters.size()) ? m_filament_diameters[m_extruder_id] : m_filament_diameters.back();
|
||||
float filament_radius = 0.5f * filament_diameter;
|
||||
float area_filament_cross_section = static_cast<float>(M_PI) * sqr(filament_radius);
|
||||
#endif // !ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
float volume_extruded_filament = area_filament_cross_section * delta_pos[E];
|
||||
float area_toolpath_cross_section = volume_extruded_filament / delta_xyz;
|
||||
|
||||
|
|
@ -2235,6 +2216,13 @@ void GCodeProcessor::process_M83(const GCodeReader::GCodeLine& line)
|
|||
m_e_local_positioning_type = EPositioningType::Relative;
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_M104(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
float new_temp;
|
||||
if (line.has_value('S', new_temp))
|
||||
m_extruder_temps[m_extruder_id] = new_temp;
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_M106(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
if (!line.has('P')) {
|
||||
|
|
@ -2267,6 +2255,21 @@ void GCodeProcessor::process_M108(const GCodeReader::GCodeLine& line)
|
|||
process_T(cmd.substr(pos));
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_M109(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
float new_temp;
|
||||
if (line.has_value('R', new_temp)) {
|
||||
float val;
|
||||
if (line.has_value('T', val)) {
|
||||
size_t eid = static_cast<size_t>(val);
|
||||
if (eid < m_extruder_temps.size())
|
||||
m_extruder_temps[eid] = new_temp;
|
||||
}
|
||||
else
|
||||
m_extruder_temps[m_extruder_id] = new_temp;
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_M132(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
// This command is used by Makerbot to load the current home position from EEPROM
|
||||
|
|
@ -2555,6 +2558,7 @@ void GCodeProcessor::store_move_vertex(EMoveType type)
|
|||
m_height,
|
||||
m_mm3_per_mm,
|
||||
m_fan_speed,
|
||||
m_extruder_temps[m_extruder_id],
|
||||
static_cast<float>(m_result.moves.size())
|
||||
};
|
||||
m_result.moves.emplace_back(vertex);
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ namespace Slic3r {
|
|||
private:
|
||||
using AxisCoords = std::array<float, 4>;
|
||||
using ExtruderColors = std::vector<unsigned char>;
|
||||
using ExtruderTemps = std::vector<float>;
|
||||
|
||||
enum class EUnits : unsigned char
|
||||
{
|
||||
|
|
@ -211,6 +212,7 @@ namespace Slic3r {
|
|||
float height{ 0.0f }; // mm
|
||||
float mm3_per_mm{ 0.0f };
|
||||
float fan_speed{ 0.0f }; // percentage
|
||||
float temperature{ 0.0f }; // Celsius degrees
|
||||
float time{ 0.0f }; // s
|
||||
|
||||
float volumetric_rate() const { return feedrate * mm3_per_mm; }
|
||||
|
|
@ -320,6 +322,7 @@ namespace Slic3r {
|
|||
float height{ 0.0f }; // mm
|
||||
float mm3_per_mm{ 0.0f };
|
||||
float fan_speed{ 0.0f }; // percentage
|
||||
float temperature{ 0.0f }; // Celsius degrees
|
||||
float time{ 0.0f }; // s
|
||||
|
||||
float volumetric_rate() const { return feedrate * mm3_per_mm; }
|
||||
|
|
@ -470,14 +473,13 @@ namespace Slic3r {
|
|||
ExtrusionRole m_extrusion_role;
|
||||
unsigned char m_extruder_id;
|
||||
ExtruderColors m_extruder_colors;
|
||||
ExtruderTemps m_extruder_temps;
|
||||
std::vector<float> m_filament_diameters;
|
||||
float m_extruded_last_z;
|
||||
unsigned int m_g1_line_id;
|
||||
unsigned int m_layer_id;
|
||||
CpColor m_cp_color;
|
||||
#if ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
bool m_use_volumetric_e;
|
||||
#endif // ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING
|
||||
|
||||
enum class EProducer
|
||||
{
|
||||
|
|
@ -590,6 +592,9 @@ namespace Slic3r {
|
|||
// Set extruder to relative mode
|
||||
void process_M83(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set extruder temperature
|
||||
void process_M104(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set fan speed
|
||||
void process_M106(const GCodeReader::GCodeLine& line);
|
||||
|
||||
|
|
@ -599,6 +604,9 @@ namespace Slic3r {
|
|||
// Set tool (Sailfish)
|
||||
void process_M108(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set extruder temperature and wait
|
||||
void process_M109(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Recall stored home offsets
|
||||
void process_M132(const GCodeReader::GCodeLine& line);
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,20 @@ unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, c
|
|||
return (extruder == 0) ? 0 : extruder - 1;
|
||||
}
|
||||
|
||||
static double calc_max_layer_height(const PrintConfig &config, double max_object_layer_height)
|
||||
{
|
||||
double max_layer_height = std::numeric_limits<double>::max();
|
||||
for (size_t i = 0; i < config.nozzle_diameter.values.size(); ++ i) {
|
||||
double mlh = config.max_layer_height.values[i];
|
||||
if (mlh == 0.)
|
||||
mlh = 0.75 * config.nozzle_diameter.values[i];
|
||||
max_layer_height = std::min(max_layer_height, mlh);
|
||||
}
|
||||
// The Prusa3D Fast (0.35mm layer height) print profile sets a higher layer height than what is normally allowed
|
||||
// by the nozzle. This is a hack and it works by increasing extrusion width. See GH #3919.
|
||||
return std::max(max_layer_height, max_object_layer_height);
|
||||
}
|
||||
|
||||
// For the use case when each object is printed separately
|
||||
// (print.config().complete_objects is true).
|
||||
ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material)
|
||||
|
|
@ -87,6 +101,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
|
|||
zs.emplace_back(layer->print_z);
|
||||
this->initialize_layers(zs);
|
||||
}
|
||||
double max_layer_height = calc_max_layer_height(object.print()->config(), object.config().layer_height);
|
||||
|
||||
// Collect extruders reuqired to print the layers.
|
||||
this->collect_extruders(object, std::vector<std::pair<double, unsigned int>>());
|
||||
|
|
@ -94,9 +109,11 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
|
|||
// Reorder the extruders to minimize tool switches.
|
||||
this->reorder_extruders(first_extruder);
|
||||
|
||||
this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, object.config().layer_height);
|
||||
this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, max_layer_height);
|
||||
|
||||
this->collect_extruder_statistics(prime_multi_material);
|
||||
|
||||
this->mark_skirt_layers(object.print()->config(), max_layer_height);
|
||||
}
|
||||
|
||||
// For the use case when all objects are printed at once.
|
||||
|
|
@ -128,6 +145,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
|
|||
}
|
||||
this->initialize_layers(zs);
|
||||
}
|
||||
max_layer_height = calc_max_layer_height(print.config(), max_layer_height);
|
||||
|
||||
// Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object.
|
||||
// Do it only if all the objects were configured to be printed with a single extruder.
|
||||
|
|
@ -150,6 +168,8 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
|
|||
this->fill_wipe_tower_partitions(print.config(), object_bottom_z, max_layer_height);
|
||||
|
||||
this->collect_extruder_statistics(prime_multi_material);
|
||||
|
||||
this->mark_skirt_layers(print.config(), max_layer_height);
|
||||
}
|
||||
|
||||
void ToolOrdering::initialize_layers(std::vector<coordf_t> &zs)
|
||||
|
|
@ -321,7 +341,7 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
|
|||
}
|
||||
}
|
||||
|
||||
void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_object_layer_height)
|
||||
void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height)
|
||||
{
|
||||
if (m_layer_tools.empty())
|
||||
return;
|
||||
|
|
@ -347,17 +367,6 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
|
|||
lt.has_wipe_tower = (lt.has_object && lt.wipe_tower_partitions > 0) || lt.print_z < object_bottom_z + EPSILON;
|
||||
|
||||
// Test for a raft, insert additional wipe tower layer to fill in the raft separation gap.
|
||||
double max_layer_height = std::numeric_limits<double>::max();
|
||||
for (size_t i = 0; i < config.nozzle_diameter.values.size(); ++ i) {
|
||||
double mlh = config.max_layer_height.values[i];
|
||||
if (mlh == 0.)
|
||||
mlh = 0.75 * config.nozzle_diameter.values[i];
|
||||
max_layer_height = std::min(max_layer_height, mlh);
|
||||
}
|
||||
// The Prusa3D Fast (0.35mm layer height) print profile sets a higher layer height than what is normally allowed
|
||||
// by the nozzle. This is a hack and it works by increasing extrusion width. See GH #3919.
|
||||
max_layer_height = std::max(max_layer_height, max_object_layer_height);
|
||||
|
||||
for (size_t i = 0; i + 1 < m_layer_tools.size(); ++ i) {
|
||||
const LayerTools < = m_layer_tools[i];
|
||||
const LayerTools <_next = m_layer_tools[i + 1];
|
||||
|
|
@ -460,6 +469,48 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material)
|
|||
}
|
||||
}
|
||||
|
||||
// Layers are marked for infinite skirt aka draft shield. Not all the layers have to be printed.
|
||||
void ToolOrdering::mark_skirt_layers(const PrintConfig &config, coordf_t max_layer_height)
|
||||
{
|
||||
if (m_layer_tools.empty())
|
||||
return;
|
||||
|
||||
if (m_layer_tools.front().extruders.empty()) {
|
||||
// Empty first layer, no skirt will be printed.
|
||||
//FIXME throw an exception?
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
for (;;) {
|
||||
m_layer_tools[i].has_skirt = true;
|
||||
size_t j = i + 1;
|
||||
for (; j < m_layer_tools.size() && ! m_layer_tools[j].has_object; ++ j);
|
||||
// i and j are two successive layers printing an object.
|
||||
if (j == m_layer_tools.size())
|
||||
// Don't print skirt above the last object layer.
|
||||
break;
|
||||
// Mark some printing intermediate layers as having skirt.
|
||||
double last_z = m_layer_tools[i].print_z;
|
||||
for (size_t k = i + 1; k < j; ++ k) {
|
||||
if (m_layer_tools[k + 1].print_z - last_z > max_layer_height + EPSILON) {
|
||||
// Layer k is the last one not violating the maximum layer height.
|
||||
// Don't extrude skirt on empty layers.
|
||||
while (m_layer_tools[k].extruders.empty())
|
||||
-- k;
|
||||
if (m_layer_tools[k].has_skirt) {
|
||||
// Skirt cannot be generated due to empty layers, there would be a missing layer in the skirt.
|
||||
//FIXME throw an exception?
|
||||
break;
|
||||
}
|
||||
m_layer_tools[k].has_skirt = true;
|
||||
last_z = m_layer_tools[k].print_z;
|
||||
}
|
||||
}
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
// Assign a pointer to a custom G-code to the respective ToolOrdering::LayerTools.
|
||||
// Ignore color changes, which are performed on a layer and for such an extruder, that the extruder will not be printing above that layer.
|
||||
// If multiple events are planned over a span of a single layer, use the last one.
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ class LayerTools;
|
|||
namespace CustomGCode { struct Item; }
|
||||
class PrintRegion;
|
||||
|
||||
|
||||
|
||||
// Object of this class holds information about whether an extrusion is printed immediately
|
||||
// after a toolchange (as part of infill/perimeter wiping) or not. One extrusion can be a part
|
||||
// of several copies - this has to be taken into account.
|
||||
|
|
@ -69,8 +67,6 @@ private:
|
|||
const LayerTools* m_layer_tools = nullptr; // so we know which LayerTools object this belongs to
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LayerTools
|
||||
{
|
||||
public:
|
||||
|
|
@ -99,6 +95,9 @@ public:
|
|||
// If per layer extruder switches are inserted by the G-code preview slider, this value contains the new (1 based) extruder, with which the whole object layer is being printed with.
|
||||
// If not overriden, it is set to 0.
|
||||
unsigned int extruder_override = 0;
|
||||
// Should a skirt be printed at this layer?
|
||||
// Layers are marked for infinite skirt aka draft shield. Not all the layers have to be printed.
|
||||
bool has_skirt = false;
|
||||
// Will there be anything extruded on this layer for the wipe tower?
|
||||
// Due to the support layers possibly interleaving the object layers,
|
||||
// wipe tower will be disabled for some support only layers.
|
||||
|
|
@ -120,12 +119,10 @@ private:
|
|||
WipingExtrusions m_wiping_extrusions;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ToolOrdering
|
||||
{
|
||||
public:
|
||||
ToolOrdering() {}
|
||||
ToolOrdering() = default;
|
||||
|
||||
// For the use case when each object is printed separately
|
||||
// (print.config.complete_objects is true).
|
||||
|
|
@ -169,6 +166,7 @@ private:
|
|||
void collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches);
|
||||
void reorder_extruders(unsigned int last_extruder_id);
|
||||
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height);
|
||||
void mark_skirt_layers(const PrintConfig &config, coordf_t max_layer_height);
|
||||
void collect_extruder_statistics(bool prime_multi_material);
|
||||
|
||||
std::vector<LayerTools> m_layer_tools;
|
||||
|
|
@ -182,8 +180,6 @@ private:
|
|||
const PrintConfig* m_print_config_ptr = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SLic3r
|
||||
|
||||
#endif /* slic3r_ToolOrdering_hpp_ */
|
||||
|
|
|
|||
|
|
@ -245,8 +245,7 @@ Polygon convex_hull(Points points)
|
|||
return hull;
|
||||
}
|
||||
|
||||
Pointf3s
|
||||
convex_hull(Pointf3s points)
|
||||
Pointf3s convex_hull(Pointf3s points)
|
||||
{
|
||||
assert(points.size() >= 3);
|
||||
// sort input points
|
||||
|
|
@ -304,8 +303,7 @@ convex_hull(Pointf3s points)
|
|||
return hull;
|
||||
}
|
||||
|
||||
Polygon
|
||||
convex_hull(const Polygons &polygons)
|
||||
Polygon convex_hull(const Polygons &polygons)
|
||||
{
|
||||
Points pp;
|
||||
for (Polygons::const_iterator p = polygons.begin(); p != polygons.end(); ++p) {
|
||||
|
|
|
|||
242
src/libslic3r/MutablePolygon.cpp
Normal file
242
src/libslic3r/MutablePolygon.cpp
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
#include "MutablePolygon.hpp"
|
||||
#include "Line.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Remove exact duplicate points. May reduce the polygon down to empty polygon.
|
||||
void remove_duplicates(MutablePolygon &polygon)
|
||||
{
|
||||
if (! polygon.empty()) {
|
||||
auto begin = polygon.begin();
|
||||
auto it = begin;
|
||||
for (++ it; it != begin;) {
|
||||
auto prev = it.prev();
|
||||
if (*prev == *it)
|
||||
it = it.remove();
|
||||
else
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove nearly duplicate points. May reduce the polygon down to empty polygon.
|
||||
void remove_duplicates(MutablePolygon &polygon, double eps)
|
||||
{
|
||||
if (! polygon.empty()) {
|
||||
auto eps2 = eps * eps;
|
||||
auto begin = polygon.begin();
|
||||
auto it = begin;
|
||||
for (++ it; it != begin;) {
|
||||
auto prev = it.prev();
|
||||
if ((*it - *prev).cast<double>().squaredNorm() < eps2)
|
||||
it = it.remove();
|
||||
else
|
||||
++ it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sample a point on line (a, b) at distance "dist" from ref_pt.
|
||||
// If two points fulfill the condition, then the first one (closer to point a) is taken.
|
||||
// If none of the two points falls on line (a, b), return false.
|
||||
template<typename VectorType>
|
||||
static inline VectorType point_on_line_at_dist(const VectorType &a, const VectorType &b, const VectorType &ref_pt, const double dist)
|
||||
{
|
||||
using T = typename VectorType::Scalar;
|
||||
auto v = b - a;
|
||||
auto l2 = v.squaredNorm();
|
||||
assert(l2 > T(0));
|
||||
auto vpt = ref_pt - a;
|
||||
// Parameter of the foot point of ref_pt on line (a, b).
|
||||
auto t = v.dot(vpt) / l2;
|
||||
// Foot point of ref_pt on line (a, b).
|
||||
auto foot_pt = a + t * v;
|
||||
auto dfoot2 = vpt.squaredNorm() - (foot_pt - ref_pt).squaredNorm();
|
||||
// Distance of the result point from the foot point, normalized to length of (a, b).
|
||||
auto dfoot = dfoot2 > T(0) ? sqrt(dfoot2) / sqrt(l2) : T(0);
|
||||
auto t_result = t - dfoot;
|
||||
if (t_result < T(0))
|
||||
t_result = t + dfoot;
|
||||
t_result = Slic3r::clamp(0., 1., t_result);
|
||||
return a + v * t;
|
||||
}
|
||||
|
||||
static bool smooth_corner_complex(const Vec2d p1, MutablePolygon::iterator &it0, MutablePolygon::iterator &it2, const double shortcut_length)
|
||||
{
|
||||
// walk away from the corner until the shortcut > shortcut_length or it would smooth a piece inward
|
||||
// - walk in both directions untill shortcut > shortcut_length
|
||||
// - stop walking in one direction if it would otherwise cut off a corner in that direction
|
||||
// - same in the other direction
|
||||
// - stop if both are cut off
|
||||
// walk by updating p0_it and p2_it
|
||||
double shortcut_length2 = shortcut_length * shortcut_length;
|
||||
bool forward_is_blocked = false;
|
||||
bool forward_is_too_far = false;
|
||||
bool backward_is_blocked = false;
|
||||
bool backward_is_too_far = false;
|
||||
for (;;) {
|
||||
const bool forward_has_converged = forward_is_blocked || forward_is_too_far;
|
||||
const bool backward_has_converged = backward_is_blocked || backward_is_too_far;
|
||||
if (forward_has_converged && backward_has_converged) {
|
||||
if (forward_is_too_far && backward_is_too_far && (*it0.prev() - *it2.next()).cast<double>().squaredNorm() < shortcut_length2) {
|
||||
// Trim the narrowing region.
|
||||
-- it0;
|
||||
++ it2;
|
||||
forward_is_too_far = false;
|
||||
backward_is_too_far = false;
|
||||
continue;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
const Vec2d p0 = it0->cast<double>();
|
||||
const Vec2d p2 = it2->cast<double>();
|
||||
if (! forward_has_converged && (backward_has_converged || (p2 - p1).squaredNorm() < (p0 - p1).squaredNorm())) {
|
||||
// walk forward
|
||||
const auto it2_2 = it2.next();
|
||||
const Vec2d p2_2 = it2_2->cast<double>();
|
||||
if (cross2(p2 - p0, p2_2 - p0) > 0) {
|
||||
forward_is_blocked = true;
|
||||
} else if ((p2_2 - p0).squaredNorm() > shortcut_length2) {
|
||||
forward_is_too_far = true;
|
||||
} else {
|
||||
it2 = it2_2; // make one step in the forward direction
|
||||
backward_is_blocked = false; // invalidate data about backward walking
|
||||
backward_is_too_far = false;
|
||||
}
|
||||
} else {
|
||||
// walk backward
|
||||
const auto it0_2 = it0.prev();
|
||||
const Vec2d p0_2 = it0_2->cast<double>();
|
||||
if (cross2(p0_2 - p0, p2 - p0_2) > 0) {
|
||||
backward_is_blocked = true;
|
||||
} else if ((p2 - p0_2).squaredNorm() > shortcut_length2) {
|
||||
backward_is_too_far = true;
|
||||
} else {
|
||||
it0 = it0_2; // make one step in the backward direction
|
||||
forward_is_blocked = false; // invalidate data about forward walking
|
||||
forward_is_too_far = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (it0.prev() == it2 || it0 == it2) {
|
||||
// stop if we went all the way around the polygon
|
||||
// this should only be the case for hole polygons (?)
|
||||
if (forward_is_too_far && backward_is_too_far) {
|
||||
// in case p0_it.prev() == p2_it :
|
||||
// / .
|
||||
// / /|
|
||||
// | becomes | |
|
||||
// \ \|
|
||||
// \ .
|
||||
// in case p0_it == p2_it :
|
||||
// / .
|
||||
// / becomes /|
|
||||
// \ \|
|
||||
// \ .
|
||||
break;
|
||||
} else {
|
||||
// this whole polygon can be removed
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Vec2d p0 = it0->cast<double>();
|
||||
const Vec2d p2 = it2->cast<double>();
|
||||
const Vec2d v02 = p2 - p0;
|
||||
const int64_t l2_v02 = v02.squaredNorm();
|
||||
if (std::abs(l2_v02 - shortcut_length2) < shortcut_length * 10) // i.e. if (size2 < l * (l+10) && size2 > l * (l-10))
|
||||
{ // v02 is approximately shortcut length
|
||||
// handle this separately to avoid rounding problems below in the getPointOnLineWithDist function
|
||||
// p0_it and p2_it are already correct
|
||||
} else if (! backward_is_blocked && ! forward_is_blocked) {
|
||||
const auto l_v02 = sqrt(l2_v02);
|
||||
const Vec2d p0_2 = it0.prev()->cast<double>();
|
||||
const Vec2d p2_2 = it2.next()->cast<double>();
|
||||
double t = Slic3r::clamp(0., 1., (shortcut_length - l_v02) / ((p2_2 - p0_2).norm() - l_v02));
|
||||
it0 = it0.prev().insert((p0 + (p0_2 - p0) * t).cast<coord_t>());
|
||||
it2 = it2.insert((p2 + (p2_2 - p2) * t).cast<coord_t>());
|
||||
} else if (! backward_is_blocked) {
|
||||
it0 = it0.prev().insert(point_on_line_at_dist(p0, Vec2d(it0.prev()->cast<double>()), p2, shortcut_length).cast<coord_t>());
|
||||
} else if (! forward_is_blocked) {
|
||||
it2 = it2.insert(point_on_line_at_dist(p2, Vec2d(it2.next()->cast<double>()), p0, shortcut_length).cast<coord_t>());
|
||||
} else {
|
||||
// |
|
||||
// __|2
|
||||
// | / > shortcut cannot be of the desired length
|
||||
// ___|/ .
|
||||
// 0
|
||||
// both are blocked and p0_it and p2_it are already correct
|
||||
}
|
||||
// Delete all the points between it0 and it2.
|
||||
while (it0.next() != it2)
|
||||
it0.next().remove();
|
||||
return false;
|
||||
}
|
||||
|
||||
void smooth_outward(MutablePolygon &polygon, double shortcut_length)
|
||||
{
|
||||
remove_duplicates(polygon, scaled<double>(0.01));
|
||||
|
||||
const int shortcut_length2 = shortcut_length * shortcut_length;
|
||||
static constexpr const double cos_min_angle = -0.70710678118654752440084436210485; // cos(135 degrees)
|
||||
|
||||
MutablePolygon::iterator it1 = polygon.begin();
|
||||
do {
|
||||
const Vec2d p1 = it1->cast<double>();
|
||||
auto it0 = it1.prev();
|
||||
auto it2 = it1.next();
|
||||
const Vec2d p0 = it0->cast<double>();
|
||||
const Vec2d p2 = it2->cast<double>();
|
||||
const Vec2d v1 = p0 - p1;
|
||||
const Vec2d v2 = p2 - p1;
|
||||
const double cos_angle = v1.dot(v2);
|
||||
if (cos_angle < cos_min_angle && cross2(v1, v2) < 0) {
|
||||
// Simplify the sharp angle.
|
||||
const Vec2d v02 = p2 - p0;
|
||||
const double l2_v02 = v02.squaredNorm();
|
||||
if (l2_v02 >= shortcut_length2) {
|
||||
// Trim an obtuse corner.
|
||||
it1.remove();
|
||||
if (l2_v02 > Slic3r::sqr(shortcut_length + SCALED_EPSILON)) {
|
||||
double l2_1 = v1.squaredNorm();
|
||||
double l2_2 = v2.squaredNorm();
|
||||
bool trim = true;
|
||||
if (cos_angle > 0.9999) {
|
||||
// The triangle p0, p1, p2 is likely degenerate.
|
||||
// Measure height of the triangle.
|
||||
double d2 = l2_1 > l2_2 ? line_alg::distance_to_squared(Linef{ p0, p1 }, p2) : line_alg::distance_to_squared(Linef{ p2, p1 }, p0);
|
||||
if (d2 < Slic3r::sqr(scaled<double>(0.02)))
|
||||
trim = false;
|
||||
}
|
||||
if (trim) {
|
||||
Vec2d bisector = v1 / l2_1 + v2 / l2_2;
|
||||
double d1 = v1.dot(bisector) / l2_1;
|
||||
double d2 = v2.dot(bisector) / l2_2;
|
||||
double lbisector = bisector.norm();
|
||||
if (d1 < shortcut_length && d2 < shortcut_length) {
|
||||
it0.insert((p1 + v1 * (shortcut_length / d1)).cast<coord_t>())
|
||||
.insert((p1 + v2 * (shortcut_length / d2)).cast<coord_t>());
|
||||
} else if (v1.squaredNorm() < v2.squaredNorm())
|
||||
it0.insert(point_on_line_at_dist(p1, p2, p0, shortcut_length).cast<coord_t>());
|
||||
else
|
||||
it0.insert(point_on_line_at_dist(p1, p0, p2, shortcut_length).cast<coord_t>());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool remove_poly = smooth_corner_complex(p1, it0, it2, shortcut_length); // edits p0_it and p2_it!
|
||||
if (remove_poly) {
|
||||
// don't convert ListPolygon into result
|
||||
return;
|
||||
}
|
||||
}
|
||||
// update:
|
||||
it1 = it2; // next point to consider for whether it's an internal corner
|
||||
}
|
||||
else
|
||||
++ it1;
|
||||
} while (it1 != polygon.begin());
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
227
src/libslic3r/MutablePolygon.hpp
Normal file
227
src/libslic3r/MutablePolygon.hpp
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
#ifndef slic3r_MutablePolygon_hpp_
|
||||
#define slic3r_MutablePolygon_hpp_
|
||||
|
||||
#include "Point.hpp"
|
||||
#include "Polygon.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class MutablePolygon
|
||||
{
|
||||
public:
|
||||
using IndexType = int32_t;
|
||||
using PointType = Point;
|
||||
class const_iterator {
|
||||
public:
|
||||
bool operator==(const const_iterator &rhs) const { assert(m_data == rhs.m_data); assert(this->valid()); return m_idx == rhs.m_idx; }
|
||||
bool operator!=(const const_iterator &rhs) const { return ! (*this == rhs); }
|
||||
const_iterator& operator--() { assert(this->valid()); m_idx = m_data->at(m_idx).prev; return *this; }
|
||||
const_iterator operator--(int) { const_iterator result(*this); --(*this); return result; }
|
||||
const_iterator& operator++() { assert(this->valid()); m_idx = m_data->at(m_idx).next; return *this; }
|
||||
const_iterator operator++(int) { const_iterator result(*this); ++(*this); return result; }
|
||||
const_iterator prev() const { assert(this->valid()); return { m_data, m_data->at(m_idx).prev }; }
|
||||
const_iterator next() const { assert(this->valid()); return { m_data, m_data->at(m_idx).next }; }
|
||||
bool valid() const { return m_idx >= 0; }
|
||||
const PointType& operator*() const { return m_data->at(m_idx).point; }
|
||||
const PointType* operator->() const { return &m_data->at(m_idx).point; }
|
||||
const MutablePolygon& polygon() const { assert(this->valid()); return *m_data; }
|
||||
IndexType size() const { assert(this->valid()); return m_data->size(); }
|
||||
private:
|
||||
const_iterator(const MutablePolygon *data, IndexType idx) : m_data(data), m_idx(idx) {}
|
||||
friend class MutablePolygon;
|
||||
const MutablePolygon *m_data;
|
||||
IndexType m_idx;
|
||||
};
|
||||
|
||||
class iterator {
|
||||
public:
|
||||
bool operator==(const iterator &rhs) const { assert(m_data == rhs.m_data); assert(this->valid()); return m_idx == rhs.m_idx; }
|
||||
bool operator!=(const iterator &rhs) const { return !(*this == rhs); }
|
||||
iterator& operator--() { assert(this->valid()); m_idx = m_data->at(m_idx).prev; return *this; }
|
||||
iterator operator--(int) { iterator result(*this); --(*this); return result; }
|
||||
iterator& operator++() { assert(this->valid()); m_idx = m_data->at(m_idx).next; return *this; }
|
||||
iterator operator++(int) { iterator result(*this); ++(*this); return result; }
|
||||
iterator prev() const { assert(this->valid()); return { m_data, m_data->at(m_idx).prev }; }
|
||||
iterator next() const { assert(this->valid()); return { m_data, m_data->at(m_idx).next }; }
|
||||
bool valid() const { return m_idx >= 0; }
|
||||
PointType& operator*() const { return m_data->at(m_idx).point; }
|
||||
PointType* operator->() const { return &m_data->at(m_idx).point; }
|
||||
MutablePolygon& polygon() const { assert(this->valid()); return *m_data; }
|
||||
IndexType size() const { assert(this->valid()); return m_data->size(); }
|
||||
iterator& remove() { this->m_idx = m_data->remove(*this).m_idx; return *this; }
|
||||
iterator insert(const PointType pt) const { return m_data->insert(*this, pt); }
|
||||
private:
|
||||
iterator(MutablePolygon *data, IndexType idx) : m_data(data), m_idx(idx) {}
|
||||
friend class MutablePolygon;
|
||||
MutablePolygon *m_data;
|
||||
IndexType m_idx;
|
||||
};
|
||||
|
||||
MutablePolygon() = default;
|
||||
MutablePolygon(const Polygon &rhs, size_t reserve = 0) : MutablePolygon(rhs.points.begin(), rhs.points.end(), reserve) {}
|
||||
MutablePolygon(std::initializer_list<Point> rhs, size_t reserve = 0) : MutablePolygon(rhs.begin(), rhs.end(), reserve) {}
|
||||
|
||||
template<typename IT>
|
||||
MutablePolygon(IT begin, IT end, size_t reserve = 0) {
|
||||
m_size = IndexType(end - begin);
|
||||
if (m_size > 0) {
|
||||
m_head = 0;
|
||||
m_data.reserve(std::max<size_t>(m_size, reserve));
|
||||
auto i = IndexType(-1);
|
||||
auto j = IndexType(1);
|
||||
for (auto it = begin; it != end; ++ it)
|
||||
m_data.push_back({ *it, i ++, j ++ });
|
||||
m_data.front().prev = m_size - 1;
|
||||
m_data.back ().next = 0;
|
||||
}
|
||||
};
|
||||
|
||||
Polygon polygon() const {
|
||||
Polygon out;
|
||||
if (this->valid()) {
|
||||
out.points.reserve(this->size());
|
||||
for (auto it = this->cbegin(); it != this->cend(); ++ it)
|
||||
out.points.emplace_back(*it);
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
bool empty() const { return this->m_size == 0; }
|
||||
size_t size() const { return this->m_size; }
|
||||
size_t capacity() const { return this->m_data.capacity(); }
|
||||
bool valid() const { return this->m_size >= 3; }
|
||||
|
||||
iterator begin() { return { this, m_head }; }
|
||||
const_iterator cbegin() const { return { this, m_head }; }
|
||||
const_iterator begin() const { return this->cbegin(); }
|
||||
// End points to the last item before roll over. This is different from the usual end() concept!
|
||||
iterator end() { return { this, this->empty() ? -1 : this->at(m_head).prev }; }
|
||||
const_iterator cend() const { return { this, this->empty() ? -1 : this->at(m_head).prev }; }
|
||||
const_iterator end() const { return this->cend(); }
|
||||
|
||||
// Returns iterator following the removed element. Returned iterator will become invalid if last point is removed.
|
||||
// If begin() is removed, then the next element will become the new begin().
|
||||
iterator remove(const iterator it) { assert(it.m_data == this); return { this, this->remove(it.m_idx) }; }
|
||||
// Insert a new point before it. Returns iterator to the newly inserted point.
|
||||
// begin() will not change, end() may point to the newly inserted point.
|
||||
iterator insert(const iterator it, const PointType pt) { assert(it.m_data == this); return { this, this->insert(it.m_idx, pt) }; }
|
||||
|
||||
private:
|
||||
struct LinkedPoint {
|
||||
PointType point;
|
||||
IndexType prev;
|
||||
IndexType next;
|
||||
};
|
||||
std::vector<LinkedPoint> m_data;
|
||||
// Number of points in the linked list.
|
||||
IndexType m_size { 0 };
|
||||
IndexType m_head { IndexType(-1) };
|
||||
// Head of the free list.
|
||||
IndexType m_head_free { IndexType(-1) };
|
||||
|
||||
LinkedPoint& at(IndexType i) { return m_data[i]; }
|
||||
const LinkedPoint& at(IndexType i) const { return m_data[i]; }
|
||||
|
||||
IndexType remove(const IndexType i) {
|
||||
assert(i >= 0);
|
||||
assert(m_size > 0);
|
||||
assert(m_head != -1);
|
||||
LinkedPoint &lp = this->at(i);
|
||||
IndexType prev = lp.prev;
|
||||
IndexType next = lp.next;
|
||||
lp.next = m_head_free;
|
||||
m_head_free = i;
|
||||
if (-- m_size == 0)
|
||||
m_head = -1;
|
||||
else if (m_head == i)
|
||||
m_head = next;
|
||||
assert(! this->empty() || (prev == i && next == i));
|
||||
if (this->empty())
|
||||
return IndexType(-1);
|
||||
this->at(prev).next = next;
|
||||
this->at(next).prev = prev;
|
||||
return next;
|
||||
}
|
||||
|
||||
IndexType insert(const IndexType i, const Point pt) {
|
||||
assert(i >= 0);
|
||||
IndexType n;
|
||||
IndexType j = this->at(i).prev;
|
||||
if (m_head_free == -1) {
|
||||
// Allocate a new item.
|
||||
n = IndexType(m_data.size());
|
||||
m_data.push_back({ pt, j, i });
|
||||
} else {
|
||||
n = m_head_free;
|
||||
LinkedPoint &nlp = this->at(n);
|
||||
m_head_free = nlp.next;
|
||||
nlp = { pt, j, i };
|
||||
}
|
||||
this->at(j).next = n;
|
||||
this->at(i).prev = n;
|
||||
++ m_size;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
IndexType insert(const IndexType i, const Point pt) {
|
||||
assert(i >= 0);
|
||||
if (this->at(i).point == pt)
|
||||
return i;
|
||||
IndexType j = this->at(i).next;
|
||||
if (this->at(j).point == pt)
|
||||
return i;
|
||||
IndexType n;
|
||||
if (m_head_free == -1) {
|
||||
// Allocate a new item.
|
||||
n = IndexType(m_data.size());
|
||||
m_data.push_back({ pt, i, j });
|
||||
} else {
|
||||
LinkedPoint &nlp = this->at(m_head_free);
|
||||
m_head_free = nlp.next;
|
||||
nlp = { pt, i, j };
|
||||
}
|
||||
this->at(i).next = n;
|
||||
this->at(j).prev = n;
|
||||
++ m_size;
|
||||
return n;
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
inline bool operator==(const MutablePolygon &p1, const MutablePolygon &p2)
|
||||
{
|
||||
if (p1.size() != p2.size())
|
||||
return false;
|
||||
if (p1.empty())
|
||||
return true;
|
||||
auto begin = p1.cbegin();
|
||||
auto it = begin;
|
||||
auto it2 = p2.cbegin();
|
||||
for (;;) {
|
||||
if (! (*it == *it2))
|
||||
return false;
|
||||
if (++ it == begin)
|
||||
return true;
|
||||
++ it2;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool operator!=(const MutablePolygon &p1, const MutablePolygon &p2) { return ! (p1 == p2); }
|
||||
|
||||
// Remove exact duplicate points. May reduce the polygon down to empty polygon.
|
||||
void remove_duplicates(MutablePolygon &polygon);
|
||||
void remove_duplicates(MutablePolygon &polygon, double eps);
|
||||
|
||||
void smooth_outward(MutablePolygon &polygon, double shortcut_length);
|
||||
|
||||
inline Polygon smooth_outward(const Polygon &polygon, double shortcut_length)
|
||||
{
|
||||
MutablePolygon mp(polygon, polygon.size() * 2);
|
||||
smooth_outward(mp, shortcut_length);
|
||||
return mp.polygon();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // slic3r_MutablePolygon_hpp_
|
||||
|
|
@ -56,11 +56,21 @@ typedef Eigen::Transform<double, 3, Eigen::Affine, Eigen::DontAlign> Transform3d
|
|||
|
||||
inline bool operator<(const Vec2d &lhs, const Vec2d &rhs) { return lhs(0) < rhs(0) || (lhs(0) == rhs(0) && lhs(1) < rhs(1)); }
|
||||
|
||||
// One likely does not want to perform the cross product with a 32bit accumulator.
|
||||
//inline int32_t cross2(const Vec2i32 &v1, const Vec2i32 &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||
inline int64_t cross2(const Vec2i64 &v1, const Vec2i64 &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||
inline float cross2(const Vec2f &v1, const Vec2f &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||
inline double cross2(const Vec2d &v1, const Vec2d &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||
template<int Options>
|
||||
int32_t cross2(const Eigen::MatrixBase<Eigen::Matrix<int32_t, 2, 1, Options>> &v1, const Eigen::MatrixBase<Eigen::Matrix<int32_t, 2, 1, Options>> &v2) = delete;
|
||||
|
||||
template<typename T, int Options>
|
||||
inline T cross2(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> &v1, const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> &v2)
|
||||
{
|
||||
return v1(0) * v2(1) - v1(1) * v2(0);
|
||||
}
|
||||
|
||||
template<typename Derived, typename Derived2>
|
||||
inline typename Derived::Scalar cross2(const Eigen::MatrixBase<Derived> &v1, const Eigen::MatrixBase<Derived2> &v2)
|
||||
{
|
||||
static_assert(std::is_same<typename Derived::Scalar, typename Derived2::Scalar>::value, "cross2(): Scalar types of 1st and 2nd operand must be equal.");
|
||||
return v1(0) * v2(1) - v1(1) * v2(0);
|
||||
}
|
||||
|
||||
template<typename T, int Options>
|
||||
inline Eigen::Matrix<T, 2, 1, Eigen::DontAlign> perp(const Eigen::MatrixBase<Eigen::Matrix<T, 2, 1, Options>> &v) { return Eigen::Matrix<T, 2, 1, Eigen::DontAlign>(- v.y(), v.x()); }
|
||||
|
|
|
|||
|
|
@ -1393,9 +1393,8 @@ const std::vector<std::string>& PhysicalPrinter::printer_options()
|
|||
static std::vector<std::string> s_opts;
|
||||
if (s_opts.empty()) {
|
||||
s_opts = {
|
||||
"preset_name",
|
||||
"preset_names",
|
||||
"printer_technology",
|
||||
// "printer_model",
|
||||
"host_type",
|
||||
"print_host",
|
||||
"printhost_apikey",
|
||||
|
|
@ -1453,11 +1452,10 @@ bool PhysicalPrinter::has_empty_config() const
|
|||
void PhysicalPrinter::update_preset_names_in_config()
|
||||
{
|
||||
if (!preset_names.empty()) {
|
||||
std::string name;
|
||||
for (auto el : preset_names)
|
||||
name += el + ";";
|
||||
name.pop_back();
|
||||
config.set_key_value("preset_name", new ConfigOptionString(name));
|
||||
std::vector<std::string>& values = config.option<ConfigOptionStrings>("preset_names")->values;
|
||||
values.clear();
|
||||
for (auto preset : preset_names)
|
||||
values.push_back(preset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1482,14 +1480,13 @@ void PhysicalPrinter::update_from_config(const DynamicPrintConfig& new_config)
|
|||
{
|
||||
config.apply_only(new_config, printer_options(), false);
|
||||
|
||||
std::string str = config.opt_string("preset_name");
|
||||
std::set<std::string> values{};
|
||||
if (!str.empty()) {
|
||||
boost::split(values, str, boost::is_any_of(";"));
|
||||
const std::vector<std::string>& values = config.option<ConfigOptionStrings>("preset_names")->values;
|
||||
|
||||
if (values.empty())
|
||||
preset_names.clear();
|
||||
else
|
||||
for (const std::string& val : values)
|
||||
preset_names.emplace(val);
|
||||
}
|
||||
preset_names = values;
|
||||
}
|
||||
|
||||
void PhysicalPrinter::reset_presets()
|
||||
|
|
@ -1817,7 +1814,7 @@ bool PhysicalPrinterCollection::delete_preset_from_printers( const std::string&
|
|||
return true;
|
||||
}
|
||||
|
||||
// Get list of printers which have more than one preset and "preset_name" preset is one of them
|
||||
// Get list of printers which have more than one preset and "preset_names" preset is one of them
|
||||
std::vector<std::string> PhysicalPrinterCollection::get_printers_with_preset(const std::string& preset_name)
|
||||
{
|
||||
std::vector<std::string> printers;
|
||||
|
|
@ -1832,7 +1829,7 @@ std::vector<std::string> PhysicalPrinterCollection::get_printers_with_preset(con
|
|||
return printers;
|
||||
}
|
||||
|
||||
// Get list of printers which has only "preset_name" preset
|
||||
// Get list of printers which has only "preset_names" preset
|
||||
std::vector<std::string> PhysicalPrinterCollection::get_printers_with_only_preset(const std::string& preset_name)
|
||||
{
|
||||
std::vector<std::string> printers;
|
||||
|
|
|
|||
|
|
@ -685,9 +685,9 @@ public:
|
|||
// returns true if all presets were deleted successfully.
|
||||
bool delete_preset_from_printers(const std::string& preset_name);
|
||||
|
||||
// Get list of printers which have more than one preset and "preset_name" preset is one of them
|
||||
// Get list of printers which have more than one preset and "preset_names" preset is one of them
|
||||
std::vector<std::string> get_printers_with_preset( const std::string &preset_name);
|
||||
// Get list of printers which has only "preset_name" preset
|
||||
// Get list of printers which has only "preset_names" preset
|
||||
std::vector<std::string> get_printers_with_only_preset( const std::string &preset_name);
|
||||
|
||||
// Return the selected preset, without the user modifications applied.
|
||||
|
|
|
|||
|
|
@ -876,6 +876,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
|||
this->filament_presets[i] = loaded->name;
|
||||
}
|
||||
}
|
||||
|
||||
// 4) Load the project config values (the per extruder wipe matrix etc).
|
||||
this->project_config.apply_only(config, s_project_options);
|
||||
|
||||
|
|
|
|||
|
|
@ -94,12 +94,14 @@ std::string PrintBase::output_filepath(const std::string &path, const std::strin
|
|||
return path;
|
||||
}
|
||||
|
||||
void PrintBase::status_update_warnings(ObjectID object_id, int step, PrintStateBase::WarningLevel /* warning_level */, const std::string &message)
|
||||
void PrintBase::status_update_warnings(int step, PrintStateBase::WarningLevel /* warning_level */, const std::string &message, const PrintObjectBase* print_object)
|
||||
{
|
||||
if (this->m_status_callback)
|
||||
m_status_callback(SlicingStatus(*this, step));
|
||||
if (this->m_status_callback) {
|
||||
auto status = print_object ? SlicingStatus(*print_object, step) : SlicingStatus(*this, step);
|
||||
m_status_callback(status);
|
||||
}
|
||||
else if (! message.empty())
|
||||
printf("%s warning: %s\n", (object_id == this->id()) ? "print" : "print object", message.c_str());
|
||||
printf("%s warning: %s\n", print_object ? "print_object" : "print", message.c_str());
|
||||
}
|
||||
|
||||
tbb::mutex& PrintObjectBase::state_mutex(PrintBase *print)
|
||||
|
|
@ -114,7 +116,7 @@ std::function<void()> PrintObjectBase::cancel_callback(PrintBase *print)
|
|||
|
||||
void PrintObjectBase::status_update_warnings(PrintBase *print, int step, PrintStateBase::WarningLevel warning_level, const std::string &message)
|
||||
{
|
||||
print->status_update_warnings(this->id(), step, warning_level, message);
|
||||
print->status_update_warnings(step, warning_level, message, this);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
|||
|
|
@ -481,7 +481,7 @@ protected:
|
|||
// Notify UI about a new warning of a milestone "step" on this PrintBase.
|
||||
// The UI will be notified by calling a status callback.
|
||||
// If no status callback is registered, the message is printed to console.
|
||||
void status_update_warnings(ObjectID object_id, int step, PrintStateBase::WarningLevel warning_level, const std::string &message);
|
||||
void status_update_warnings(int step, PrintStateBase::WarningLevel warning_level, const std::string &message, const PrintObjectBase* print_object = nullptr);
|
||||
|
||||
// If the background processing stop was requested, throw CanceledException.
|
||||
// To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly.
|
||||
|
|
@ -528,7 +528,7 @@ protected:
|
|||
PrintStateBase::TimeStamp set_done(PrintStepEnum step) {
|
||||
std::pair<PrintStateBase::TimeStamp, bool> status = m_state.set_done(step, this->state_mutex(), [this](){ this->throw_if_canceled(); });
|
||||
if (status.second)
|
||||
this->status_update_warnings(this->id(), static_cast<int>(step), PrintStateBase::WarningLevel::NON_CRITICAL, std::string());
|
||||
this->status_update_warnings(static_cast<int>(step), PrintStateBase::WarningLevel::NON_CRITICAL, std::string());
|
||||
return status.first;
|
||||
}
|
||||
bool invalidate_step(PrintStepEnum step)
|
||||
|
|
@ -550,7 +550,7 @@ protected:
|
|||
std::pair<PrintStepEnum, bool> active_step = m_state.active_step_add_warning(warning_level, message, message_id, this->state_mutex());
|
||||
if (active_step.second)
|
||||
// Update UI.
|
||||
this->status_update_warnings(this->id(), static_cast<int>(active_step.first), warning_level, message);
|
||||
this->status_update_warnings(static_cast<int>(active_step.first), warning_level, message);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -151,11 +151,11 @@ void PrintConfigDef::init_common_params()
|
|||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
|
||||
def = this->add("preset_name", coString);
|
||||
def->label = L("Printer preset name");
|
||||
def->tooltip = L("Related printer preset name");
|
||||
def = this->add("preset_names", coStrings);
|
||||
def->label = L("Printer preset names");
|
||||
def->tooltip = L("Names of presets related to the physical printer");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
def->set_default_value(new ConfigOptionStrings());
|
||||
|
||||
def = this->add("printhost_authorization_type", coEnum);
|
||||
def->label = L("Authorization Type");
|
||||
|
|
@ -3366,6 +3366,8 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
|||
opt_key = "printhost_cafile";
|
||||
} else if (opt_key == "octoprint_apikey") {
|
||||
opt_key = "printhost_apikey";
|
||||
} else if (opt_key == "preset_name") {
|
||||
opt_key = "preset_names";
|
||||
}
|
||||
|
||||
// Ignore the following obsolete configuration keys:
|
||||
|
|
|
|||
|
|
@ -513,7 +513,7 @@ public:
|
|||
ConfigOptionFloat support_material_interface_spacing;
|
||||
ConfigOptionFloatOrPercent support_material_interface_speed;
|
||||
ConfigOptionEnum<SupportMaterialPattern> support_material_pattern;
|
||||
ConfigOptionEnum<SupportMaterialPattern> support_material_interface_pattern;
|
||||
ConfigOptionEnum<SupportMaterialInterfacePattern> support_material_interface_pattern;
|
||||
// Spacing between support material lines (the hatching distance).
|
||||
ConfigOptionFloat support_material_spacing;
|
||||
ConfigOptionFloat support_material_speed;
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@ void PrintObject::generate_support_material()
|
|||
{
|
||||
if (this->set_started(posSupportMaterial)) {
|
||||
this->clear_support_layers();
|
||||
if (this->has_support_material() && m_layers.size() > 1) {
|
||||
if ((this->has_support() && m_layers.size() > 1) || (this->has_raft() && ! m_layers.empty())) {
|
||||
m_print->set_status(85, L("Generating support material"));
|
||||
this->_generate_support_material();
|
||||
m_print->throw_if_canceled();
|
||||
|
|
|
|||
|
|
@ -501,7 +501,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object)
|
|||
// If raft is to be generated, the 1st top_contact layer will contain the 1st object layer silhouette with holes filled.
|
||||
// There is also a 1st intermediate layer containing bases of support columns.
|
||||
// Inflate the bases of the support columns and create the raft base under the object.
|
||||
MyLayersPtr raft_layers = this->generate_raft_base(object, top_contacts, interface_layers, intermediate_layers, layer_storage);
|
||||
MyLayersPtr raft_layers = this->generate_raft_base(object, top_contacts, interface_layers, intermediate_layers, base_interface_layers, layer_storage);
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
for (const MyLayer *l : interface_layers)
|
||||
|
|
@ -1264,6 +1264,14 @@ namespace SupportMaterialInternal {
|
|||
offset(layerm->unsupported_bridge_edges, scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||
// Remove bridged areas from the supported areas.
|
||||
contact_polygons = diff(contact_polygons, bridges, true);
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
static int iRun = 0;
|
||||
SVG::export_expolygons(debug_out_path("support-top-contacts-remove-bridges-run%d.svg", iRun ++),
|
||||
{ { { union_ex(offset(layerm->unsupported_bridge_edges, scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS), false) }, { "unsupported_bridge_edges", "orange", 0.5f } },
|
||||
{ { union_ex(contact_polygons, false) }, { "contact_polygons", "blue", 0.5f } },
|
||||
{ { union_ex(bridges, false) }, { "bridges", "red", "black", "", scaled<coord_t>(0.1f), 0.5f } } });
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1678,7 +1686,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
|||
#endif /* SLIC3R_DEBUG */
|
||||
}
|
||||
}
|
||||
#ifdef SLIC3R_DEBUG
|
||||
#ifdef SLIC3R_DEBUG
|
||||
SVG::export_expolygons(debug_out_path("support-top-contacts-final0-run%d-layer%d-z%f.svg", iRun, layer_id, layer.print_z),
|
||||
{ { { union_ex(lower_layer_polygons, false) }, { "lower_layer_polygons", "gray", 0.2f } },
|
||||
{ { union_ex(*new_layer.contact_polygons, false) }, { "new_layer.contact_polygons", "yellow", 0.5f } },
|
||||
|
|
@ -2538,6 +2546,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
|
|||
const PrintObject &object,
|
||||
const MyLayersPtr &top_contacts,
|
||||
const MyLayersPtr &interface_layers,
|
||||
const MyLayersPtr &base_interface_layers,
|
||||
const MyLayersPtr &base_layers,
|
||||
MyLayerStorage &layer_storage) const
|
||||
{
|
||||
|
|
@ -2573,15 +2582,19 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
|
|||
// How much to inflate the support columns to be stable. This also applies to the 1st layer, if no raft layers are to be printed.
|
||||
const float inflate_factor_fine = float(scale_((m_slicing_params.raft_layers() > 1) ? 0.5 : EPSILON));
|
||||
const float inflate_factor_1st_layer = std::max(0.f, float(scale_(object.config().raft_first_layer_expansion)) - inflate_factor_fine);
|
||||
MyLayer *contacts = top_contacts .empty() ? nullptr : top_contacts .front();
|
||||
MyLayer *interfaces = interface_layers.empty() ? nullptr : interface_layers.front();
|
||||
MyLayer *columns_base = base_layers .empty() ? nullptr : base_layers .front();
|
||||
MyLayer *contacts = top_contacts .empty() ? nullptr : top_contacts .front();
|
||||
MyLayer *interfaces = interface_layers .empty() ? nullptr : interface_layers .front();
|
||||
MyLayer *base_interfaces = base_interface_layers.empty() ? nullptr : base_interface_layers.front();
|
||||
MyLayer *columns_base = base_layers .empty() ? nullptr : base_layers .front();
|
||||
if (contacts != nullptr && contacts->print_z > std::max(m_slicing_params.first_print_layer_height, m_slicing_params.raft_contact_top_z) + EPSILON)
|
||||
// This is not the raft contact layer.
|
||||
contacts = nullptr;
|
||||
if (interfaces != nullptr && interfaces->bottom_print_z() > m_slicing_params.raft_interface_top_z + EPSILON)
|
||||
// This is not the raft column base layer.
|
||||
interfaces = nullptr;
|
||||
if (base_interfaces != nullptr && base_interfaces->bottom_print_z() > m_slicing_params.raft_interface_top_z + EPSILON)
|
||||
// This is not the raft column base layer.
|
||||
base_interfaces = nullptr;
|
||||
if (columns_base != nullptr && columns_base->bottom_print_z() > m_slicing_params.raft_interface_top_z + EPSILON)
|
||||
// This is not the raft interface layer.
|
||||
columns_base = nullptr;
|
||||
|
|
@ -2591,6 +2604,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
|
|||
polygons_append(interface_polygons, offset(contacts->polygons, inflate_factor_fine, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||
if (interfaces != nullptr && ! interfaces->polygons.empty())
|
||||
polygons_append(interface_polygons, offset(interfaces->polygons, inflate_factor_fine, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||
if (base_interfaces != nullptr && ! base_interfaces->polygons.empty())
|
||||
polygons_append(interface_polygons, offset(base_interfaces->polygons, inflate_factor_fine, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||
|
||||
// Output vector.
|
||||
MyLayersPtr raft_layers;
|
||||
|
|
@ -2643,9 +2658,18 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
|
|||
}
|
||||
} else if (columns_base != nullptr) {
|
||||
// Expand the bases of the support columns in the 1st layer.
|
||||
columns_base->polygons = diff(
|
||||
inflate_factor_1st_layer > 0 ? offset(columns_base->polygons, inflate_factor_1st_layer) : columns_base->polygons,
|
||||
offset(m_object->layers().front()->lslices, (float)scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||
{
|
||||
Polygons &raft = columns_base->polygons;
|
||||
Polygons trimming = offset(m_object->layers().front()->lslices, (float)scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS);
|
||||
if (inflate_factor_1st_layer > SCALED_EPSILON) {
|
||||
// Inflate in multiple steps to avoid leaking of the support 1st layer through object walls.
|
||||
auto nsteps = std::max(5, int(ceil(inflate_factor_1st_layer / m_first_layer_flow.scaled_width())));
|
||||
float step = inflate_factor_1st_layer / nsteps;
|
||||
for (int i = 0; i < nsteps; ++ i)
|
||||
raft = diff(offset(raft, step), trimming);
|
||||
} else
|
||||
raft = diff(raft, trimming);
|
||||
}
|
||||
if (contacts != nullptr)
|
||||
columns_base->polygons = diff(columns_base->polygons, interface_polygons);
|
||||
if (! brim.empty()) {
|
||||
|
|
@ -2654,6 +2678,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
|
|||
contacts->polygons = diff(contacts->polygons, brim);
|
||||
if (interfaces)
|
||||
interfaces->polygons = diff(interfaces->polygons, brim);
|
||||
if (base_interfaces)
|
||||
base_interfaces->polygons = diff(base_interfaces->polygons, brim);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2706,7 +2732,7 @@ std::pair<PrintObjectSupportMaterial::MyLayersPtr, PrintObjectSupportMaterial::M
|
|||
layer_new.bridging = intermediate_layer.bridging;
|
||||
// Merge top into bottom, unite them with a safety offset.
|
||||
append(bottom, std::move(top));
|
||||
layer_new.polygons = union_(std::move(bottom), true);
|
||||
layer_new.polygons = intersection(union_(std::move(bottom), true), intermediate_layer.polygons);
|
||||
// Subtract the interface from the base regions.
|
||||
intermediate_layer.polygons = diff(intermediate_layer.polygons, layer_new.polygons, false);
|
||||
if (subtract)
|
||||
|
|
@ -3564,8 +3590,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
|
|||
// Base flange.
|
||||
filler->angle = raft_angle_1st_layer;
|
||||
filler->spacing = m_first_layer_flow.spacing();
|
||||
// 70% of density on the 1st layer.
|
||||
density = 0.7f;
|
||||
density = float(m_object_config->raft_first_layer_density.value * 0.01);
|
||||
} else if (support_layer_id >= m_slicing_params.base_raft_layers) {
|
||||
filler->angle = raft_angle_interface;
|
||||
// We don't use $base_flow->spacing because we need a constant spacing
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ private:
|
|||
const PrintObject &object,
|
||||
const MyLayersPtr &top_contacts,
|
||||
const MyLayersPtr &interface_layers,
|
||||
const MyLayersPtr &base_interface_layers,
|
||||
const MyLayersPtr &base_layers,
|
||||
MyLayerStorage &layer_storage) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
//=============
|
||||
// debug techs
|
||||
//=============
|
||||
|
||||
// Shows camera target in the 3D scene
|
||||
#define ENABLE_SHOW_CAMERA_TARGET 0
|
||||
// Log debug messages to console when changing selection
|
||||
|
|
@ -29,63 +28,12 @@
|
|||
#define ENABLE_GCODE_VIEWER_DATA_CHECKING 0
|
||||
|
||||
|
||||
//=================
|
||||
// 2.2.0.rc1 techs
|
||||
//=================
|
||||
#define ENABLE_2_2_0_RC1 1
|
||||
|
||||
// Enable hack to remove crash when closing on OSX 10.9.5
|
||||
#define ENABLE_HACK_CLOSING_ON_OSX_10_9_5 (1 && ENABLE_2_2_0_RC1)
|
||||
|
||||
|
||||
//====================
|
||||
// 2.3.0.alpha1 techs
|
||||
//====================
|
||||
#define ENABLE_2_3_0_ALPHA1 1
|
||||
|
||||
// Enable rendering of objects using environment map
|
||||
#define ENABLE_ENVIRONMENT_MAP (0 && ENABLE_2_3_0_ALPHA1)
|
||||
|
||||
#define ENABLE_ENVIRONMENT_MAP 0
|
||||
// Enable smoothing of objects normals
|
||||
#define ENABLE_SMOOTH_NORMALS (0 && ENABLE_2_3_0_ALPHA1)
|
||||
|
||||
// Enable error logging for OpenGL calls when SLIC3R_LOGLEVEL >= 5
|
||||
#define ENABLE_OPENGL_ERROR_LOGGING (1 && ENABLE_2_3_0_ALPHA1)
|
||||
|
||||
// Enable built-in DPI changed event handler of wxWidgets 3.1.3
|
||||
#define ENABLE_WX_3_1_3_DPI_CHANGED_EVENT (1 && ENABLE_2_3_0_ALPHA1)
|
||||
|
||||
|
||||
//====================
|
||||
// 2.3.0.alpha3 techs
|
||||
//====================
|
||||
#define ENABLE_2_3_0_ALPHA3 1
|
||||
|
||||
#define ENABLE_CTRL_M_ON_WINDOWS (1 && ENABLE_2_3_0_ALPHA3)
|
||||
|
||||
|
||||
//====================
|
||||
// 2.3.0.alpha4 techs
|
||||
//====================
|
||||
#define ENABLE_2_3_0_ALPHA4 1
|
||||
|
||||
#define ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS (1 && ENABLE_2_3_0_ALPHA4)
|
||||
|
||||
|
||||
//===================
|
||||
// 2.3.0.beta1 techs
|
||||
//===================
|
||||
#define ENABLE_2_3_0_BETA1 1
|
||||
|
||||
#define ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN (1 && ENABLE_2_3_0_BETA1)
|
||||
|
||||
|
||||
//=================
|
||||
// 2.3.0.rc1 techs
|
||||
//=================
|
||||
#define ENABLE_2_3_0_RC1 1
|
||||
|
||||
#define ENABLE_VOLUMETRIC_EXTRUSION_PROCESSING (1 && ENABLE_2_3_0_RC1)
|
||||
#define ENABLE_SMOOTH_NORMALS 0
|
||||
// Enable rendering markers for options in preview as fixed screen size points
|
||||
#define ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS 1
|
||||
|
||||
|
||||
//====================
|
||||
|
|
@ -93,11 +41,17 @@
|
|||
//====================
|
||||
#define ENABLE_2_3_1_ALPHA1 1
|
||||
|
||||
// Enable splitting of vertex buffers used to render toolpaths
|
||||
#define ENABLE_SPLITTED_VERTEX_BUFFER (1 && ENABLE_2_3_1_ALPHA1)
|
||||
#define ENABLE_RELOAD_FROM_DISK_FOR_3MF (1 && ENABLE_2_3_1_ALPHA1)
|
||||
// Enable rendering only starting and final caps for toolpaths
|
||||
#define ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS (1 && ENABLE_SPLITTED_VERTEX_BUFFER)
|
||||
// Enable reload from disk command for 3mf files
|
||||
#define ENABLE_RELOAD_FROM_DISK_FOR_3MF (1 && ENABLE_2_3_1_ALPHA1)
|
||||
// Removes obsolete warning texture code
|
||||
#define ENABLE_WARNING_TEXTURE_REMOVAL (1 && ENABLE_2_3_1_ALPHA1)
|
||||
// Enable showing gcode line numbers in previeww horizontal slider
|
||||
#define ENABLE_GCODE_LINES_ID_IN_H_SLIDER (1 && ENABLE_2_3_1_ALPHA1)
|
||||
// Enable validation of custom gcode against gcode processor reserved keywords
|
||||
#define ENABLE_VALIDATE_CUSTOM_GCODE (1 && ENABLE_2_3_1_ALPHA1)
|
||||
#define ENABLE_GCODE_WINDOW (1 && ENABLE_2_3_1_ALPHA1)
|
||||
|
||||
|
|
|
|||
|
|
@ -39,12 +39,11 @@
|
|||
#ifdef HAS_GLSAFE
|
||||
void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char* function_name)
|
||||
{
|
||||
#if defined(NDEBUG) && ENABLE_OPENGL_ERROR_LOGGING
|
||||
// In release mode, if OpenGL debugging was forced by ENABLE_OPENGL_ERROR_LOGGING, only show
|
||||
// OpenGL errors if sufficiently high loglevel.
|
||||
#if defined(NDEBUG)
|
||||
// In release mode, only show OpenGL errors if sufficiently high loglevel.
|
||||
if (Slic3r::get_logging_level() < 5)
|
||||
return;
|
||||
#endif // ENABLE_OPENGL_ERROR_LOGGING
|
||||
#endif // NDEBUG
|
||||
|
||||
GLenum err = glGetError();
|
||||
if (err == GL_NO_ERROR)
|
||||
|
|
|
|||
|
|
@ -10,10 +10,7 @@
|
|||
|
||||
#include <functional>
|
||||
|
||||
#if ENABLE_OPENGL_ERROR_LOGGING || ! defined(NDEBUG)
|
||||
#define HAS_GLSAFE
|
||||
#endif
|
||||
|
||||
#define HAS_GLSAFE
|
||||
#ifdef HAS_GLSAFE
|
||||
extern void glAssertRecentCallImpl(const char *file_name, unsigned int line, const char *function_name);
|
||||
inline void glAssertRecentCall() { glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); }
|
||||
|
|
|
|||
|
|
@ -629,13 +629,13 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin
|
|||
append(html_window, 0, wxEXPAND);
|
||||
|
||||
list_printer->Bind(wxEVT_LISTBOX, [this](wxCommandEvent& evt) {
|
||||
update_lists(evt.GetInt(), list_type->GetSelection(), list_vendor->GetSelection());
|
||||
update_lists(list_type->GetSelection(), list_vendor->GetSelection(), evt.GetInt());
|
||||
});
|
||||
list_type->Bind(wxEVT_LISTBOX, [this](wxCommandEvent &) {
|
||||
update_lists(list_printer->GetSelection(), list_type->GetSelection(), list_vendor->GetSelection());
|
||||
update_lists(list_type->GetSelection(), list_vendor->GetSelection());
|
||||
});
|
||||
list_vendor->Bind(wxEVT_LISTBOX, [this](wxCommandEvent &) {
|
||||
update_lists(list_printer->GetSelection(), list_type->GetSelection(), list_vendor->GetSelection());
|
||||
update_lists(list_type->GetSelection(), list_vendor->GetSelection());
|
||||
});
|
||||
|
||||
list_profile->Bind(wxEVT_CHECKLISTBOX, [this](wxCommandEvent &evt) { select_material(evt.GetInt()); });
|
||||
|
|
@ -681,8 +681,7 @@ void PageMaterials::reload_presets()
|
|||
sort_list_data(list_printer, true, false);
|
||||
if (list_printer->GetCount() > 0) {
|
||||
list_printer->SetSelection(0);
|
||||
sel_printer_count_prev = wxNOT_FOUND;
|
||||
sel_printer_item_prev = wxNOT_FOUND;
|
||||
sel_printers_prev.Clear();
|
||||
sel_type_prev = wxNOT_FOUND;
|
||||
sel_vendor_prev = wxNOT_FOUND;
|
||||
update_lists(0, 0, 0);
|
||||
|
|
@ -812,7 +811,7 @@ void PageMaterials::on_material_highlighted(int sel_material)
|
|||
set_compatible_printers_html_window(names, names.size() == materials->printers.size());
|
||||
}
|
||||
|
||||
void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor)
|
||||
void PageMaterials::update_lists(int sel_type, int sel_vendor, int last_selected_printer/* = -1*/)
|
||||
{
|
||||
wxWindowUpdateLocker freeze_guard(this);
|
||||
(void)freeze_guard;
|
||||
|
|
@ -820,7 +819,22 @@ void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor)
|
|||
wxArrayInt sel_printers;
|
||||
int sel_printers_count = list_printer->GetSelections(sel_printers);
|
||||
|
||||
if (sel_printers_count != sel_printer_count_prev || (sel_printers_count == 1 && sel_printer_item_prev != sel_printer && sel_printer != -1)) {
|
||||
// Does our wxWidgets version support operator== for wxArrayInt ?
|
||||
// https://github.com/prusa3d/PrusaSlicer/issues/5152#issuecomment-787208614
|
||||
#if wxCHECK_VERSION(3, 1, 1)
|
||||
if (sel_printers != sel_printers_prev) {
|
||||
#else
|
||||
auto are_equal = [](const wxArrayInt& arr_first, const wxArrayInt& arr_second) {
|
||||
if (arr_first.GetCount() != arr_second.GetCount())
|
||||
return false;
|
||||
for (size_t i = 0; i < arr_first.GetCount(); i++)
|
||||
if (arr_first[i] != arr_second[i])
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
if (!are_equal(sel_printers, sel_printers_prev)) {
|
||||
#endif
|
||||
|
||||
// Refresh type list
|
||||
list_type->Clear();
|
||||
list_type->append(_L("(All)"), &EMPTY);
|
||||
|
|
@ -828,7 +842,7 @@ void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor)
|
|||
// If all is selected with other printers
|
||||
// unselect "all" or all printers depending on last value
|
||||
if (sel_printers[0] == 0 && sel_printers_count > 1) {
|
||||
if (sel_printer == 0) {
|
||||
if (last_selected_printer == 0) {
|
||||
list_printer->SetSelection(wxNOT_FOUND);
|
||||
list_printer->SetSelection(0);
|
||||
} else {
|
||||
|
|
@ -869,8 +883,7 @@ void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor)
|
|||
sort_list_data(list_type, true, true);
|
||||
}
|
||||
|
||||
sel_printer_count_prev = sel_printers_count;
|
||||
sel_printer_item_prev = sel_printer;
|
||||
sel_printers_prev = sel_printers;
|
||||
sel_type = 0;
|
||||
sel_type_prev = wxNOT_FOUND;
|
||||
list_type->SetSelection(sel_type);
|
||||
|
|
@ -1089,8 +1102,7 @@ void PageMaterials::clear()
|
|||
list_type->Clear();
|
||||
list_vendor->Clear();
|
||||
list_profile->Clear();
|
||||
sel_printer_count_prev = wxNOT_FOUND;
|
||||
sel_printer_item_prev = wxNOT_FOUND;
|
||||
sel_printers_prev.Clear();
|
||||
sel_type_prev = wxNOT_FOUND;
|
||||
sel_vendor_prev = wxNOT_FOUND;
|
||||
presets_loaded = false;
|
||||
|
|
@ -1189,7 +1201,6 @@ PageReloadFromDisk::PageReloadFromDisk(ConfigWizard* parent)
|
|||
box_pathnames->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& event) { this->full_pathnames = event.IsChecked(); });
|
||||
}
|
||||
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#ifdef _WIN32
|
||||
PageFilesAssociation::PageFilesAssociation(ConfigWizard* parent)
|
||||
: ConfigWizardPage(parent, _L("Files association"), _L("Files association"))
|
||||
|
|
@ -1203,7 +1214,6 @@ PageFilesAssociation::PageFilesAssociation(ConfigWizard* parent)
|
|||
// append(cb_gcode);
|
||||
}
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
|
||||
PageMode::PageMode(ConfigWizard *parent)
|
||||
: ConfigWizardPage(parent, _L("View mode"), _L("View mode"))
|
||||
|
|
@ -1816,11 +1826,9 @@ void ConfigWizard::priv::load_pages()
|
|||
|
||||
index->add_page(page_update);
|
||||
index->add_page(page_reload_from_disk);
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#ifdef _WIN32
|
||||
index->add_page(page_files_association);
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
index->add_page(page_mode);
|
||||
|
||||
index->go_to(former_active); // Will restore the active item/page if possible
|
||||
|
|
@ -2414,7 +2422,6 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
|
|||
app_config->set("preset_update", page_update->preset_update ? "1" : "0");
|
||||
app_config->set("export_sources_full_pathnames", page_reload_from_disk->full_pathnames ? "1" : "0");
|
||||
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#ifdef _WIN32
|
||||
app_config->set("associate_3mf", page_files_association->associate_3mf() ? "1" : "0");
|
||||
app_config->set("associate_stl", page_files_association->associate_stl() ? "1" : "0");
|
||||
|
|
@ -2432,7 +2439,6 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
|
|||
// }
|
||||
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
|
||||
page_mode->serialize_mode(app_config);
|
||||
|
||||
|
|
@ -2597,11 +2603,9 @@ ConfigWizard::ConfigWizard(wxWindow *parent)
|
|||
|
||||
p->add_page(p->page_update = new PageUpdate(this));
|
||||
p->add_page(p->page_reload_from_disk = new PageReloadFromDisk(this));
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#ifdef _WIN32
|
||||
p->add_page(p->page_files_association = new PageFilesAssociation(this));
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
p->add_page(p->page_mode = new PageMode(this));
|
||||
p->add_page(p->page_firmware = new PageFirmware(this));
|
||||
p->add_page(p->page_bed = new PageBedShape(this));
|
||||
|
|
|
|||
|
|
@ -327,7 +327,8 @@ struct PageMaterials: ConfigWizardPage
|
|||
Materials *materials;
|
||||
StringList *list_printer, *list_type, *list_vendor;
|
||||
PresetList *list_profile;
|
||||
int sel_printer_count_prev, sel_printer_item_prev, sel_type_prev, sel_vendor_prev;
|
||||
wxArrayInt sel_printers_prev;
|
||||
int sel_type_prev, sel_vendor_prev;
|
||||
bool presets_loaded;
|
||||
|
||||
wxFlexGridSizer *grid;
|
||||
|
|
@ -342,7 +343,7 @@ struct PageMaterials: ConfigWizardPage
|
|||
PageMaterials(ConfigWizard *parent, Materials *materials, wxString title, wxString shortname, wxString list1name);
|
||||
|
||||
void reload_presets();
|
||||
void update_lists(int sel1, int sel2, int sel3);
|
||||
void update_lists(int sel_type, int sel_vendor, int last_selected_printer = -1);
|
||||
void on_material_highlighted(int sel_material);
|
||||
void on_material_hovered(int sel_material);
|
||||
void select_material(int i);
|
||||
|
|
@ -392,7 +393,6 @@ struct PageReloadFromDisk : ConfigWizardPage
|
|||
PageReloadFromDisk(ConfigWizard* parent);
|
||||
};
|
||||
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#ifdef _WIN32
|
||||
struct PageFilesAssociation : ConfigWizardPage
|
||||
{
|
||||
|
|
@ -409,7 +409,6 @@ public:
|
|||
// bool associate_gcode() const { return cb_gcode->IsChecked(); }
|
||||
};
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
|
||||
struct PageMode: ConfigWizardPage
|
||||
{
|
||||
|
|
@ -571,11 +570,9 @@ struct ConfigWizard::priv
|
|||
PageCustom *page_custom = nullptr;
|
||||
PageUpdate *page_update = nullptr;
|
||||
PageReloadFromDisk *page_reload_from_disk = nullptr;
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#ifdef _WIN32
|
||||
PageFilesAssociation* page_files_association = nullptr;
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
PageMode *page_mode = nullptr;
|
||||
PageVendors *page_vendors = nullptr;
|
||||
Pages3rdparty pages_3rdparty;
|
||||
|
|
|
|||
|
|
@ -183,11 +183,13 @@ void GCodeViewer::TBuffer::add_path(const GCodeProcessor::MoveVertex& move, unsi
|
|||
// use rounding to reduce the number of generated paths
|
||||
#if ENABLE_SPLITTED_VERTEX_BUFFER
|
||||
paths.push_back({ move.type, move.extrusion_role, move.delta_extruder,
|
||||
round_to_nearest(move.height, 2), round_to_nearest(move.width, 2), move.feedrate, move.fan_speed,
|
||||
round_to_nearest(move.height, 2), round_to_nearest(move.width, 2),
|
||||
move.feedrate, move.fan_speed, move.temperature,
|
||||
move.volumetric_rate(), move.extruder_id, move.cp_color_id, { { endpoint, endpoint } } });
|
||||
#else
|
||||
paths.push_back({ move.type, move.extrusion_role, endpoint, endpoint, move.delta_extruder,
|
||||
round_to_nearest(move.height, 2), round_to_nearest(move.width, 2), move.feedrate, move.fan_speed,
|
||||
round_to_nearest(move.height, 2), round_to_nearest(move.width, 2),
|
||||
move.feedrate, move.fan_speed, move.temperature,
|
||||
move.volumetric_rate(), move.extruder_id, move.cp_color_id });
|
||||
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
|
||||
}
|
||||
|
|
@ -654,6 +656,7 @@ void GCodeViewer::refresh(const GCodeProcessor::Result& gcode_result, const std:
|
|||
m_extrusions.ranges.height.update_from(round_to_nearest(curr.height, 2));
|
||||
m_extrusions.ranges.width.update_from(round_to_nearest(curr.width, 2));
|
||||
m_extrusions.ranges.fan_speed.update_from(curr.fan_speed);
|
||||
m_extrusions.ranges.temperature.update_from(curr.temperature);
|
||||
m_extrusions.ranges.volumetric_rate.update_from(round_to_nearest(curr.volumetric_rate(), 2));
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
|
@ -2898,6 +2901,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
|
|||
case EViewType::Width: { color = m_extrusions.ranges.width.get_color_at(path.width); break; }
|
||||
case EViewType::Feedrate: { color = m_extrusions.ranges.feedrate.get_color_at(path.feedrate); break; }
|
||||
case EViewType::FanSpeed: { color = m_extrusions.ranges.fan_speed.get_color_at(path.fan_speed); break; }
|
||||
case EViewType::Temperature: { color = m_extrusions.ranges.temperature.get_color_at(path.temperature); break; }
|
||||
case EViewType::VolumetricRate: { color = m_extrusions.ranges.volumetric_rate.get_color_at(path.volumetric_rate); break; }
|
||||
case EViewType::Tool: { color = m_tool_colors[path.extruder_id]; break; }
|
||||
case EViewType::ColorPrint: {
|
||||
|
|
@ -3357,6 +3361,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
|
|||
case EViewType::Width: { color = m_extrusions.ranges.width.get_color_at(path.width); break; }
|
||||
case EViewType::Feedrate: { color = m_extrusions.ranges.feedrate.get_color_at(path.feedrate); break; }
|
||||
case EViewType::FanSpeed: { color = m_extrusions.ranges.fan_speed.get_color_at(path.fan_speed); break; }
|
||||
case EViewType::Temperature: { color = m_extrusions.ranges.temperature.get_color_at(path.temperature); break; }
|
||||
case EViewType::VolumetricRate: { color = m_extrusions.ranges.volumetric_rate.get_color_at(path.volumetric_rate); break; }
|
||||
case EViewType::Tool: { color = m_tool_colors[path.extruder_id]; break; }
|
||||
case EViewType::ColorPrint: {
|
||||
|
|
@ -4191,6 +4196,7 @@ void GCodeViewer::render_legend() const
|
|||
case EViewType::Width: { imgui.title(_u8L("Width (mm)")); break; }
|
||||
case EViewType::Feedrate: { imgui.title(_u8L("Speed (mm/s)")); break; }
|
||||
case EViewType::FanSpeed: { imgui.title(_u8L("Fan Speed (%)")); break; }
|
||||
case EViewType::Temperature: { imgui.title(_u8L("Temperature (°C)")); break; }
|
||||
case EViewType::VolumetricRate: { imgui.title(_u8L("Volumetric flow rate (mm³/s)")); break; }
|
||||
case EViewType::Tool: { imgui.title(_u8L("Tool")); break; }
|
||||
case EViewType::ColorPrint: { imgui.title(_u8L("Color Print")); break; }
|
||||
|
|
@ -4225,6 +4231,7 @@ void GCodeViewer::render_legend() const
|
|||
case EViewType::Width: { append_range(m_extrusions.ranges.width, 3); break; }
|
||||
case EViewType::Feedrate: { append_range(m_extrusions.ranges.feedrate, 1); break; }
|
||||
case EViewType::FanSpeed: { append_range(m_extrusions.ranges.fan_speed, 0); break; }
|
||||
case EViewType::Temperature: { append_range(m_extrusions.ranges.temperature, 0); break; }
|
||||
case EViewType::VolumetricRate: { append_range(m_extrusions.ranges.volumetric_rate, 3); break; }
|
||||
case EViewType::Tool:
|
||||
{
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ class GCodeViewer
|
|||
float width{ 0.0f };
|
||||
float feedrate{ 0.0f };
|
||||
float fan_speed{ 0.0f };
|
||||
float temperature{ 0.0f };
|
||||
float volumetric_rate{ 0.0f };
|
||||
unsigned char extruder_id{ 0 };
|
||||
unsigned char cp_color_id{ 0 };
|
||||
|
|
@ -407,6 +408,8 @@ class GCodeViewer
|
|||
Range fan_speed;
|
||||
// Color mapping by volumetric extrusion rate.
|
||||
Range volumetric_rate;
|
||||
// Color mapping by extrusion temperature.
|
||||
Range temperature;
|
||||
|
||||
void reset() {
|
||||
height.reset();
|
||||
|
|
@ -414,6 +417,7 @@ class GCodeViewer
|
|||
feedrate.reset();
|
||||
fan_speed.reset();
|
||||
volumetric_rate.reset();
|
||||
temperature.reset();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -654,6 +658,7 @@ public:
|
|||
Width,
|
||||
Feedrate,
|
||||
FanSpeed,
|
||||
Temperature,
|
||||
VolumetricRate,
|
||||
Tool,
|
||||
ColorPrint,
|
||||
|
|
|
|||
|
|
@ -2512,8 +2512,6 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
|||
#endif /* __APPLE__ */
|
||||
post_event(SimpleEvent(EVT_GLTOOLBAR_COPY));
|
||||
break;
|
||||
|
||||
#if ENABLE_CTRL_M_ON_WINDOWS
|
||||
#ifdef __APPLE__
|
||||
case 'm':
|
||||
case 'M':
|
||||
|
|
@ -2532,18 +2530,6 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
|||
#endif //_WIN32
|
||||
break;
|
||||
}
|
||||
#else
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
case WXK_CONTROL_M:
|
||||
{
|
||||
Mouse3DController& controller = wxGetApp().plater()->get_mouse3d_controller();
|
||||
controller.show_settings_dialog(!controller.is_settings_dialog_shown());
|
||||
m_dirty = true;
|
||||
break;
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
#endif // ENABLE_CTRL_M_ON_WINDOWS
|
||||
|
||||
#ifdef __APPLE__
|
||||
case 'v':
|
||||
case 'V':
|
||||
|
|
|
|||
|
|
@ -835,14 +835,10 @@ bool GUI_App::on_init_inner()
|
|||
|
||||
if (is_editor()) {
|
||||
#ifdef __WXMSW__
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
if (app_config->get("associate_3mf") == "1")
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
associate_3mf_files();
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
if (app_config->get("associate_stl") == "1")
|
||||
associate_stl_files();
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#endif // __WXMSW__
|
||||
|
||||
preset_updater = new PresetUpdater();
|
||||
|
|
@ -858,9 +854,7 @@ bool GUI_App::on_init_inner()
|
|||
}
|
||||
else {
|
||||
#ifdef __WXMSW__
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
if (app_config->get("associate_gcode") == "1")
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
associate_gcode_files();
|
||||
#endif // __WXMSW__
|
||||
}
|
||||
|
|
@ -1722,7 +1716,6 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
|||
if (dlg.seq_top_layer_only_changed())
|
||||
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
|
||||
this->plater_->refresh_print();
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#ifdef _WIN32
|
||||
if (is_editor()) {
|
||||
if (app_config->get("associate_3mf") == "1")
|
||||
|
|
@ -1735,7 +1728,6 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
|||
associate_gcode_files();
|
||||
}
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
}
|
||||
if (app_layout_changed) {
|
||||
// hide full main_sizer for mainFrame
|
||||
|
|
@ -2303,7 +2295,6 @@ void GUI_App::associate_3mf_files()
|
|||
::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
|
||||
}
|
||||
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
void GUI_App::associate_stl_files()
|
||||
{
|
||||
wchar_t app_path[MAX_PATH];
|
||||
|
|
@ -2327,7 +2318,6 @@ void GUI_App::associate_stl_files()
|
|||
// notify Windows only when any of the values gets changed
|
||||
::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
|
||||
}
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
|
||||
void GUI_App::associate_gcode_files()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -279,13 +279,11 @@ public:
|
|||
bool is_gl_version_greater_or_equal_to(unsigned int major, unsigned int minor) const { return m_opengl_mgr.get_gl_info().is_version_greater_or_equal_to(major, minor); }
|
||||
bool is_glsl_version_greater_or_equal_to(unsigned int major, unsigned int minor) const { return m_opengl_mgr.get_gl_info().is_glsl_version_greater_or_equal_to(major, minor); }
|
||||
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#ifdef __WXMSW__
|
||||
void associate_3mf_files();
|
||||
void associate_stl_files();
|
||||
void associate_gcode_files();
|
||||
#endif // __WXMSW__
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
|
||||
private:
|
||||
bool on_init_inner();
|
||||
|
|
@ -297,13 +295,6 @@ private:
|
|||
|
||||
bool config_wizard_startup();
|
||||
void check_updates(const bool verbose);
|
||||
|
||||
#if !ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#ifdef __WXMSW__
|
||||
void associate_3mf_files();
|
||||
void associate_gcode_files();
|
||||
#endif // __WXMSW__
|
||||
#endif // !ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
};
|
||||
|
||||
DECLARE_APP(GUI_App)
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ ObjectList::ObjectList(wxWindow* parent) :
|
|||
CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap("layers");
|
||||
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap("infill");
|
||||
CATEGORY_ICON[L("Ironing")] = create_scaled_bitmap("ironing");
|
||||
CATEGORY_ICON[L("Fuzzy Skin")] = create_scaled_bitmap("fuzzy_skin");
|
||||
CATEGORY_ICON[L("Support material")] = create_scaled_bitmap("support");
|
||||
CATEGORY_ICON[L("Speed")] = create_scaled_bitmap("time");
|
||||
CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap("funnel");
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ bool Preview::init(wxWindow* parent, Model* model)
|
|||
m_choice_view_type->Append(_L("Width"));
|
||||
m_choice_view_type->Append(_L("Speed"));
|
||||
m_choice_view_type->Append(_L("Fan speed"));
|
||||
m_choice_view_type->Append(_L("Temperature"));
|
||||
m_choice_view_type->Append(_L("Volumetric flow rate"));
|
||||
m_choice_view_type->Append(_L("Tool"));
|
||||
m_choice_view_type->Append(_L("Color Print"));
|
||||
|
|
|
|||
|
|
@ -26,11 +26,7 @@ class wxCheckBox;
|
|||
class wxTopLevelWindow;
|
||||
class wxRect;
|
||||
|
||||
#if ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
|
||||
#define wxVERSION_EQUAL_OR_GREATER_THAN(major, minor, release) ((wxMAJOR_VERSION > major) || ((wxMAJOR_VERSION == major) && (wxMINOR_VERSION > minor)) || ((wxMAJOR_VERSION == major) && (wxMINOR_VERSION == minor) && (wxRELEASE_NUMBER >= release)))
|
||||
#else
|
||||
#define wxVERSION_EQUAL_OR_GREATER_THAN(major, minor, release) 0
|
||||
#endif // ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
|
@ -99,12 +95,12 @@ public:
|
|||
|
||||
// Linux specific issue : get_dpi_for_window(this) still doesn't responce to the Display's scale in new wxWidgets(3.1.3).
|
||||
// So, calculate the m_em_unit value from the font size, as before
|
||||
#if ENABLE_WX_3_1_3_DPI_CHANGED_EVENT && !defined(__WXGTK__)
|
||||
#if !defined(__WXGTK__)
|
||||
m_em_unit = std::max<size_t>(10, 10.0f * m_scale_factor);
|
||||
#else
|
||||
// initialize default width_unit according to the width of the one symbol ("m") of the currently active font of this window.
|
||||
m_em_unit = std::max<size_t>(10, this->GetTextExtent("m").x - 1);
|
||||
#endif // ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
|
||||
#endif // __WXGTK__
|
||||
|
||||
// recalc_font();
|
||||
|
||||
|
|
@ -235,11 +231,7 @@ private:
|
|||
m_normal_font = this->GetFont();
|
||||
|
||||
// update em_unit value for new window font
|
||||
#if ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
|
||||
m_em_unit = std::max<int>(10, 10.0f * m_scale_factor);
|
||||
#else
|
||||
m_em_unit = std::max<size_t>(10, this->GetTextExtent("m").x - 1);
|
||||
#endif // ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
|
||||
|
||||
// rescale missed controls sizes and images
|
||||
on_dpi_changed(suggested_rect);
|
||||
|
|
|
|||
|
|
@ -147,17 +147,11 @@ void KBShortcutsDialog::fill_shortcuts()
|
|||
{ "O", L("Zoom out") },
|
||||
{ "Tab", L("Switch between Editor/Preview") },
|
||||
{ "Shift+Tab", L("Collapse/Expand the sidebar") },
|
||||
#if ENABLE_CTRL_M_ON_WINDOWS
|
||||
#ifdef _WIN32
|
||||
{ ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog, if enabled") },
|
||||
#else
|
||||
{ ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog") },
|
||||
#endif // _WIN32
|
||||
#else
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
{ ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog") },
|
||||
#endif // __linux__
|
||||
#endif // ENABLE_CTRL_M_ON_WINDOWS
|
||||
#if ENABLE_RENDER_PICKING_PASS
|
||||
// Don't localize debugging texts.
|
||||
{ "P", "Toggle picking pass texture rendering on/off" },
|
||||
|
|
|
|||
|
|
@ -549,9 +549,10 @@ void MainFrame::init_tabpanel()
|
|||
wxWindow* panel = m_tabpanel->GetCurrentPage();
|
||||
if (panel != nullptr) {
|
||||
Tab* tab = dynamic_cast<Tab*>(panel);
|
||||
if (tab && (tab->type() == Preset::TYPE_FILAMENT || tab->type() == Preset::TYPE_PRINTER))
|
||||
if (!tab->validate_custom_gcodes())
|
||||
evt.Veto();
|
||||
if (tab != nullptr)
|
||||
tab->validate_custom_gcodes();
|
||||
// if (tab != nullptr && !tab->validate_custom_gcodes())
|
||||
// evt.Veto();
|
||||
}
|
||||
});
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
|
@ -803,11 +804,7 @@ bool MainFrame::can_reslice() const
|
|||
|
||||
void MainFrame::on_dpi_changed(const wxRect& suggested_rect)
|
||||
{
|
||||
#if ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
|
||||
wxGetApp().update_fonts(this);
|
||||
#else
|
||||
wxGetApp().update_fonts();
|
||||
#endif // ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
|
||||
this->SetFont(this->normal_font());
|
||||
|
||||
// update Plater
|
||||
|
|
@ -1848,14 +1845,14 @@ SettingsDialog::SettingsDialog(MainFrame* mainframe)
|
|||
if (wxGetApp().is_gcode_viewer())
|
||||
return;
|
||||
|
||||
#if ENABLE_WX_3_1_3_DPI_CHANGED_EVENT && defined(__WXMSW__)
|
||||
#if defined(__WXMSW__)
|
||||
// ys_FIXME! temporary workaround for correct font scaling
|
||||
// Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts,
|
||||
// From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT
|
||||
this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||
#else
|
||||
this->SetFont(wxGetApp().normal_font());
|
||||
#endif // ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
|
||||
#endif // __WXMSW__
|
||||
this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
|
||||
// Load the icon either from the exe, or from the ico file.
|
||||
|
|
|
|||
|
|
@ -100,7 +100,6 @@ void Mouse3DController::State::append_button(unsigned int id, size_t /* input_qu
|
|||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#if ENABLE_CTRL_M_ON_WINDOWS
|
||||
static std::string format_device_string(int vid, int pid)
|
||||
{
|
||||
std::string ret;
|
||||
|
|
@ -257,7 +256,6 @@ static std::string detect_attached_device()
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif // ENABLE_CTRL_M_ON_WINDOWS
|
||||
|
||||
// Called by Win32 HID enumeration callback.
|
||||
void Mouse3DController::device_attached(const std::string &device)
|
||||
|
|
@ -274,7 +272,6 @@ void Mouse3DController::device_attached(const std::string &device)
|
|||
// Never mind, enumeration will be performed until connected.
|
||||
m_wakeup = true;
|
||||
m_stop_condition.notify_all();
|
||||
#if ENABLE_CTRL_M_ON_WINDOWS
|
||||
m_device_str = format_device_string(vid, pid);
|
||||
if (auto it_params = m_params_by_device.find(m_device_str); it_params != m_params_by_device.end()) {
|
||||
tbb::mutex::scoped_lock lock(m_params_ui_mutex);
|
||||
|
|
@ -283,12 +280,10 @@ void Mouse3DController::device_attached(const std::string &device)
|
|||
else
|
||||
m_params_by_device[format_device_string(vid, pid)] = Params();
|
||||
m_connected = true;
|
||||
#endif // ENABLE_CTRL_M_ON_WINDOWS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_CTRL_M_ON_WINDOWS
|
||||
void Mouse3DController::device_detached(const std::string& device)
|
||||
{
|
||||
int vid = 0;
|
||||
|
|
@ -302,7 +297,6 @@ void Mouse3DController::device_detached(const std::string& device)
|
|||
m_device_str = "";
|
||||
m_connected = false;
|
||||
}
|
||||
#endif // ENABLE_CTRL_M_ON_WINDOWS
|
||||
|
||||
// Filter out mouse scroll events produced by the 3DConnexion driver.
|
||||
bool Mouse3DController::State::process_mouse_wheel()
|
||||
|
|
@ -415,7 +409,6 @@ bool Mouse3DController::apply(Camera& camera)
|
|||
m_settings_dialog_closed_by_user = false;
|
||||
}
|
||||
|
||||
#if ENABLE_CTRL_M_ON_WINDOWS
|
||||
#ifdef _WIN32
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_params_ui_mutex);
|
||||
|
|
@ -425,7 +418,6 @@ bool Mouse3DController::apply(Camera& camera)
|
|||
}
|
||||
}
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CTRL_M_ON_WINDOWS
|
||||
|
||||
return m_state.apply(m_params, camera);
|
||||
}
|
||||
|
|
@ -661,7 +653,6 @@ bool Mouse3DController::handle_input(const DataPacketAxis& packet)
|
|||
// Initialize the application.
|
||||
void Mouse3DController::init()
|
||||
{
|
||||
#if ENABLE_CTRL_M_ON_WINDOWS
|
||||
#ifdef _WIN32
|
||||
m_device_str = detect_attached_device();
|
||||
if (!m_device_str.empty()) {
|
||||
|
|
@ -670,7 +661,6 @@ void Mouse3DController::init()
|
|||
m_params = m_params_ui = it_params->second;
|
||||
}
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CTRL_M_ON_WINDOWS
|
||||
|
||||
assert(! m_thread.joinable());
|
||||
if (! m_thread.joinable()) {
|
||||
|
|
@ -698,12 +688,10 @@ void Mouse3DController::shutdown()
|
|||
m_stop = false;
|
||||
}
|
||||
|
||||
#if ENABLE_CTRL_M_ON_WINDOWS
|
||||
#ifdef _WIN32
|
||||
if (!m_device_str.empty())
|
||||
m_params_by_device[m_device_str] = m_params_ui;
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CTRL_M_ON_WINDOWS
|
||||
}
|
||||
|
||||
// Main routine of the worker thread.
|
||||
|
|
@ -1064,9 +1052,7 @@ bool Mouse3DController::handle_raw_input_win32(const unsigned char *data, const
|
|||
DataPacketRaw packet;
|
||||
memcpy(packet.data(), data, packet_length);
|
||||
handle_packet(packet, packet_length, m_params, m_state);
|
||||
#if ENABLE_CTRL_M_ON_WINDOWS
|
||||
m_connected = true;
|
||||
#endif // ENABLE_CTRL_M_ON_WINDOWS
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -195,9 +195,7 @@ public:
|
|||
|
||||
// Called by Win32 HID enumeration callback.
|
||||
void device_attached(const std::string &device);
|
||||
#if ENABLE_CTRL_M_ON_WINDOWS
|
||||
void device_detached(const std::string& device);
|
||||
#endif // ENABLE_CTRL_M_ON_WINDOWS
|
||||
|
||||
// On Windows, the 3DConnexion driver sends out mouse wheel rotation events to an active application
|
||||
// if the application does not register at the driver. This is a workaround to ignore these superfluous
|
||||
|
|
|
|||
|
|
@ -14,14 +14,10 @@
|
|||
#include <wx/glcanvas.h>
|
||||
#include <wx/msgdlg.h>
|
||||
|
||||
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
#ifdef __APPLE__
|
||||
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
|
||||
#include <wx/platinfo.h>
|
||||
#endif // __APPLE__
|
||||
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "../Utils/MacDarkMode.hpp"
|
||||
#endif // __APPLE__
|
||||
|
||||
|
|
@ -202,34 +198,26 @@ bool OpenGLManager::s_compressed_textures_supported = false;
|
|||
OpenGLManager::EMultisampleState OpenGLManager::s_multisample = OpenGLManager::EMultisampleState::Unknown;
|
||||
OpenGLManager::EFramebufferType OpenGLManager::s_framebuffers_type = OpenGLManager::EFramebufferType::Unknown;
|
||||
|
||||
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
#ifdef __APPLE__
|
||||
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
|
||||
OpenGLManager::OSInfo OpenGLManager::s_os_info;
|
||||
#endif // __APPLE__
|
||||
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
|
||||
OpenGLManager::~OpenGLManager()
|
||||
{
|
||||
m_shaders_manager.shutdown();
|
||||
|
||||
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
#ifdef __APPLE__
|
||||
// This is an ugly hack needed to solve the crash happening when closing the application on OSX 10.9.5 with newer wxWidgets
|
||||
// The crash is triggered inside wxGLContext destructor
|
||||
if (s_os_info.major != 10 || s_os_info.minor != 9 || s_os_info.micro != 5)
|
||||
{
|
||||
#endif //__APPLE__
|
||||
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
|
||||
if (m_context != nullptr)
|
||||
delete m_context;
|
||||
|
||||
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
#ifdef __APPLE__
|
||||
}
|
||||
#endif //__APPLE__
|
||||
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
}
|
||||
|
||||
bool OpenGLManager::init_gl()
|
||||
|
|
@ -286,14 +274,12 @@ wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas)
|
|||
if (m_context == nullptr) {
|
||||
m_context = new wxGLContext(&canvas);
|
||||
|
||||
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
#ifdef __APPLE__
|
||||
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
|
||||
s_os_info.major = wxPlatformInfo::Get().GetOSMajorVersion();
|
||||
s_os_info.minor = wxPlatformInfo::Get().GetOSMinorVersion();
|
||||
s_os_info.micro = wxPlatformInfo::Get().GetOSMicroVersion();
|
||||
#endif //__APPLE__
|
||||
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
}
|
||||
return m_context;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ public:
|
|||
void detect() const;
|
||||
};
|
||||
|
||||
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
#ifdef __APPLE__
|
||||
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
|
||||
struct OSInfo
|
||||
|
|
@ -61,7 +60,6 @@ public:
|
|||
int micro{ 0 };
|
||||
};
|
||||
#endif //__APPLE__
|
||||
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
|
||||
private:
|
||||
enum class EMultisampleState : unsigned char
|
||||
|
|
@ -75,12 +73,10 @@ private:
|
|||
wxGLContext* m_context{ nullptr };
|
||||
GLShadersManager m_shaders_manager;
|
||||
static GLInfo s_gl_info;
|
||||
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
#ifdef __APPLE__
|
||||
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
|
||||
static OSInfo s_os_info;
|
||||
#endif //__APPLE__
|
||||
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
|
||||
static bool s_compressed_textures_supported;
|
||||
static EMultisampleState s_multisample;
|
||||
static EFramebufferType s_framebuffers_type;
|
||||
|
|
|
|||
|
|
@ -1931,11 +1931,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
this->q->Bind(EVT_HID_DEVICE_ATTACHED, [this](HIDDeviceAttachedEvent &evt) {
|
||||
mouse3d_controller.device_attached(evt.data);
|
||||
});
|
||||
#if ENABLE_CTRL_M_ON_WINDOWS
|
||||
this->q->Bind(EVT_HID_DEVICE_DETACHED, [this](HIDDeviceAttachedEvent& evt) {
|
||||
mouse3d_controller.device_detached(evt.data);
|
||||
});
|
||||
#endif // ENABLE_CTRL_M_ON_WINDOWS
|
||||
#endif /* _WIN32 */
|
||||
|
||||
notification_manager = new NotificationManager(this->q);
|
||||
|
|
@ -2191,9 +2189,56 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
{
|
||||
if (!config.empty()) {
|
||||
Preset::normalize(config);
|
||||
wxGetApp().preset_bundle->load_config_model(filename.string(), std::move(config));
|
||||
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
|
||||
preset_bundle->load_config_model(filename.string(), std::move(config));
|
||||
{
|
||||
// After loading of the presets from project, check if they are visible.
|
||||
// Set them to visible if they are not.
|
||||
|
||||
auto update_selected_preset_visibility = [](PresetCollection& presets, std::vector<std::string>& names) {
|
||||
if (!presets.get_selected_preset().is_visible) {
|
||||
assert(presets.get_selected_preset().name == presets.get_edited_preset().name);
|
||||
presets.get_selected_preset().is_visible = true;
|
||||
presets.get_edited_preset().is_visible = true;
|
||||
names.emplace_back(presets.get_selected_preset().name);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<std::string> names;
|
||||
if (printer_technology == ptFFF) {
|
||||
update_selected_preset_visibility(preset_bundle->prints, names);
|
||||
for (const std::string& filament : preset_bundle->filament_presets) {
|
||||
Preset* preset = preset_bundle->filaments.find_preset(filament);
|
||||
if (preset && !preset->is_visible) {
|
||||
preset->is_visible = true;
|
||||
names.emplace_back(preset->name);
|
||||
if (preset->name == preset_bundle->filaments.get_edited_preset().name)
|
||||
preset_bundle->filaments.get_selected_preset().is_visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
update_selected_preset_visibility(preset_bundle->sla_prints, names);
|
||||
update_selected_preset_visibility(preset_bundle->sla_materials, names);
|
||||
}
|
||||
update_selected_preset_visibility(preset_bundle->printers, names);
|
||||
|
||||
preset_bundle->update_compatible(PresetSelectCompatibleType::Never);
|
||||
|
||||
// show notification about temporary instaled presets
|
||||
if (!names.empty()) {
|
||||
std::string notif_text = into_u8(_L_PLURAL("The preset below was temporary instaled on active instance of PrusaSlicer",
|
||||
"The presets below were temporary instaled on active instance of PrusaSlicer", names.size())) + ":";
|
||||
for (std::string& name : names)
|
||||
notif_text += "\n - " + name;
|
||||
notification_manager->push_notification(NotificationType::CustomNotification,
|
||||
NotificationManager::NotificationLevel::RegularNotification, notif_text);
|
||||
}
|
||||
}
|
||||
|
||||
if (printer_technology == ptFFF)
|
||||
CustomGCode::update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, &wxGetApp().preset_bundle->project_config);
|
||||
CustomGCode::update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, &preset_bundle->project_config);
|
||||
|
||||
// For exporting from the amf/3mf we shouldn't check printer_presets for the containing information about "Print Host upload"
|
||||
wxGetApp().load_current_presets(false);
|
||||
// Update filament colors for the MM-printer profile in the full config
|
||||
|
|
@ -3346,16 +3391,14 @@ void Plater::priv::set_current_panel(wxPanel* panel)
|
|||
|
||||
void Plater::priv::on_select_preset(wxCommandEvent &evt)
|
||||
{
|
||||
auto preset_type = static_cast<Preset::Type>(evt.GetInt());
|
||||
auto *combo = static_cast<PlaterPresetComboBox*>(evt.GetEventObject());
|
||||
PlaterPresetComboBox* combo = static_cast<PlaterPresetComboBox*>(evt.GetEventObject());
|
||||
Preset::Type preset_type = combo->get_type();
|
||||
|
||||
// see https://github.com/prusa3d/PrusaSlicer/issues/3889
|
||||
// Under OSX: in case of use of a same names written in different case (like "ENDER" and "Ender"),
|
||||
// m_presets_choice->GetSelection() will return first item, because search in PopupListCtrl is case-insensitive.
|
||||
// So, use GetSelection() from event parameter
|
||||
// But in this function we couldn't use evt.GetSelection(), because m_commandInt is used for preset_type
|
||||
// Thus, get selection in this way:
|
||||
int selection = combo->FindString(evt.GetString(), true);
|
||||
int selection = evt.GetSelection();
|
||||
|
||||
auto idx = combo->get_extruder_idx();
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,6 @@ void PreferencesDialog::build()
|
|||
option = Option(def, "export_sources_full_pathnames");
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#ifdef _WIN32
|
||||
// Please keep in sync with ConfigWizard
|
||||
def.label = L("Associate .3mf files to PrusaSlicer");
|
||||
|
|
@ -123,7 +122,6 @@ void PreferencesDialog::build()
|
|||
option = Option(def, "associate_stl");
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
|
||||
// Please keep in sync with ConfigWizard
|
||||
def.label = L("Update built-in Presets automatically");
|
||||
|
|
@ -184,7 +182,6 @@ void PreferencesDialog::build()
|
|||
option = Option(def, "default_action_on_select_preset");
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
}
|
||||
#if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
#ifdef _WIN32
|
||||
else {
|
||||
def.label = L("Associate .gcode files to PrusaSlicer G-code Viewer");
|
||||
|
|
@ -195,7 +192,6 @@ void PreferencesDialog::build()
|
|||
m_optgroup_general->append_single_option_line(option);
|
||||
}
|
||||
#endif // _WIN32
|
||||
#endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN
|
||||
|
||||
#if __APPLE__
|
||||
def.label = L("Use Retina resolution for the 3D scene");
|
||||
|
|
@ -215,7 +211,6 @@ void PreferencesDialog::build()
|
|||
option = Option(def, "show_splash_screen");
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
|
||||
#if ENABLE_CTRL_M_ON_WINDOWS
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
def.label = L("Enable support for legacy 3DConnexion devices");
|
||||
def.type = coBool;
|
||||
|
|
@ -224,7 +219,6 @@ void PreferencesDialog::build()
|
|||
option = Option(def, "use_legacy_3DConnexion");
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
#endif // _WIN32 || __APPLE__
|
||||
#endif // ENABLE_CTRL_M_ON_WINDOWS
|
||||
|
||||
activate_options_tab(m_optgroup_general);
|
||||
|
||||
|
|
|
|||
|
|
@ -121,23 +121,26 @@ PresetComboBox::PresetComboBox(wxWindow* parent, Preset::Type preset_type, const
|
|||
Bind(wxEVT_COMBOBOX_DROPDOWN, [this](wxCommandEvent&) { m_suppress_change = false; });
|
||||
Bind(wxEVT_COMBOBOX_CLOSEUP, [this](wxCommandEvent&) { m_suppress_change = true; });
|
||||
|
||||
Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) {
|
||||
// see https://github.com/prusa3d/PrusaSlicer/issues/3889
|
||||
// Under OSX: in case of use of a same names written in different case (like "ENDER" and "Ender")
|
||||
// m_presets_choice->GetSelection() will return first item, because search in PopupListCtrl is case-insensitive.
|
||||
// So, use GetSelection() from event parameter
|
||||
auto selected_item = evt.GetSelection();
|
||||
Bind(wxEVT_COMBOBOX, &PresetComboBox::OnSelect, this);
|
||||
}
|
||||
|
||||
auto marker = reinterpret_cast<Marker>(this->GetClientData(selected_item));
|
||||
if (marker >= LABEL_ITEM_DISABLED && marker < LABEL_ITEM_MAX)
|
||||
this->SetSelection(this->m_last_selected);
|
||||
else if (on_selection_changed && (m_last_selected != selected_item || m_collection->current_is_dirty())) {
|
||||
m_last_selected = selected_item;
|
||||
on_selection_changed(selected_item);
|
||||
evt.StopPropagation();
|
||||
}
|
||||
evt.Skip();
|
||||
});
|
||||
void PresetComboBox::OnSelect(wxCommandEvent& evt)
|
||||
{
|
||||
// see https://github.com/prusa3d/PrusaSlicer/issues/3889
|
||||
// Under OSX: in case of use of a same names written in different case (like "ENDER" and "Ender")
|
||||
// m_presets_choice->GetSelection() will return first item, because search in PopupListCtrl is case-insensitive.
|
||||
// So, use GetSelection() from event parameter
|
||||
auto selected_item = evt.GetSelection();
|
||||
|
||||
auto marker = reinterpret_cast<Marker>(this->GetClientData(selected_item));
|
||||
if (marker >= LABEL_ITEM_DISABLED && marker < LABEL_ITEM_MAX)
|
||||
this->SetSelection(this->m_last_selected);
|
||||
else if (on_selection_changed && (m_last_selected != selected_item || m_collection->current_is_dirty())) {
|
||||
m_last_selected = selected_item;
|
||||
on_selection_changed(selected_item);
|
||||
evt.StopPropagation();
|
||||
}
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
PresetComboBox::~PresetComboBox()
|
||||
|
|
@ -602,34 +605,6 @@ void PresetComboBox::OnDrawItem(wxDC& dc,
|
|||
PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset_type) :
|
||||
PresetComboBox(parent, preset_type, wxSize(15 * wxGetApp().em_unit(), -1))
|
||||
{
|
||||
Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &evt) {
|
||||
auto selected_item = evt.GetSelection();
|
||||
|
||||
auto marker = reinterpret_cast<Marker>(this->GetClientData(selected_item));
|
||||
if (marker >= LABEL_ITEM_MARKER && marker < LABEL_ITEM_MAX) {
|
||||
this->SetSelection(this->m_last_selected);
|
||||
evt.StopPropagation();
|
||||
if (marker == LABEL_ITEM_WIZARD_PRINTERS)
|
||||
show_add_menu();
|
||||
else
|
||||
{
|
||||
ConfigWizard::StartPage sp = ConfigWizard::SP_WELCOME;
|
||||
switch (marker) {
|
||||
case LABEL_ITEM_WIZARD_FILAMENTS: sp = ConfigWizard::SP_FILAMENTS; break;
|
||||
case LABEL_ITEM_WIZARD_MATERIALS: sp = ConfigWizard::SP_MATERIALS; break;
|
||||
default: break;
|
||||
}
|
||||
wxTheApp->CallAfter([sp]() { wxGetApp().run_wizard(ConfigWizard::RR_USER, sp); });
|
||||
}
|
||||
} else if (marker == LABEL_ITEM_PHYSICAL_PRINTER || this->m_last_selected != selected_item || m_collection->current_is_dirty() ) {
|
||||
this->m_last_selected = selected_item;
|
||||
evt.SetInt(this->m_type);
|
||||
evt.Skip();
|
||||
} else {
|
||||
evt.StopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
if (m_type == Preset::TYPE_FILAMENT)
|
||||
{
|
||||
Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &event) {
|
||||
|
|
@ -717,6 +692,35 @@ PlaterPresetComboBox::~PlaterPresetComboBox()
|
|||
edit_btn->Destroy();
|
||||
}
|
||||
|
||||
void PlaterPresetComboBox::OnSelect(wxCommandEvent &evt)
|
||||
{
|
||||
auto selected_item = evt.GetSelection();
|
||||
|
||||
auto marker = reinterpret_cast<Marker>(this->GetClientData(selected_item));
|
||||
if (marker >= LABEL_ITEM_MARKER && marker < LABEL_ITEM_MAX) {
|
||||
this->SetSelection(this->m_last_selected);
|
||||
evt.StopPropagation();
|
||||
if (marker == LABEL_ITEM_MARKER)
|
||||
return;
|
||||
if (marker == LABEL_ITEM_WIZARD_PRINTERS)
|
||||
show_add_menu();
|
||||
else {
|
||||
ConfigWizard::StartPage sp = ConfigWizard::SP_WELCOME;
|
||||
switch (marker) {
|
||||
case LABEL_ITEM_WIZARD_FILAMENTS: sp = ConfigWizard::SP_FILAMENTS; break;
|
||||
case LABEL_ITEM_WIZARD_MATERIALS: sp = ConfigWizard::SP_MATERIALS; break;
|
||||
default: break;
|
||||
}
|
||||
wxTheApp->CallAfter([sp]() { wxGetApp().run_wizard(ConfigWizard::RR_USER, sp); });
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (marker == LABEL_ITEM_PHYSICAL_PRINTER || this->m_last_selected != selected_item || m_collection->current_is_dirty())
|
||||
this->m_last_selected = selected_item;
|
||||
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
bool PlaterPresetComboBox::switch_to_tab()
|
||||
{
|
||||
Tab* tab = wxGetApp().get_tab(m_type);
|
||||
|
|
@ -895,7 +899,7 @@ void PlaterPresetComboBox::update()
|
|||
for (PhysicalPrinterCollection::ConstIterator it = ph_printers.begin(); it != ph_printers.end(); ++it) {
|
||||
for (const std::string& preset_name : it->get_preset_names()) {
|
||||
Preset* preset = m_collection->find_preset(preset_name);
|
||||
if (!preset)
|
||||
if (!preset || !preset->is_visible)
|
||||
continue;
|
||||
std::string main_icon_name, bitmap_key = main_icon_name = preset->printer_technology() == ptSLA ? "sla_printer" : m_main_bitmap_name;
|
||||
wxBitmap* bmp = get_bmp(main_icon_name, wide_icons, main_icon_name);
|
||||
|
|
@ -957,40 +961,42 @@ void PlaterPresetComboBox::msw_rescale()
|
|||
TabPresetComboBox::TabPresetComboBox(wxWindow* parent, Preset::Type preset_type) :
|
||||
PresetComboBox(parent, preset_type, wxSize(35 * wxGetApp().em_unit(), -1))
|
||||
{
|
||||
Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) {
|
||||
// see https://github.com/prusa3d/PrusaSlicer/issues/3889
|
||||
// Under OSX: in case of use of a same names written in different case (like "ENDER" and "Ender")
|
||||
// m_presets_choice->GetSelection() will return first item, because search in PopupListCtrl is case-insensitive.
|
||||
// So, use GetSelection() from event parameter
|
||||
auto selected_item = evt.GetSelection();
|
||||
}
|
||||
|
||||
auto marker = reinterpret_cast<Marker>(this->GetClientData(selected_item));
|
||||
if (marker >= LABEL_ITEM_DISABLED && marker < LABEL_ITEM_MAX) {
|
||||
this->SetSelection(this->m_last_selected);
|
||||
if (marker == LABEL_ITEM_WIZARD_PRINTERS)
|
||||
wxTheApp->CallAfter([this]() {
|
||||
wxGetApp().run_wizard(ConfigWizard::RR_USER, ConfigWizard::SP_PRINTERS);
|
||||
void TabPresetComboBox::OnSelect(wxCommandEvent &evt)
|
||||
{
|
||||
// see https://github.com/prusa3d/PrusaSlicer/issues/3889
|
||||
// Under OSX: in case of use of a same names written in different case (like "ENDER" and "Ender")
|
||||
// m_presets_choice->GetSelection() will return first item, because search in PopupListCtrl is case-insensitive.
|
||||
// So, use GetSelection() from event parameter
|
||||
auto selected_item = evt.GetSelection();
|
||||
|
||||
// update combobox if its parent is a PhysicalPrinterDialog
|
||||
PhysicalPrinterDialog* parent = dynamic_cast<PhysicalPrinterDialog*>(this->GetParent());
|
||||
if (parent != nullptr)
|
||||
update();
|
||||
});
|
||||
}
|
||||
else if (on_selection_changed && (m_last_selected != selected_item || m_collection->current_is_dirty()) ) {
|
||||
m_last_selected = selected_item;
|
||||
on_selection_changed(selected_item);
|
||||
}
|
||||
auto marker = reinterpret_cast<Marker>(this->GetClientData(selected_item));
|
||||
if (marker >= LABEL_ITEM_DISABLED && marker < LABEL_ITEM_MAX) {
|
||||
this->SetSelection(this->m_last_selected);
|
||||
if (marker == LABEL_ITEM_WIZARD_PRINTERS)
|
||||
wxTheApp->CallAfter([this]() {
|
||||
wxGetApp().run_wizard(ConfigWizard::RR_USER, ConfigWizard::SP_PRINTERS);
|
||||
|
||||
evt.StopPropagation();
|
||||
// update combobox if its parent is a PhysicalPrinterDialog
|
||||
PhysicalPrinterDialog* parent = dynamic_cast<PhysicalPrinterDialog*>(this->GetParent());
|
||||
if (parent != nullptr)
|
||||
update();
|
||||
});
|
||||
}
|
||||
else if (on_selection_changed && (m_last_selected != selected_item || m_collection->current_is_dirty())) {
|
||||
m_last_selected = selected_item;
|
||||
on_selection_changed(selected_item);
|
||||
}
|
||||
|
||||
evt.StopPropagation();
|
||||
#ifdef __WXMSW__
|
||||
// From the Win 2004 preset combobox lose a focus after change the preset selection
|
||||
// and that is why the up/down arrow doesn't work properly
|
||||
// (see https://github.com/prusa3d/PrusaSlicer/issues/5531 ).
|
||||
// So, set the focus to the combobox explicitly
|
||||
this->SetFocus();
|
||||
#endif
|
||||
});
|
||||
// From the Win 2004 preset combobox lose a focus after change the preset selection
|
||||
// and that is why the up/down arrow doesn't work properly
|
||||
// (see https://github.com/prusa3d/PrusaSlicer/issues/5531 ).
|
||||
// So, set the focus to the combobox explicitly
|
||||
this->SetFocus();
|
||||
#endif
|
||||
}
|
||||
|
||||
wxString TabPresetComboBox::get_preset_name(const Preset& preset)
|
||||
|
|
@ -1080,7 +1086,7 @@ void TabPresetComboBox::update()
|
|||
for (PhysicalPrinterCollection::ConstIterator it = ph_printers.begin(); it != ph_printers.end(); ++it) {
|
||||
for (const std::string& preset_name : it->get_preset_names()) {
|
||||
Preset* preset = m_collection->find_preset(preset_name);
|
||||
if (!preset)
|
||||
if (!preset || !preset->is_visible)
|
||||
continue;
|
||||
std::string main_icon_name = preset->printer_technology() == ptSLA ? "sla_printer" : m_main_bitmap_name;
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ public:
|
|||
void show_all(bool show_all);
|
||||
virtual void update();
|
||||
virtual void msw_rescale();
|
||||
virtual void OnSelect(wxCommandEvent& evt);
|
||||
|
||||
protected:
|
||||
typedef std::size_t Marker;
|
||||
|
|
@ -167,6 +168,7 @@ public:
|
|||
wxString get_preset_name(const Preset& preset) override;
|
||||
void update() override;
|
||||
void msw_rescale() override;
|
||||
void OnSelect(wxCommandEvent& evt) override;
|
||||
|
||||
private:
|
||||
int m_extruder_idx = -1;
|
||||
|
|
@ -193,6 +195,7 @@ public:
|
|||
void update() override;
|
||||
void update_dirty();
|
||||
void msw_rescale() override;
|
||||
void OnSelect(wxCommandEvent& evt) override;
|
||||
|
||||
void set_enable_all(bool enable=true) { m_enable_all = enable; }
|
||||
|
||||
|
|
|
|||
|
|
@ -209,12 +209,12 @@ SavePresetDialog::~SavePresetDialog()
|
|||
void SavePresetDialog::build(std::vector<Preset::Type> types, std::string suffix)
|
||||
{
|
||||
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
#if ENABLE_WX_3_1_3_DPI_CHANGED_EVENT && defined(__WXMSW__)
|
||||
#if defined(__WXMSW__)
|
||||
// ys_FIXME! temporary workaround for correct font scaling
|
||||
// Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts,
|
||||
// From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT
|
||||
this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||
#endif // ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
|
||||
#endif // __WXMSW__
|
||||
|
||||
if (suffix.empty())
|
||||
suffix = _CTX_utf8(L_CONTEXT("Copy", "PresetName"), "PresetName");
|
||||
|
|
|
|||
|
|
@ -1732,10 +1732,10 @@ bool Tab::validate_custom_gcode(const wxString& title, const std::string& gcode)
|
|||
return !invalid;
|
||||
}
|
||||
|
||||
static void validate_custom_gcode_cb(Tab* tab, ConfigOptionsGroupShp opt_group, const boost::any& value) {
|
||||
static void validate_custom_gcode_cb(Tab* tab, ConfigOptionsGroupShp opt_group, const t_config_option_key& opt_key, const boost::any& value) {
|
||||
Tab::validate_custom_gcode(opt_group->title, boost::any_cast<std::string>(value));
|
||||
tab->update_dirty();
|
||||
tab->update();
|
||||
tab->on_value_change(opt_key, value);
|
||||
}
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
|
|
@ -1964,7 +1964,7 @@ void TabFilament::build()
|
|||
optgroup = page->new_optgroup(L("Start G-code"), 0);
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup, value);
|
||||
validate_custom_gcode_cb(this, optgroup, opt_key, value);
|
||||
};
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
option = optgroup->get_option("start_filament_gcode");
|
||||
|
|
@ -1976,7 +1976,7 @@ void TabFilament::build()
|
|||
optgroup = page->new_optgroup(L("End G-code"), 0);
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup, value);
|
||||
validate_custom_gcode_cb(this, optgroup, opt_key, value);
|
||||
};
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
option = optgroup->get_option("end_filament_gcode");
|
||||
|
|
@ -2273,17 +2273,11 @@ void TabPrinter::build_fff()
|
|||
|
||||
const int gcode_field_height = 15; // 150
|
||||
const int notes_field_height = 25; // 250
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
// WARNING !!
|
||||
// if you are going to change any of the following optgroup/option titles
|
||||
// or to add/remove optgroups/options
|
||||
// update also TabPrinter::validate_custom_gcodes()
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
page = add_options_page(L("Custom G-code"), "cog");
|
||||
optgroup = page->new_optgroup(L("Start G-code"), 0);
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup, boost::any_cast<std::string>(value));
|
||||
validate_custom_gcode_cb(this, optgroup, opt_key, value);
|
||||
};
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
option = optgroup->get_option("start_gcode");
|
||||
|
|
@ -2295,7 +2289,7 @@ void TabPrinter::build_fff()
|
|||
optgroup = page->new_optgroup(L("End G-code"), 0);
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup, boost::any_cast<std::string>(value));
|
||||
validate_custom_gcode_cb(this, optgroup, opt_key, value);
|
||||
};
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
option = optgroup->get_option("end_gcode");
|
||||
|
|
@ -2307,7 +2301,7 @@ void TabPrinter::build_fff()
|
|||
optgroup = page->new_optgroup(L("Before layer change G-code"), 0);
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup, boost::any_cast<std::string>(value));
|
||||
validate_custom_gcode_cb(this, optgroup, opt_key, value);
|
||||
};
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
option = optgroup->get_option("before_layer_gcode");
|
||||
|
|
@ -2319,7 +2313,7 @@ void TabPrinter::build_fff()
|
|||
optgroup = page->new_optgroup(L("After layer change G-code"), 0);
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup, boost::any_cast<std::string>(value));
|
||||
validate_custom_gcode_cb(this, optgroup, opt_key, value);
|
||||
};
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
option = optgroup->get_option("layer_gcode");
|
||||
|
|
@ -2331,7 +2325,7 @@ void TabPrinter::build_fff()
|
|||
optgroup = page->new_optgroup(L("Tool change G-code"), 0);
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup, boost::any_cast<std::string>(value));
|
||||
validate_custom_gcode_cb(this, optgroup, opt_key, value);
|
||||
};
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
option = optgroup->get_option("toolchange_gcode");
|
||||
|
|
@ -2343,7 +2337,7 @@ void TabPrinter::build_fff()
|
|||
optgroup = page->new_optgroup(L("Between objects G-code (for sequential printing)"), 0);
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup, boost::any_cast<std::string>(value));
|
||||
validate_custom_gcode_cb(this, optgroup, opt_key, value);
|
||||
};
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
option = optgroup->get_option("between_objects_gcode");
|
||||
|
|
@ -2355,7 +2349,7 @@ void TabPrinter::build_fff()
|
|||
optgroup = page->new_optgroup(L("Color Change G-code"), 0);
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup, boost::any_cast<std::string>(value));
|
||||
validate_custom_gcode_cb(this, optgroup, opt_key, value);
|
||||
};
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
option = optgroup->get_option("color_change_gcode");
|
||||
|
|
@ -2366,7 +2360,7 @@ void TabPrinter::build_fff()
|
|||
optgroup = page->new_optgroup(L("Pause Print G-code"), 0);
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup, boost::any_cast<std::string>(value));
|
||||
validate_custom_gcode_cb(this, optgroup, opt_key, value);
|
||||
};
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
option = optgroup->get_option("pause_print_gcode");
|
||||
|
|
@ -2377,7 +2371,7 @@ void TabPrinter::build_fff()
|
|||
optgroup = page->new_optgroup(L("Template Custom G-code"), 0);
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(this, optgroup, boost::any_cast<std::string>(value));
|
||||
validate_custom_gcode_cb(this, optgroup, opt_key, value);
|
||||
};
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
option = optgroup->get_option("template_custom_gcode");
|
||||
|
|
@ -3832,15 +3826,35 @@ void TabPrinter::apply_extruder_cnt_from_cache()
|
|||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
bool Tab::validate_custom_gcodes()
|
||||
{
|
||||
if (m_type != Preset::TYPE_FILAMENT &&
|
||||
(m_type != Preset::TYPE_PRINTER || static_cast<TabPrinter*>(this)->m_printer_technology != ptFFF))
|
||||
return true;
|
||||
if (m_active_page->title() != L("Custom G-code"))
|
||||
return true;
|
||||
|
||||
bool valid = true;
|
||||
if ((m_type == Preset::TYPE_FILAMENT ||
|
||||
m_type == Preset::TYPE_PRINTER && static_cast<TabPrinter*>(this)->m_printer_technology == ptFFF) &&
|
||||
m_active_page->title() == "Custom G-code") {
|
||||
for (auto opt_group : m_active_page->m_optgroups) {
|
||||
assert(opt_group->opt_map().size() == 1);
|
||||
std::string key = opt_group->opt_map().begin()->first;
|
||||
valid &= validate_custom_gcode(opt_group->title, boost::any_cast<std::string>(opt_group->get_value(key)));
|
||||
}
|
||||
for (auto opt_group : m_active_page->m_optgroups) {
|
||||
assert(opt_group->opt_map().size() == 1);
|
||||
std::string key = opt_group->opt_map().begin()->first;
|
||||
std::string value = boost::any_cast<std::string>(opt_group->get_value(key));
|
||||
std::string config_value = m_config->opt_string(key);
|
||||
valid &= validate_custom_gcode(opt_group->title, value);
|
||||
Field* field = opt_group->get_field(key);
|
||||
TextCtrl* text_ctrl = dynamic_cast<TextCtrl*>(field);
|
||||
if (text_ctrl != nullptr && text_ctrl->m_on_change != nullptr && !text_ctrl->m_disable_change_event) {
|
||||
Slic3r::GUI::t_change callback = opt_group->m_on_change;
|
||||
// temporary disable the opt_group->m_on_change callback to avoid multiple validations
|
||||
opt_group->m_on_change = nullptr;
|
||||
text_ctrl->m_on_change(key, value);
|
||||
// restore the opt_group->m_on_change callback
|
||||
opt_group->m_on_change = callback;
|
||||
|
||||
update_dirty();
|
||||
on_value_change(key, value);
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
break;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -601,7 +601,7 @@ void DiffViewCtrl::AppendBmpTextColumn(const wxString& label, unsigned model_col
|
|||
#ifdef SUPPORTS_MARKUP
|
||||
rd->EnableMarkup(true);
|
||||
#endif
|
||||
wxDataViewColumn* column = new wxDataViewColumn(label, rd, model_column, width, wxALIGN_TOP, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_CELL_INERT);
|
||||
wxDataViewColumn* column = new wxDataViewColumn(label, rd, model_column, width * m_em_unit, wxALIGN_TOP, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_CELL_INERT);
|
||||
#else
|
||||
wxDataViewColumn* column = new wxDataViewColumn(label, new BitmapTextRenderer(true, wxDATAVIEW_CELL_INERT), model_column, width * m_em_unit, wxALIGN_TOP, wxDATAVIEW_COL_RESIZABLE);
|
||||
#endif //__linux__
|
||||
|
|
@ -792,12 +792,12 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection* dependent_
|
|||
wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
||||
SetBackgroundColour(bgr_clr);
|
||||
|
||||
#if ENABLE_WX_3_1_3_DPI_CHANGED_EVENT && defined(__WXMSW__)
|
||||
#if defined(__WXMSW__)
|
||||
// ys_FIXME! temporary workaround for correct font scaling
|
||||
// Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts,
|
||||
// From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT
|
||||
this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||
#endif // ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
|
||||
#endif // __WXMSW__
|
||||
|
||||
int border = 10;
|
||||
int em = em_unit();
|
||||
|
|
@ -806,7 +806,7 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection* dependent_
|
|||
m_action_line->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold());
|
||||
|
||||
m_tree = new DiffViewCtrl(this, wxSize(em * 60, em * 30));
|
||||
m_tree->AppendToggleColumn_(L"\u2714" , DiffModel::colToggle, wxLinux ? 8 : 6);
|
||||
m_tree->AppendToggleColumn_(L"\u2714" , DiffModel::colToggle, wxLinux ? 9 : 6);
|
||||
m_tree->AppendBmpTextColumn("" , DiffModel::colIconText, 28);
|
||||
m_tree->AppendBmpTextColumn(_L("Old Value"), DiffModel::colOldValue, 12);
|
||||
m_tree->AppendBmpTextColumn(_L("New Value"), DiffModel::colNewValue, 12);
|
||||
|
|
@ -1375,12 +1375,12 @@ DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe)
|
|||
wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
||||
SetBackgroundColour(bgr_clr);
|
||||
|
||||
#if ENABLE_WX_3_1_3_DPI_CHANGED_EVENT && defined(__WXMSW__)
|
||||
#if defined(__WXMSW__)
|
||||
// ys_FIXME! temporary workaround for correct font scaling
|
||||
// Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts,
|
||||
// From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT
|
||||
this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||
#endif // ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
|
||||
#endif // __WXMSW__
|
||||
|
||||
int border = 10;
|
||||
int em = em_unit();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue