mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-20 14:08:20 +00:00
Merge branch 'main' into zaa
This commit is contained in:
commit
b945c957d8
838 files changed
+81546
-33829
No files matched your search
@@ -88,6 +88,7 @@ using namespace nlohmann;
|
||||
|
||||
#ifdef __WXGTK__
|
||||
#include <X11/Xlib.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef SLIC3R_GUI
|
||||
@@ -1191,6 +1192,17 @@ int CLI::run(int argc, char **argv)
|
||||
// mode forces software rendering, which works reliably on all backends.
|
||||
::setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", /* replace */ false);
|
||||
|
||||
// On Linux dual-GPU systems, request the high-performance discrete GPU.
|
||||
// DRI_PRIME=1 handles AMD and nouveau (open-source NVIDIA) PRIME setups.
|
||||
::setenv("DRI_PRIME", "1", /* replace */ false);
|
||||
|
||||
// For NVIDIA proprietary driver PRIME render offload, set additional variables.
|
||||
// Only set if the NVIDIA kernel module is loaded to avoid breaking systems without NVIDIA.
|
||||
if (::access("/proc/driver/nvidia/version", F_OK) == 0) {
|
||||
::setenv("__NV_PRIME_RENDER_OFFLOAD", "1", /* replace */ false);
|
||||
::setenv("__GLX_VENDOR_LIBRARY_NAME", "nvidia", /* replace */ false);
|
||||
}
|
||||
|
||||
// Also on Linux, we need to tell Xlib that we will be using threads,
|
||||
// lest we crash when we fire up GStreamer.
|
||||
XInitThreads();
|
||||
|
||||
@@ -257,8 +257,9 @@ SplittedLine do_split_line(const ClipperZUtils::ZPath& path, const ExPolygons& c
|
||||
idx++;
|
||||
} else {
|
||||
if (!is_src(node.front()->front())) {
|
||||
const auto& last = result.back();
|
||||
if (result.empty() || last.get_src_index() != to_src_idx(p)) {
|
||||
if (result.empty() || result.back().get_src_index() != to_src_idx(p)) {
|
||||
//const auto& last = result.back();
|
||||
//if (result.empty() || last.get_src_index() != to_src_idx(p)) {
|
||||
result.emplace_back(to_point(p), false, idx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,6 +196,9 @@ void AppConfig::set_defaults()
|
||||
if (get("seq_top_layer_only").empty())
|
||||
set("seq_top_layer_only", "1");
|
||||
|
||||
if (get("filaments_area_preferred_count").empty())
|
||||
set("filaments_area_preferred_count", "10");
|
||||
|
||||
if (get("use_perspective_camera").empty())
|
||||
set_bool("use_perspective_camera", true);
|
||||
|
||||
@@ -248,6 +251,9 @@ void AppConfig::set_defaults()
|
||||
if (get("show_3d_navigator").empty())
|
||||
set_bool("show_3d_navigator", true);
|
||||
|
||||
if (get("show_plate_gridlines").empty())
|
||||
set_bool("show_plate_gridlines", true);
|
||||
|
||||
if (get("show_outline").empty())
|
||||
set_bool("show_outline", false);
|
||||
|
||||
|
||||
@@ -29,7 +29,12 @@ using namespace nlohmann;
|
||||
#define SETTING_NETWORK_PLUGIN_UPDATE_DISABLED "network_plugin_update_prompts_disabled"
|
||||
#define SETTING_NETWORK_PLUGIN_REMIND_LATER "network_plugin_remind_later"
|
||||
#define SETTING_USE_ENCRYPTED_TOKEN_FILE "use_encrypted_token_file"
|
||||
#define BAMBU_NETWORK_AGENT_VERSION_LEGACY "01.10.01.01"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define BAMBU_NETWORK_AGENT_VERSION_LEGACY "01.10.01.09"
|
||||
#else
|
||||
#define BAMBU_NETWORK_AGENT_VERSION_LEGACY "01.10.01.01"
|
||||
#endif
|
||||
|
||||
#define SUPPORT_DARK_MODE
|
||||
//#define _MSW_DARK_MODE
|
||||
|
||||
@@ -450,6 +450,8 @@ set(lisbslic3r_sources
|
||||
Timer.hpp
|
||||
TriangleMesh.cpp
|
||||
TriangleMesh.hpp
|
||||
TriangleMeshDeal.cpp
|
||||
TriangleMeshDeal.hpp
|
||||
TriangleMeshSlicer.cpp
|
||||
TriangleMeshSlicer.hpp
|
||||
TriangleSelector.cpp
|
||||
|
||||
@@ -318,6 +318,24 @@ ConfigOption* ConfigOptionDef::create_default_option() const
|
||||
return this->create_empty_option();
|
||||
}
|
||||
|
||||
bool ConfigOptionDef::is_value_valid(const double value, const int max_precision /*= 4*/) const
|
||||
{
|
||||
// Special handling for the nil values
|
||||
// The nil value is a valid one only for nullable options
|
||||
if (std::isnan(value))
|
||||
return this->nullable;
|
||||
|
||||
// Special handling of 0
|
||||
if (this->min == 0.f && value < 0)
|
||||
return false;
|
||||
|
||||
const double ep = std::pow(0.1, max_precision);
|
||||
if (is_approx(value, (double) this->min, ep) || is_approx(value, (double) this->max, ep))
|
||||
return true;
|
||||
|
||||
return this->min <= value && value <= this->max;
|
||||
}
|
||||
|
||||
// Assignment of the serialization IDs is not thread safe. The Defs shall be initialized from the main thread!
|
||||
ConfigOptionDef* ConfigDef::add(const t_config_option_key &opt_key, ConfigOptionType type)
|
||||
{
|
||||
|
||||
+22
-12
@@ -4,6 +4,7 @@
|
||||
#include <assert.h>
|
||||
#include <map>
|
||||
#include <climits>
|
||||
#include <cfloat>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
@@ -36,9 +37,9 @@ namespace Slic3r {
|
||||
template<class Archive> void serialize(Archive& ar) { ar(this->value); ar(this->percent); }
|
||||
};
|
||||
|
||||
inline bool operator==(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value == r.value && l.percent == r.percent; }
|
||||
inline bool operator==(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return is_approx(l.value, r.value) && l.percent == r.percent; }
|
||||
inline bool operator!=(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return !(l == r); }
|
||||
inline bool operator< (const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value < r.value || (l.value == r.value && int(l.percent) < int(r.percent)); }
|
||||
inline bool operator< (const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value < r.value || (is_approx(l.value, r.value) && int(l.percent) < int(r.percent)); }
|
||||
}
|
||||
|
||||
namespace std {
|
||||
@@ -761,8 +762,8 @@ public:
|
||||
ConfigOptionType type() const override { return static_type(); }
|
||||
double getFloat() const override { return this->value; }
|
||||
ConfigOption* clone() const override { return new ConfigOptionFloat(*this); }
|
||||
bool operator==(const ConfigOptionFloat &rhs) const throw() { return this->value == rhs.value; }
|
||||
bool operator< (const ConfigOptionFloat &rhs) const throw() { return this->value < rhs.value; }
|
||||
bool operator==(const ConfigOptionFloat &rhs) const throw() { return is_approx(this->value, rhs.value); }
|
||||
bool operator< (const ConfigOptionFloat &rhs) const throw() { return this->value < rhs.value; }
|
||||
|
||||
std::string serialize() const override
|
||||
{
|
||||
@@ -779,6 +780,14 @@ public:
|
||||
return !iss.fail();
|
||||
}
|
||||
|
||||
bool operator==(const ConfigOption &rhs) const override
|
||||
{
|
||||
if (rhs.type() != this->type())
|
||||
throw ConfigurationError("ConfigOptionFloat: Comparing incompatible types");
|
||||
assert(dynamic_cast<const ConfigOptionFloat*>(&rhs));
|
||||
return *this == *static_cast<const ConfigOptionFloat*>(&rhs);
|
||||
}
|
||||
|
||||
ConfigOptionFloat& operator=(const ConfigOption *opt)
|
||||
{
|
||||
this->set(opt);
|
||||
@@ -905,7 +914,7 @@ protected:
|
||||
if (v1.size() != v2.size())
|
||||
return false;
|
||||
for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end(); ++ it1, ++ it2)
|
||||
if (! ((std::isnan(*it1) && std::isnan(*it2)) || *it1 == *it2))
|
||||
if (! ((std::isnan(*it1) && std::isnan(*it2)) || is_approx(*it1, *it2)))
|
||||
return false;
|
||||
return true;
|
||||
} else
|
||||
@@ -1257,11 +1266,11 @@ public:
|
||||
return *this == *static_cast<const ConfigOptionFloatOrPercent*>(&rhs);
|
||||
}
|
||||
bool operator==(const ConfigOptionFloatOrPercent &rhs) const throw()
|
||||
{ return this->value == rhs.value && this->percent == rhs.percent; }
|
||||
{ return is_approx(this->value, rhs.value) && this->percent == rhs.percent; }
|
||||
size_t hash() const throw() override
|
||||
{ size_t seed = std::hash<double>{}(this->value); return this->percent ? seed ^ 0x9e3779b9 : seed; }
|
||||
bool operator< (const ConfigOptionFloatOrPercent &rhs) const throw()
|
||||
{ return this->value < rhs.value || (this->value == rhs.value && int(this->percent) < int(rhs.percent)); }
|
||||
{ return this->value < rhs.value || (is_approx(this->value, rhs.value) && int(this->percent) < int(rhs.percent)); }
|
||||
|
||||
double get_abs_value(double ratio_over) const
|
||||
{ return this->percent ? (ratio_over * this->value / 100) : this->value; }
|
||||
@@ -2085,11 +2094,11 @@ class ConfigOptionEnumsGenericTempl : public ConfigOptionInts
|
||||
public:
|
||||
ConfigOptionEnumsGenericTempl(const t_config_enum_values *keys_map = nullptr) : keys_map(keys_map) {}
|
||||
explicit ConfigOptionEnumsGenericTempl(const t_config_enum_values *keys_map, size_t size, int value) : ConfigOptionInts(size, value), keys_map(keys_map) {}
|
||||
explicit ConfigOptionEnumsGenericTempl(std::initializer_list<int> il) : ConfigOptionInts(std::move(il)), keys_map(keys_map) {}
|
||||
explicit ConfigOptionEnumsGenericTempl(std::initializer_list<int> il) : ConfigOptionInts(std::move(il)) {}
|
||||
explicit ConfigOptionEnumsGenericTempl(const std::vector<int> &vec) : ConfigOptionInts(vec) {}
|
||||
explicit ConfigOptionEnumsGenericTempl(std::vector<int> &&vec) : ConfigOptionInts(std::move(vec)) {}
|
||||
|
||||
const t_config_enum_values* keys_map = nullptr;
|
||||
const t_config_enum_values* keys_map { nullptr };
|
||||
|
||||
static ConfigOptionType static_type() { return coEnums; }
|
||||
ConfigOptionType type() const override { return static_type(); }
|
||||
@@ -2455,10 +2464,11 @@ public:
|
||||
// Optional width of an input field.
|
||||
int width = -1;
|
||||
// <min, max> limit of a numeric input.
|
||||
// If not set, the <min, max> is set to <INT_MIN, INT_MAX>
|
||||
// If not set, the <min, max> is set to <-FLT_MAX, FLT_MAX>
|
||||
// By setting min=0, only nonnegative input is allowed.
|
||||
int min = INT_MIN;
|
||||
int max = INT_MAX;
|
||||
float min = -FLT_MAX;
|
||||
float max = FLT_MAX;
|
||||
bool is_value_valid(const double value, const int max_precision = 4) const;
|
||||
// To check if it's not a typo and a % is missing
|
||||
double max_literal = 1;
|
||||
ConfigOptionMode mode = comSimple;
|
||||
|
||||
@@ -111,7 +111,7 @@ void fuzzy_polyline(Points& poly, bool closed, coordf_t slice_z, const FuzzySkin
|
||||
}
|
||||
|
||||
// Thanks Cura developers for this function.
|
||||
void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice_z, const FuzzySkinConfig& cfg)
|
||||
void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice_z, const FuzzySkinConfig& cfg, bool closed)
|
||||
{
|
||||
std::unique_ptr<noise::module::Module> noise = get_noise_module(cfg);
|
||||
|
||||
@@ -124,9 +124,12 @@ void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice
|
||||
Arachne::ExtrusionJunctions out;
|
||||
out.reserve(ext_lines.size());
|
||||
for (auto& p1 : ext_lines) {
|
||||
if (p0->p == p1.p) { // Connect endpoints.
|
||||
out.emplace_back(p1.p, p1.w, p1.perimeter_index);
|
||||
continue;
|
||||
// Orca: only skip the first point for closed path, open path should not skip any point
|
||||
if (closed) {
|
||||
if (p0->p == p1.p) { // Connect endpoints.
|
||||
out.emplace_back(p1.p, p1.w, p1.perimeter_index);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 'a' is the (next) new point between p0 and p1
|
||||
@@ -266,11 +269,11 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim
|
||||
BoundingBox bbox = get_extents(perimeter_generator.slices->surfaces);
|
||||
bbox.offset(scale_(1.));
|
||||
::Slic3r::SVG svg(debug_out_path("fuzzy_traverse_loops_%d_%d_%d_region_%d.svg", perimeter_generator.layer_id,
|
||||
loop.is_contour ? 0 : 1, loop.depth, i)
|
||||
is_contour ? 0 : 1, loop_idx, i)
|
||||
.c_str(),
|
||||
bbox);
|
||||
svg.draw_outline(perimeter_generator.slices->surfaces);
|
||||
svg.draw_outline(loop.polygon, "green");
|
||||
svg.draw_outline(polygon, "green");
|
||||
svg.draw(r.second, "red", 0.5);
|
||||
svg.draw_outline(r.second, "red");
|
||||
svg.Close();
|
||||
@@ -298,11 +301,21 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim
|
||||
fuzzified.points.clear();
|
||||
|
||||
const auto fuzzy_current_segment = [&segment, &fuzzified, &r, slice_z]() {
|
||||
fuzzified.points.push_back(segment.front());
|
||||
const auto back = segment.back();
|
||||
// Orca: non fuzzy points to isolate fuzzy region
|
||||
const auto front = segment.front();
|
||||
const auto back = segment.back();
|
||||
|
||||
fuzzy_polyline(segment, false, slice_z, r.first);
|
||||
//Orca: only add non fuzzy point if it's not in the polygon closing point.
|
||||
if (!fuzzified.points.empty()
|
||||
&& fuzzified.points.back() != front) {
|
||||
fuzzified.points.push_back(front);
|
||||
}
|
||||
fuzzified.points.insert(fuzzified.points.end(), segment.begin(), segment.end());
|
||||
fuzzified.points.push_back(back);
|
||||
//Orca: only add non fuzzy point if it's not in the polygon closing point.
|
||||
if (!fuzzified.points.empty() && fuzzified.points.back() != front) {
|
||||
fuzzified.points.push_back(back);
|
||||
}
|
||||
segment.clear();
|
||||
};
|
||||
|
||||
@@ -325,7 +338,12 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Orca: ensure the loop is closed after fuzzification
|
||||
if (!fuzzified.points.empty() && fuzzified.points.front() != fuzzified.points.back()) {
|
||||
fuzzified.points.back() = fuzzified.points.front();
|
||||
}
|
||||
|
||||
return fuzzified;
|
||||
}
|
||||
|
||||
@@ -348,6 +366,35 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
|
||||
}
|
||||
}
|
||||
if (!fuzzified_regions.empty()) {
|
||||
|
||||
#ifdef DEBUG_FUZZY
|
||||
{
|
||||
int i = 0;
|
||||
for (const auto& r : fuzzified_regions) {
|
||||
BoundingBox bbox = get_extents(perimeter_generator.slices->surfaces);
|
||||
bbox.offset(scale_(1.));
|
||||
::Slic3r::SVG svg(debug_out_path("fuzzy_traverse_loops_%d_%d_%d_region_%d.svg", perimeter_generator.layer_id,
|
||||
is_contour ? 0 : 1, extrusion->inset_idx, i)
|
||||
.c_str(),
|
||||
bbox);
|
||||
|
||||
// Convert extrusion line to polygon for visualization
|
||||
Polygon extrusion_polygon;
|
||||
extrusion_polygon.points.reserve(extrusion->junctions.size());
|
||||
for (const auto& junction : extrusion->junctions) {
|
||||
extrusion_polygon.points.push_back(junction.p);
|
||||
}
|
||||
|
||||
svg.draw_outline(perimeter_generator.slices->surfaces);
|
||||
svg.draw_outline(extrusion_polygon, "green");
|
||||
svg.draw(r.second, "red", 0.5);
|
||||
svg.draw_outline(r.second, "red");
|
||||
svg.Close();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Split the loops into lines with different config, and fuzzy them separately
|
||||
for (const auto& r : fuzzified_regions) {
|
||||
const auto splitted = Algorithm::split_line(*extrusion, r.second, false);
|
||||
@@ -360,6 +407,7 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
|
||||
if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) {
|
||||
// The entire polygon is fuzzified
|
||||
fuzzy_extrusion_line(extrusion->junctions, slice_z, r.first);
|
||||
continue;
|
||||
} else {
|
||||
const auto current_ext = extrusion->junctions;
|
||||
std::vector<Arachne::ExtrusionJunction> segment;
|
||||
@@ -367,11 +415,20 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
|
||||
extrusion->junctions.clear();
|
||||
|
||||
const auto fuzzy_current_segment = [&segment, &extrusion, &r, slice_z]() {
|
||||
extrusion->junctions.push_back(segment.front());
|
||||
const auto back = segment.back();
|
||||
fuzzy_extrusion_line(segment, slice_z, r.first);
|
||||
// Orca: non fuzzy points to isolate fuzzy region
|
||||
const auto front = segment.front();
|
||||
const auto back = segment.back();
|
||||
|
||||
fuzzy_extrusion_line(segment, slice_z, r.first, false);
|
||||
// Orca: only add non fuzzy point if it's not in the extrusion closing point.
|
||||
if (!extrusion->junctions.empty() && extrusion->junctions.front().p != front.p) {
|
||||
extrusion->junctions.push_back(front);
|
||||
}
|
||||
extrusion->junctions.insert(extrusion->junctions.end(), segment.begin(), segment.end());
|
||||
extrusion->junctions.push_back(back);
|
||||
// Orca: only add non fuzzy point if it's not in the extrusion closing point.
|
||||
if (!extrusion->junctions.empty() && extrusion->junctions.back().p != front.p) {
|
||||
extrusion->junctions.push_back(back);
|
||||
}
|
||||
segment.clear();
|
||||
};
|
||||
|
||||
@@ -398,6 +455,12 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
|
||||
if (!segment.empty()) {
|
||||
fuzzy_current_segment();
|
||||
}
|
||||
|
||||
//Orca: ensure the loop is closed after fuzzy
|
||||
if (!extrusion->junctions.empty() && extrusion->junctions.front().p != extrusion->junctions.back().p) {
|
||||
extrusion->junctions.back().p = extrusion->junctions.front().p;
|
||||
extrusion->junctions.back().w = extrusion->junctions.front().w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Slic3r::Feature::FuzzySkin {
|
||||
|
||||
void fuzzy_polyline(Points& poly, bool closed, coordf_t slice_z, const FuzzySkinConfig& cfg);
|
||||
|
||||
void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice_z, const FuzzySkinConfig& cfg);
|
||||
void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice_z, const FuzzySkinConfig& cfg, bool closed = true);
|
||||
|
||||
void group_region_by_fuzzify(PerimeterGenerator& g);
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ double calculate_infill_rotation_angle(const PrintObject* object,
|
||||
idx = std::min(idx, (int) object->layers().size() - 1);
|
||||
limit_fill_z = object->get_layer(idx)->print_z + sdx * object->config().layer_height;
|
||||
}
|
||||
repeats = std::max(--repeats, 0);
|
||||
repeats = std::max(repeats - 1, 0);
|
||||
} else
|
||||
_noop = true; // set the dumb cycle
|
||||
if (_absolute) { // is absolute
|
||||
|
||||
@@ -3021,24 +3021,25 @@ bool FillRectilinear::fill_surface_by_multilines(const Surface *surface, FillPar
|
||||
multiline_fill(fill_lines, params, spacing);
|
||||
|
||||
// Contract surface polygon by half line width to avoid excesive overlap with perimeter
|
||||
ExPolygons contracted = offset_ex(surface->expolygon, -float(scale_(0.5 * this->spacing)));
|
||||
|
||||
// if contraction results in empty polygon, use original surface
|
||||
const ExPolygon &intersection_surface = contracted.empty() ? surface->expolygon : contracted.front();
|
||||
const ExPolygons contracted = offset_ex(surface->expolygon, -float(scale_(0.5 * this->spacing)));
|
||||
|
||||
// if contraction results in empty ExPolygons, use original surface
|
||||
const ExPolygons& intersection_surface = contracted.empty() ? ExPolygons{surface->expolygon} : contracted;
|
||||
|
||||
// Intersect polylines with perimeter
|
||||
fill_lines = intersection_pl(std::move(fill_lines), intersection_surface);
|
||||
|
||||
if ((params.pattern == ipLateralLattice || params.pattern == ipLateralHoneycomb ) && params.multiline >1 )
|
||||
remove_overlapped(fill_lines, line_width);
|
||||
if ((params.pattern == ipLateralLattice || params.pattern == ipLateralHoneycomb) && params.multiline > 1)
|
||||
remove_overlapped(fill_lines, line_width);
|
||||
|
||||
if (!fill_lines.empty()) {
|
||||
if (params.dont_connect()) {
|
||||
if (params.dont_connect()) {
|
||||
if (fill_lines.size() > 1)
|
||||
fill_lines = chain_polylines(std::move(fill_lines));
|
||||
append(polylines_out, std::move(fill_lines));
|
||||
} else
|
||||
connect_infill(std::move(fill_lines), intersection_surface, polylines_out, this->spacing, params);
|
||||
connect_infill(std::move(fill_lines), to_polygons(intersection_surface), get_extents(surface->expolygon.contour), polylines_out,
|
||||
this->spacing, params);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -3268,7 +3269,7 @@ bool FillRectilinear::fill_surface_trapezoidal(
|
||||
ExPolygons contracted = offset_ex(expolygon, -float(scale_(0.5 * this->spacing)));
|
||||
|
||||
// if contraction results in empty polygon, use original surface
|
||||
const ExPolygon &intersection_surface = contracted.empty() ? expolygon : contracted.front();
|
||||
const ExPolygons& intersection_surface = contracted.empty() ? ExPolygons{expolygon} : contracted;
|
||||
|
||||
// Intersect polylines with offset expolygon
|
||||
polylines = intersection_pl(std::move(polylines), intersection_surface);
|
||||
@@ -3284,7 +3285,14 @@ bool FillRectilinear::fill_surface_trapezoidal(
|
||||
// Connect infill lines using offset expolygon
|
||||
int infill_start_idx = polylines_out.size();
|
||||
if (!polylines.empty()) {
|
||||
Slic3r::Fill::chain_or_connect_infill(std::move(polylines), intersection_surface, polylines_out, this->spacing, params);
|
||||
if (params.dont_connect()) {
|
||||
if (polylines.size() > 1)
|
||||
polylines = chain_polylines(std::move(polylines));
|
||||
append(polylines_out, std::move(polylines));
|
||||
} else {
|
||||
connect_infill(std::move(polylines), to_polygons(intersection_surface), get_extents(intersection_surface), polylines_out,
|
||||
this->spacing, params);
|
||||
}
|
||||
|
||||
// Rotate back the infill lines to original orientation
|
||||
if (std::abs(base_angle) >= EPSILON) {
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Slic3r {
|
||||
bool load_drc(const char *path, TriangleMesh *meshptr)
|
||||
{
|
||||
try {
|
||||
boost::iostreams::mapped_file_source file(path);
|
||||
boost::iostreams::mapped_file_source file{boost::filesystem::path{path}};
|
||||
|
||||
DecoderBuffer buffer;
|
||||
buffer.Init(file.data(), file.size());
|
||||
|
||||
+227
-23
@@ -882,7 +882,23 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
config.set_key_value("old_retract_length_toolchange", new ConfigOptionFloat(old_retract_length_toolchange));
|
||||
config.set_key_value("new_retract_length_toolchange", new ConfigOptionFloat(new_retract_length_toolchange));
|
||||
config.set_key_value("old_filament_temp", new ConfigOptionInt(old_filament_temp));
|
||||
int interface_temp = full_config.filament_tower_interface_print_temp.get_at(new_filament_id);
|
||||
if (interface_temp == -1)
|
||||
interface_temp = full_config.nozzle_temperature_range_high.get_at(new_filament_id);
|
||||
if (full_config.enable_tower_interface_features && tcr.is_contact)
|
||||
new_filament_temp = interface_temp;
|
||||
config.set_key_value("new_filament_temp", new ConfigOptionInt(new_filament_temp));
|
||||
if (full_config.enable_tower_interface_features && tcr.is_contact) {
|
||||
auto temps = full_config.nozzle_temperature.values;
|
||||
if (new_filament_id >= 0 && new_filament_id < (int)temps.size())
|
||||
temps[new_filament_id] = interface_temp;
|
||||
config.set_key_value("temperature", new ConfigOptionInts(temps));
|
||||
|
||||
auto first_layer_temps = full_config.nozzle_temperature_initial_layer.values;
|
||||
if (new_filament_id >= 0 && new_filament_id < (int)first_layer_temps.size())
|
||||
first_layer_temps[new_filament_id] = interface_temp;
|
||||
config.set_key_value("first_layer_temperature", new ConfigOptionInts(first_layer_temps));
|
||||
}
|
||||
config.set_key_value("x_after_toolchange", new ConfigOptionFloat(tool_change_start_pos(0)));
|
||||
config.set_key_value("y_after_toolchange", new ConfigOptionFloat(tool_change_start_pos(1)));
|
||||
config.set_key_value("z_after_toolchange", new ConfigOptionFloat(nozzle_pos(2)));
|
||||
@@ -912,6 +928,9 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
config.set_key_value("flush_length", new ConfigOptionFloat(purge_length));
|
||||
config.set_key_value("wipe_avoid_perimeter", new ConfigOptionBool(is_used_travel_avoid_perimeter));
|
||||
config.set_key_value("wipe_avoid_pos_x", new ConfigOptionFloat(wipe_avoid_pos_x));
|
||||
config.set_key_value("is_prime_tower_interface", new ConfigOptionBool(tcr.is_contact));
|
||||
config.set_key_value("filament_tower_interface_purge_volume", new ConfigOptionFloat(full_config.filament_tower_interface_purge_volume.get_at(new_filament_id)));
|
||||
config.set_key_value("filament_tower_interface_print_temp", new ConfigOptionInt(interface_temp));
|
||||
|
||||
int flush_count = std::min(g_max_flush_count, (int) std::round(purge_volume / g_purge_volume_one_time));
|
||||
float flush_unit = purge_length / flush_count;
|
||||
@@ -1146,10 +1165,18 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
|
||||
std::string toolchange_gcode_str;
|
||||
std::string deretraction_str;
|
||||
int toolchange_temp_override = -1;
|
||||
int interface_temp = -1;
|
||||
if (tcr.priming || (new_extruder_id >= 0 && needs_toolchange)) {
|
||||
if (is_ramming)
|
||||
gcodegen.m_wipe.reset_path(); // We don't want wiping on the ramming lines.
|
||||
toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z); // TODO: toolchange_z vs print_z
|
||||
if (gcodegen.config().enable_tower_interface_features && tcr.is_contact) {
|
||||
interface_temp = gcodegen.config().filament_tower_interface_print_temp.get_at(new_extruder_id);
|
||||
if (interface_temp == -1)
|
||||
interface_temp = gcodegen.config().nozzle_temperature_range_high.get_at(new_extruder_id);
|
||||
toolchange_temp_override = interface_temp;
|
||||
}
|
||||
toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z, false, toolchange_temp_override); // TODO: toolchange_z vs print_z
|
||||
if (gcodegen.config().enable_prime_tower) {
|
||||
deretraction_str += gcodegen.writer().travel_to_z(z, "Force restore layer Z", true);
|
||||
Vec3d position{gcodegen.writer().get_position()};
|
||||
@@ -1159,6 +1186,144 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
}
|
||||
}
|
||||
|
||||
if (toolchange_temp_override > 0) {
|
||||
int base_temp = gcodegen.on_first_layer() ? gcodegen.config().nozzle_temperature_initial_layer.get_at(new_extruder_id)
|
||||
: gcodegen.config().nozzle_temperature.get_at(new_extruder_id);
|
||||
if (std::abs(tcr.print_z) < EPSILON)
|
||||
base_temp = gcodegen.config().nozzle_temperature_initial_layer.get_at(new_extruder_id);
|
||||
const std::string t_token = " T" + std::to_string(new_extruder_id);
|
||||
std::string out;
|
||||
out.reserve(toolchange_gcode_str.size());
|
||||
size_t pos = 0;
|
||||
while (pos < toolchange_gcode_str.size()) {
|
||||
size_t line_end = toolchange_gcode_str.find('\n', pos);
|
||||
if (line_end == std::string::npos)
|
||||
line_end = toolchange_gcode_str.size();
|
||||
std::string line = toolchange_gcode_str.substr(pos, line_end - pos);
|
||||
std::string trimmed = line;
|
||||
trimmed.erase(0, trimmed.find_first_not_of(" \t"));
|
||||
bool skip_line = false;
|
||||
if (boost::starts_with(trimmed, "M109")) {
|
||||
bool matches_extruder = trimmed.find(t_token) != std::string::npos;
|
||||
if (!matches_extruder) {
|
||||
size_t t_pos = trimmed.find('T');
|
||||
if (t_pos != std::string::npos) {
|
||||
size_t t_end = trimmed.find_first_not_of("0123456789", t_pos + 1);
|
||||
const std::string t_val = trimmed.substr(t_pos + 1, t_end == std::string::npos ? std::string::npos : t_end - (t_pos + 1));
|
||||
if (!t_val.empty()) {
|
||||
try {
|
||||
matches_extruder = std::stoi(t_val) == new_extruder_id;
|
||||
} catch (...) {
|
||||
matches_extruder = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matches_extruder) {
|
||||
size_t s_pos = trimmed.find('S');
|
||||
if (s_pos != std::string::npos) {
|
||||
size_t s_end = trimmed.find_first_not_of("0123456789", s_pos + 1);
|
||||
const std::string s_val = trimmed.substr(s_pos + 1, s_end == std::string::npos ? std::string::npos : s_end - (s_pos + 1));
|
||||
if (!s_val.empty()) {
|
||||
try {
|
||||
skip_line = std::stoi(s_val) == base_temp;
|
||||
} catch (...) {
|
||||
skip_line = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!skip_line) {
|
||||
out.append(line);
|
||||
if (line_end < toolchange_gcode_str.size())
|
||||
out.push_back('\n');
|
||||
}
|
||||
pos = line_end + 1;
|
||||
}
|
||||
toolchange_gcode_str.swap(out);
|
||||
}
|
||||
|
||||
if (toolchange_temp_override > 0) {
|
||||
const std::string preheat_token = "preheat T" + std::to_string(new_extruder_id);
|
||||
const int preheat_temp = interface_temp > 0 ? interface_temp : toolchange_temp_override;
|
||||
std::string out;
|
||||
out.reserve(tcr_rotated_gcode.size());
|
||||
size_t pos = 0;
|
||||
while (pos < tcr_rotated_gcode.size()) {
|
||||
size_t line_end = tcr_rotated_gcode.find('\n', pos);
|
||||
if (line_end == std::string::npos)
|
||||
line_end = tcr_rotated_gcode.size();
|
||||
std::string line = tcr_rotated_gcode.substr(pos, line_end - pos);
|
||||
std::string trimmed = line;
|
||||
trimmed.erase(0, trimmed.find_first_not_of(" \t"));
|
||||
const bool is_preheat_line = (trimmed.find(preheat_token) != std::string::npos);
|
||||
if (is_preheat_line) {
|
||||
// Preserve early-preheat timing while forcing interface temp for contact toolchanges.
|
||||
size_t s_pos = trimmed.find('S');
|
||||
if (s_pos != std::string::npos) {
|
||||
size_t s_end = trimmed.find_first_not_of("0123456789", s_pos + 1);
|
||||
trimmed.replace(s_pos + 1,
|
||||
(s_end == std::string::npos ? trimmed.size() : s_end) - (s_pos + 1),
|
||||
std::to_string(preheat_temp));
|
||||
// Reapply left indentation from the original line.
|
||||
size_t line_prefix = line.find_first_not_of(" \t");
|
||||
if (line_prefix != std::string::npos)
|
||||
line = line.substr(0, line_prefix) + trimmed;
|
||||
else
|
||||
line = trimmed;
|
||||
}
|
||||
}
|
||||
out.append(line);
|
||||
if (line_end < tcr_rotated_gcode.size())
|
||||
out.push_back('\n');
|
||||
pos = line_end + 1;
|
||||
}
|
||||
tcr_rotated_gcode.swap(out);
|
||||
}
|
||||
|
||||
if (toolchange_temp_override > 0 && interface_temp > 0) {
|
||||
const std::string t_token = " T" + std::to_string(new_extruder_id);
|
||||
std::string out;
|
||||
out.reserve(tcr_rotated_gcode.size());
|
||||
size_t pos = 0;
|
||||
while (pos < tcr_rotated_gcode.size()) {
|
||||
size_t line_end = tcr_rotated_gcode.find('\n', pos);
|
||||
if (line_end == std::string::npos)
|
||||
line_end = tcr_rotated_gcode.size();
|
||||
std::string line = tcr_rotated_gcode.substr(pos, line_end - pos);
|
||||
std::string trimmed = line;
|
||||
trimmed.erase(0, trimmed.find_first_not_of(" \t"));
|
||||
bool skip_line = false;
|
||||
if (boost::starts_with(trimmed, "M109")) {
|
||||
bool matches_extruder = true;
|
||||
if (trimmed.find('T') != std::string::npos)
|
||||
matches_extruder = trimmed.find(t_token) != std::string::npos;
|
||||
if (matches_extruder) {
|
||||
size_t s_pos = trimmed.find('S');
|
||||
if (s_pos != std::string::npos) {
|
||||
size_t s_end = trimmed.find_first_not_of("0123456789", s_pos + 1);
|
||||
const std::string s_val = trimmed.substr(s_pos + 1, s_end == std::string::npos ? std::string::npos : s_end - (s_pos + 1));
|
||||
if (!s_val.empty()) {
|
||||
try {
|
||||
skip_line = std::stoi(s_val) == interface_temp;
|
||||
} catch (...) {
|
||||
skip_line = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!skip_line) {
|
||||
out.append(line);
|
||||
if (line_end < tcr_rotated_gcode.size())
|
||||
out.push_back('\n');
|
||||
}
|
||||
pos = line_end + 1;
|
||||
}
|
||||
tcr_rotated_gcode.swap(out);
|
||||
}
|
||||
|
||||
// Insert the toolchange and deretraction gcode into the generated gcode.
|
||||
|
||||
DynamicConfig config;
|
||||
@@ -1246,11 +1411,12 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
else
|
||||
line_out << ch;
|
||||
}
|
||||
// Strip original wipe tower X/Y even if position unchanged (fixes out of bed moves).
|
||||
line = line_out.str();
|
||||
|
||||
transformed_pos = trans_pos(pos);
|
||||
|
||||
if (transformed_pos != old_pos || never_skip) {
|
||||
line = line_out.str();
|
||||
std::ostringstream oss;
|
||||
oss << std::fixed << std::setprecision(3) << cur_gcode_start;
|
||||
if (transformed_pos.x() != old_pos.x() || never_skip)
|
||||
@@ -1283,7 +1449,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||
}
|
||||
old_pos = Vec2f{-1000.1f, -1000.1f};
|
||||
pos = tcr.tool_change_start_pos;
|
||||
transformed_pos = pos;
|
||||
transformed_pos = trans_pos(pos);
|
||||
}
|
||||
}
|
||||
return gcode_out;
|
||||
@@ -1582,7 +1748,7 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
|
||||
// first layer may result in skirt/brim in the air and maybe other issues.
|
||||
if (layers_to_print.size() == 1u) {
|
||||
if (!has_extrusions)
|
||||
throw Slic3r::SlicingError(_(L("One object has empty initial layer and can't be printed. Please Cut the bottom or enable supports.")), object.id().id);
|
||||
throw Slic3r::SlicingError(_(L("One object has an empty first layer and can't be printed. Please Cut the bottom or enable supports.")), object.id().id);
|
||||
}
|
||||
|
||||
// In case there are extrusions on this layer, check there is a layer to lay it on.
|
||||
@@ -2580,7 +2746,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
m_pa_processor = std::make_unique<AdaptivePAProcessor>(*this, tool_ordering.all_extruders());
|
||||
|
||||
// Emit machine envelope limits for the Marlin firmware.
|
||||
this->print_machine_envelope(file, print, initial_extruder_id);
|
||||
this->print_machine_envelope(file, print);
|
||||
|
||||
// Disable fan.
|
||||
if (m_config.auxiliary_fan.value && print.config().close_fan_the_first_x_layers.get_at(initial_extruder_id)) {
|
||||
@@ -2861,7 +3027,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
}
|
||||
}
|
||||
// wipe tower area
|
||||
if (has_wipe_tower) {
|
||||
if (has_wipe_tower && print.wipe_tower_data().wipe_tower_mesh_data) {
|
||||
Polygon temp_Expoly = print.wipe_tower_data().wipe_tower_mesh_data->bottom;
|
||||
area_sum_temp += temp_Expoly.area();
|
||||
}
|
||||
@@ -3645,23 +3811,22 @@ PlaceholderParserIntegration &ppi = m_placeholder_parser_integration;
|
||||
|
||||
// Print the machine envelope G-code for the Marlin firmware based on the "machine_max_xxx" parameters.
|
||||
// Do not process this piece of G-code by the time estimator, it already knows the values through another sources.
|
||||
void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print, int extruder_id)
|
||||
void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print)
|
||||
{
|
||||
int matched_machine_limit_idx = get_extruder_id(extruder_id) * 2;
|
||||
const auto flavor = print.config().gcode_flavor.value;
|
||||
if ((flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware) &&
|
||||
print.config().emit_machine_limits_to_gcode.value == true) {
|
||||
int factor = flavor == gcfRepRapFirmware ? 60 : 1; // RRF M203 and M566 are in mm/min
|
||||
file.write_format("M201 X%d Y%d Z%d E%d\n",
|
||||
int(print.config().machine_max_acceleration_x.values[matched_machine_limit_idx] + 0.5),
|
||||
int(print.config().machine_max_acceleration_y.values[matched_machine_limit_idx] + 0.5),
|
||||
int(print.config().machine_max_acceleration_z.values[matched_machine_limit_idx] + 0.5),
|
||||
int(print.config().machine_max_acceleration_e.values[matched_machine_limit_idx] + 0.5));
|
||||
int(print.config().machine_max_acceleration_x.values.front() + 0.5),
|
||||
int(print.config().machine_max_acceleration_y.values.front() + 0.5),
|
||||
int(print.config().machine_max_acceleration_z.values.front() + 0.5),
|
||||
int(print.config().machine_max_acceleration_e.values.front() + 0.5));
|
||||
file.write_format("M203 X%d Y%d Z%d E%d\n",
|
||||
int(print.config().machine_max_speed_x.values[matched_machine_limit_idx] * factor + 0.5),
|
||||
int(print.config().machine_max_speed_y.values[matched_machine_limit_idx] * factor + 0.5),
|
||||
int(print.config().machine_max_speed_z.values[matched_machine_limit_idx] * factor + 0.5),
|
||||
int(print.config().machine_max_speed_e.values[matched_machine_limit_idx] * factor + 0.5));
|
||||
int(print.config().machine_max_speed_x.values.front() * factor + 0.5),
|
||||
int(print.config().machine_max_speed_y.values.front() * factor + 0.5),
|
||||
int(print.config().machine_max_speed_z.values.front() * factor + 0.5),
|
||||
int(print.config().machine_max_speed_e.values.front() * factor + 0.5));
|
||||
|
||||
// Now M204 - acceleration. This one is quite hairy thanks to how Marlin guys care about
|
||||
// Legacy Marlin should export travel acceleration the same as printing acceleration.
|
||||
@@ -4720,7 +4885,10 @@ LayerResult GCode::process_layer(
|
||||
if (print.config().print_sequence == PrintSequence::ByObject) {
|
||||
filament_to_print_instances[filament_id] = sort_print_object_instances(objects_by_extruder_it->second, layers, ordering, single_object_instance_idx);
|
||||
} else {
|
||||
filament_to_print_instances[filament_id] = sort_print_object_instances(objects_by_extruder_it->second, layers, &new_ordering, single_object_instance_idx);
|
||||
|
||||
// PrintSequence::ByLayer to use global ordering ( per object ordering ) if intra-layer order PrintOrder::AsObjectList is specified while keeping behaviour of PrintSequence::ByLayer
|
||||
const std::vector<const PrintInstance*>* ordering_for_filament = (print.config().print_order == PrintOrder::AsObjectList && ordering != nullptr) ? ordering: &new_ordering;
|
||||
filament_to_print_instances[filament_id] = sort_print_object_instances(objects_by_extruder_it->second, layers, ordering_for_filament, single_object_instance_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5236,7 +5404,7 @@ void GCode::append_full_config(const Print &print, std::string &str)
|
||||
size_t temp_begin_t = idx * matrix_value_count, temp_end_t = (idx + 1) * matrix_value_count;
|
||||
std::transform(temp_flush_volumes_matrix.begin() + temp_begin_t, temp_flush_volumes_matrix.begin() + temp_end_t,
|
||||
temp_flush_volumes_matrix.begin() + temp_begin_t,
|
||||
[temp_cfg_flush_multiplier_idx](double inputx) { return inputx * temp_cfg_flush_multiplier_idx; });
|
||||
[temp_cfg_flush_multiplier_idx](double inputx) { return std::round(inputx * temp_cfg_flush_multiplier_idx); });
|
||||
}
|
||||
cfg.option<ConfigOptionFloats>("flush_volumes_matrix")->values = temp_flush_volumes_matrix;
|
||||
} else if (filament_count_tmp == 1) {
|
||||
@@ -5925,9 +6093,9 @@ bool GCode::_needSAFC(const ExtrusionPath &path)
|
||||
};
|
||||
|
||||
return std::any_of(std::begin(supported_patterns), std::end(supported_patterns), [&](const InfillPattern pattern) {
|
||||
return this->on_first_layer() && this->config().bottom_surface_pattern == pattern ||
|
||||
path.role() == erSolidInfill && this->config().internal_solid_infill_pattern == pattern ||
|
||||
path.role() == erTopSolidInfill && this->config().top_surface_pattern == pattern;
|
||||
return (this->on_first_layer() && this->config().bottom_surface_pattern == pattern) ||
|
||||
(path.role() == erSolidInfill && this->config().internal_solid_infill_pattern == pattern) ||
|
||||
(path.role() == erTopSolidInfill && this->config().top_surface_pattern == pattern);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6160,7 +6328,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
if (speed == 0)
|
||||
speed = filament_max_volumetric_speed / _mm3_per_mm;
|
||||
if (this->on_first_layer()) {
|
||||
//BBS: for solid infill of initial layer, speed can be higher as long as
|
||||
//BBS: for solid infill of first layer, speed can be higher as long as
|
||||
//wall lines have be attached
|
||||
if (path.role() != erBottomSurface)
|
||||
speed = m_config.get_abs_value("initial_layer_speed");
|
||||
@@ -7233,7 +7401,7 @@ std::string GCode::retract(bool toolchange, bool is_last_retraction, LiftType li
|
||||
return gcode;
|
||||
}
|
||||
|
||||
std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bool by_object)
|
||||
std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bool by_object, int toolchange_temp_override)
|
||||
{
|
||||
int new_extruder_id = get_extruder_id(new_filament_id);
|
||||
if (!m_writer.need_toolchange(new_filament_id))
|
||||
@@ -7321,6 +7489,8 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
||||
// BBS: if print_z == 0 use first layer temperature
|
||||
if (abs(print_z) < EPSILON)
|
||||
new_filament_temp = m_config.nozzle_temperature_initial_layer.get_at(new_filament_id);
|
||||
if (toolchange_temp_override > 0)
|
||||
new_filament_temp = toolchange_temp_override;
|
||||
|
||||
Vec3d nozzle_pos = m_writer.get_position();
|
||||
float old_retract_length, old_retract_length_toolchange, wipe_volume;
|
||||
@@ -7413,6 +7583,27 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
||||
dyn_config.set_key_value("travel_point_3_y", new ConfigOptionFloat(float(travel_point_3.y())));
|
||||
dyn_config.set_key_value("wipe_avoid_perimeter", new ConfigOptionBool(false));
|
||||
dyn_config.set_key_value("wipe_avoid_pos_x", new ConfigOptionFloat(wipe_avoid_pos_x));
|
||||
dyn_config.set_key_value("is_prime_tower_interface", new ConfigOptionBool(false));
|
||||
dyn_config.set_key_value("filament_tower_interface_purge_volume", new ConfigOptionFloat(m_config.filament_tower_interface_purge_volume.get_at(new_filament_id)));
|
||||
{
|
||||
int interface_temp = m_config.filament_tower_interface_print_temp.get_at(new_filament_id);
|
||||
if (interface_temp == -1)
|
||||
interface_temp = m_config.nozzle_temperature_range_high.get_at(new_filament_id);
|
||||
dyn_config.set_key_value("filament_tower_interface_print_temp", new ConfigOptionInt(interface_temp));
|
||||
}
|
||||
if (toolchange_temp_override > 0) {
|
||||
auto temps = m_config.nozzle_temperature.values;
|
||||
if (new_filament_id < temps.size())
|
||||
temps[new_filament_id] = toolchange_temp_override;
|
||||
dyn_config.set_key_value("temperature", new ConfigOptionInts(temps));
|
||||
dyn_config.set_key_value("nozzle_temperature", new ConfigOptionInts(temps));
|
||||
|
||||
auto first_layer_temps = m_config.nozzle_temperature_initial_layer.values;
|
||||
if (new_filament_id < first_layer_temps.size())
|
||||
first_layer_temps[new_filament_id] = toolchange_temp_override;
|
||||
dyn_config.set_key_value("first_layer_temperature", new ConfigOptionInts(first_layer_temps));
|
||||
dyn_config.set_key_value("nozzle_temperature_initial_layer", new ConfigOptionInts(first_layer_temps));
|
||||
}
|
||||
|
||||
auto flush_v_speed = m_print->config().filament_flush_volumetric_speed.values;
|
||||
auto flush_temps =m_print->config().filament_flush_temp.values;
|
||||
@@ -7513,6 +7704,19 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position().z() - m_config.z_offset.value));
|
||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(new_filament_id)));
|
||||
if (toolchange_temp_override > 0) {
|
||||
auto temps = m_config.nozzle_temperature.values;
|
||||
if (new_filament_id < temps.size())
|
||||
temps[new_filament_id] = toolchange_temp_override;
|
||||
config.set_key_value("temperature", new ConfigOptionInts(temps));
|
||||
config.set_key_value("nozzle_temperature", new ConfigOptionInts(temps));
|
||||
|
||||
auto first_layer_temps = m_config.nozzle_temperature_initial_layer.values;
|
||||
if (new_filament_id < first_layer_temps.size())
|
||||
first_layer_temps[new_filament_id] = toolchange_temp_override;
|
||||
config.set_key_value("first_layer_temperature", new ConfigOptionInts(first_layer_temps));
|
||||
config.set_key_value("nozzle_temperature_initial_layer", new ConfigOptionInts(first_layer_temps));
|
||||
}
|
||||
gcode += this->placeholder_parser_process("filament_start_gcode", filament_start_gcode, new_filament_id, &config);
|
||||
if (add_change_filament_624) {
|
||||
gcode += "M625\n";
|
||||
|
||||
@@ -249,7 +249,7 @@ public:
|
||||
bool needs_retraction(const Polyline& travel, ExtrusionRole role, LiftType& lift_type);
|
||||
std::string retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::NormalLift, bool apply_instantly = false, ExtrusionRole role = erNone);
|
||||
std::string unretract() { return m_writer.unlift() + m_writer.unretract(); }
|
||||
std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false);
|
||||
std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false, int toolchange_temp_override = -1);
|
||||
bool is_BBL_Printer();
|
||||
bool is_QIDI_Printer();
|
||||
|
||||
@@ -641,7 +641,7 @@ private:
|
||||
double calc_max_volumetric_speed(const double layer_height, const double line_width, const std::string co_str);
|
||||
std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1);
|
||||
bool _needSAFC(const ExtrusionPath &path);
|
||||
void print_machine_envelope(GCodeOutputStream& file, Print& print, int extruder_id);
|
||||
void print_machine_envelope(GCodeOutputStream& file, Print& print);
|
||||
void _print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
||||
void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
||||
// On the first printing layer. This flag triggers first layer speeds.
|
||||
|
||||
@@ -879,8 +879,8 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START] = true;
|
||||
need_set_fan = true;
|
||||
}
|
||||
} else if (line->type & CoolingLine::TYPE_IRONING_FAN_END && fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START]) {
|
||||
if (ironing_fan_control) {
|
||||
} else if (line->type & CoolingLine::TYPE_IRONING_FAN_END) {
|
||||
if (ironing_fan_control && fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START]) {
|
||||
fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START] = false;
|
||||
}
|
||||
need_set_fan = true;
|
||||
|
||||
@@ -124,7 +124,7 @@ static void set_option_value(ConfigOptionFloats& option, size_t id, float value)
|
||||
static float get_option_value(const ConfigOptionFloats& option, size_t id)
|
||||
{
|
||||
return option.values.empty() ? 0.0f :
|
||||
((id < option.values.size()) ? static_cast<float>(option.values[id]) : static_cast<float>(option.values.back()));
|
||||
((id < option.values.size()) ? static_cast<float>(option.values[id]) : static_cast<float>(option.values.front()));
|
||||
}
|
||||
|
||||
static float estimated_acceleration_distance(float initial_rate, float target_rate, float acceleration)
|
||||
@@ -1259,7 +1259,7 @@ void GCodeProcessor::run_post_process()
|
||||
// line inserter
|
||||
[tool_number, this](unsigned int id, const std::vector<float>& time_diffs) {
|
||||
const int temperature = int(m_layer_id != 1 ? m_filament_nozzle_temp[tool_number] :
|
||||
m_filament_nozzle_temp_first_layer[tool_number]);
|
||||
m_filament_nozzle_temp_first_layer[tool_number]);
|
||||
// Orca: M104.1 for XL printers, I can't find the documentation for this so I copied the C++ comments from
|
||||
// Prusa-Firmware-Buddy here
|
||||
/**
|
||||
@@ -1731,6 +1731,10 @@ void GCodeProcessor::register_commands()
|
||||
{"M702", [this](const GCodeReader::GCodeLine& line) { process_M702(line); }}, // Unload the current filament into the MK3 MMU2 unit at the end of print.
|
||||
{"M1020", [this](const GCodeReader::GCodeLine& line) { process_M1020(line); }}, // Select Tool
|
||||
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
{"M900", [this](const GCodeReader::GCodeLine& line) { process_M900(line); }}, // Marlin: Set pressure advance
|
||||
{"M572", [this](const GCodeReader::GCodeLine& line) { process_M572(line); }}, // RepRapFirmware/Duet: Set pressure advance
|
||||
|
||||
{"T", [this](const GCodeReader::GCodeLine& line) { process_T(line); }}, // Select Tool
|
||||
{"SYNC", [this](const GCodeReader::GCodeLine& line) { process_SYNC(line); }}, // SYNC TIME
|
||||
|
||||
@@ -2792,6 +2796,12 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line, bool
|
||||
process_SET_VELOCITY_LIMIT(line);
|
||||
return;
|
||||
}
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
if (boost::iequals(cmd, "SET_PRESSURE_ADVANCE"))
|
||||
{
|
||||
process_SET_PRESSURE_ADVANCE(line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd.length() > 1) {
|
||||
@@ -3931,7 +3941,7 @@ void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes
|
||||
|
||||
curr.abs_axis_feedrate[a] = std::abs(curr.axis_feedrate[a]);
|
||||
if (curr.abs_axis_feedrate[a] != 0.0f) {
|
||||
float axis_max_feedrate = get_axis_max_feedrate(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_extruder_id);
|
||||
float axis_max_feedrate = get_axis_max_feedrate(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
|
||||
if (axis_max_feedrate != 0.0f) min_feedrate_factor = std::min<float>(min_feedrate_factor, axis_max_feedrate / curr.abs_axis_feedrate[a]);
|
||||
}
|
||||
}
|
||||
@@ -3955,7 +3965,7 @@ void GCodeProcessor::process_G1(const std::array<std::optional<double>, 4>& axes
|
||||
|
||||
//BBS
|
||||
for (unsigned char a = X; a <= E; ++a) {
|
||||
float axis_max_acceleration = get_axis_max_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_extruder_id);
|
||||
float axis_max_acceleration = get_axis_max_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
|
||||
if (acceleration * std::abs(delta_pos[a]) * inv_distance > axis_max_acceleration)
|
||||
acceleration = axis_max_acceleration / (std::abs(delta_pos[a]) * inv_distance);
|
||||
}
|
||||
@@ -4289,7 +4299,7 @@ void GCodeProcessor::process_VG1(const GCodeReader::GCodeLine& line)
|
||||
|
||||
curr.abs_axis_feedrate[a] = std::abs(curr.axis_feedrate[a]);
|
||||
if (curr.abs_axis_feedrate[a] != 0.0f) {
|
||||
float axis_max_feedrate = get_axis_max_feedrate(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_extruder_id);
|
||||
float axis_max_feedrate = get_axis_max_feedrate(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
|
||||
if (axis_max_feedrate != 0.0f) min_feedrate_factor = std::min<float>(min_feedrate_factor, axis_max_feedrate / curr.abs_axis_feedrate[a]);
|
||||
}
|
||||
}
|
||||
@@ -4313,7 +4323,7 @@ void GCodeProcessor::process_VG1(const GCodeReader::GCodeLine& line)
|
||||
|
||||
//BBS
|
||||
for (unsigned char a = X; a <= E; ++a) {
|
||||
float axis_max_acceleration = get_axis_max_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_extruder_id);
|
||||
float axis_max_acceleration = get_axis_max_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
|
||||
if (acceleration * std::abs(delta_pos[a]) * inv_distance > axis_max_acceleration)
|
||||
acceleration = axis_max_acceleration / (std::abs(delta_pos[a]) * inv_distance);
|
||||
}
|
||||
@@ -4914,6 +4924,37 @@ void GCodeProcessor::process_M106(const GCodeReader::GCodeLine& line)
|
||||
}
|
||||
}
|
||||
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
void GCodeProcessor::process_M900(const GCodeReader::GCodeLine &line)
|
||||
{
|
||||
float pa_value = m_pressure_advance;
|
||||
line.has_value('K', pa_value);
|
||||
m_pressure_advance = std::max(0.0f, pa_value);
|
||||
// BOOST_LOG_TRIVIAL(debug) << "M900 command: PA set to " << m_pressure_advance;
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_M572(const GCodeReader::GCodeLine &line)
|
||||
{
|
||||
float pa_value = m_pressure_advance;
|
||||
line.has_value('S', pa_value);
|
||||
m_pressure_advance = std::max(0.0f, pa_value);
|
||||
// BOOST_LOG_TRIVIAL(debug) << "M572 command: PA set to " << m_pressure_advance;
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_SET_PRESSURE_ADVANCE(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
std::regex regex(R"(SET_PRESSURE_ADVANCE\s+(?:.*\s+)?ADVANCE\s*=\s*([\d.]+))");
|
||||
std::smatch matches;
|
||||
|
||||
if (std::regex_search(line.raw(), matches, regex) && matches.size() > 1) {
|
||||
float pa_value = 0;
|
||||
try {
|
||||
pa_value = std::stof(matches[1].str());
|
||||
} catch (...) {}
|
||||
m_pressure_advance = std::max(0.0f, pa_value);
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeProcessor::process_M107(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
m_fan_speed = 0.0f;
|
||||
@@ -5016,18 +5057,17 @@ void GCodeProcessor::process_M201(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
// see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration
|
||||
float factor = ((m_flavor != gcfRepRapSprinter && m_flavor != gcfRepRapFirmware) && m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f;
|
||||
int indx_limit = m_time_processor.machine_limits.machine_max_acceleration_x.size() / 2;
|
||||
for (size_t index = 0; index < indx_limit; index += 2) {
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
if (static_cast<PrintEstimatedStatistics::ETimeMode>(i) == PrintEstimatedStatistics::ETimeMode::Normal || m_time_processor.machine_envelope_processing_enabled) {
|
||||
if (line.has_x()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_x, index + i, line.x() * factor);
|
||||
|
||||
if (line.has_y()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_y, index + i, line.y() * factor);
|
||||
// Write to index i (0=Normal, 1=Stealth) — matches get_axis_max_acceleration's read pattern.
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
if (static_cast<PrintEstimatedStatistics::ETimeMode>(i) == PrintEstimatedStatistics::ETimeMode::Normal || m_time_processor.machine_envelope_processing_enabled) {
|
||||
if (line.has_x()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_x, i, line.x() * factor);
|
||||
|
||||
if (line.has_z()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_z, index + i, line.z() * factor);
|
||||
if (line.has_y()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_y, i, line.y() * factor);
|
||||
|
||||
if (line.has_e()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_e, index + i, line.e() * factor);
|
||||
}
|
||||
if (line.has_z()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_z, i, line.z() * factor);
|
||||
|
||||
if (line.has_e()) set_option_value(m_time_processor.machine_limits.machine_max_acceleration_e, i, line.e() * factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5042,23 +5082,20 @@ void GCodeProcessor::process_M203(const GCodeReader::GCodeLine& line)
|
||||
// http://smoothieware.org/supported-g-codes
|
||||
float factor = (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfSmoothie || m_flavor == gcfKlipper) ? 1.0f : MMMIN_TO_MMSEC;
|
||||
|
||||
//BBS:
|
||||
int indx_limit = m_time_processor.machine_limits.machine_max_speed_x.size() / 2;
|
||||
for (size_t index = 0; index < indx_limit; index += 2) {
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
if (static_cast<PrintEstimatedStatistics::ETimeMode>(i) == PrintEstimatedStatistics::ETimeMode::Normal || m_time_processor.machine_envelope_processing_enabled) {
|
||||
if (line.has_x())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_x, index + i, line.x() * factor);
|
||||
// Write to index i (0=Normal, 1=Stealth) — matches get_axis_max_feedrate's read pattern.
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
if (static_cast<PrintEstimatedStatistics::ETimeMode>(i) == PrintEstimatedStatistics::ETimeMode::Normal || m_time_processor.machine_envelope_processing_enabled) {
|
||||
if (line.has_x())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_x, i, line.x() * factor);
|
||||
|
||||
if (line.has_y())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_y, index + i, line.y() * factor);
|
||||
if (line.has_y())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_y, i, line.y() * factor);
|
||||
|
||||
if (line.has_z())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_z, index + i, line.z() * factor);
|
||||
if (line.has_z())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_z, i, line.z() * factor);
|
||||
|
||||
if (line.has_e())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_e, index + i, line.e() * factor);
|
||||
}
|
||||
if (line.has_e())
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_speed_e, i, line.e() * factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5118,6 +5155,9 @@ void GCodeProcessor::process_M205(const GCodeReader::GCodeLine& line)
|
||||
|
||||
if (line.has_value('T', value))
|
||||
set_option_value(m_time_processor.machine_limits.machine_min_travel_rate, i, value);
|
||||
|
||||
if (line.has_value('J', value))
|
||||
set_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, i, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5453,6 +5493,8 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type,
|
||||
m_travel_dist,
|
||||
m_fan_speed,
|
||||
m_extruder_temps[filament_id],
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
m_pressure_advance,
|
||||
{ 0.0f, 0.0f }, // time
|
||||
static_cast<float>(m_layer_id), //layer_duration: set later
|
||||
std::max<unsigned int>(1, m_layer_id) - 1,
|
||||
@@ -5499,49 +5541,94 @@ float GCodeProcessor::minimum_travel_feedrate(PrintEstimatedStatistics::ETimeMod
|
||||
return std::max(feedrate, get_option_value(m_time_processor.machine_limits.machine_min_travel_rate, static_cast<size_t>(mode)));
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_axis_max_feedrate(PrintEstimatedStatistics::ETimeMode mode, Axis axis, int extruder_id) const
|
||||
// Machine limit arrays hold 2 values: [0]=Normal, [1]=Stealth. Index by mode only.
|
||||
// BambuStudio used extruder_id*2+mode to support per-nozzle limits, but OrcaSlicer
|
||||
// never ported that system (filament_map_2 / get_config_idx_for_filament), so the
|
||||
// extruder_id offset was always wrong: uninitialized extruder (255) or extruder > 0
|
||||
// would overshoot the array and fall back to values.back() (stealth limits).
|
||||
float GCodeProcessor::get_axis_max_feedrate(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
|
||||
{
|
||||
int matched_pos = extruder_id * 2;
|
||||
switch (axis)
|
||||
{
|
||||
case X: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_x, matched_pos + static_cast<size_t>(mode)); }
|
||||
case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_y, matched_pos + static_cast<size_t>(mode)); }
|
||||
case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_z, matched_pos + static_cast<size_t>(mode)); }
|
||||
case E: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_e, matched_pos + static_cast<size_t>(mode)); }
|
||||
case X: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_x, static_cast<size_t>(mode)); }
|
||||
case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_y, static_cast<size_t>(mode)); }
|
||||
case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_z, static_cast<size_t>(mode)); }
|
||||
case E: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_e, static_cast<size_t>(mode)); }
|
||||
default: { return 0.0f; }
|
||||
}
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis, int extruder_id) const
|
||||
float GCodeProcessor::get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
|
||||
{
|
||||
int matched_pos = extruder_id * 2;
|
||||
switch (axis)
|
||||
{
|
||||
case X: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_x, matched_pos + static_cast<size_t>(mode)); }
|
||||
case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_y, matched_pos + static_cast<size_t>(mode)); }
|
||||
case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_z, matched_pos + static_cast<size_t>(mode)); }
|
||||
case E: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_e, matched_pos + static_cast<size_t>(mode)); }
|
||||
case X: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_x, static_cast<size_t>(mode)); }
|
||||
case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_y, static_cast<size_t>(mode)); }
|
||||
case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_z, static_cast<size_t>(mode)); }
|
||||
case E: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_e, static_cast<size_t>(mode)); }
|
||||
default: { return 0.0f; }
|
||||
}
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
|
||||
{
|
||||
if (axis != X && axis != Y && axis != Z && axis != E)
|
||||
return 0.0f;
|
||||
|
||||
const size_t id = static_cast<size_t>(mode);
|
||||
const float jd = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, id);
|
||||
if (jd <= 0.0f)
|
||||
return 0.0f;
|
||||
|
||||
const float axis_max_acc = get_axis_max_acceleration(mode, axis);
|
||||
const float generic_acc = get_acceleration(mode);
|
||||
const float effective_acc = axis_max_acc > 0.0f ? axis_max_acc : generic_acc;
|
||||
|
||||
return std::sqrt(jd * effective_acc * 2.5f);
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
|
||||
{
|
||||
const size_t id = static_cast<size_t>(mode);
|
||||
const float jd = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, id);
|
||||
if (m_flavor == gcfMarlinFirmware && jd > 0.0f) {
|
||||
return get_axis_max_jerk_with_jd(mode, axis);
|
||||
}
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case X: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_x, static_cast<size_t>(mode)); }
|
||||
case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_y, static_cast<size_t>(mode)); }
|
||||
case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_z, static_cast<size_t>(mode)); }
|
||||
case E: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_e, static_cast<size_t>(mode)); }
|
||||
case X: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_x, id); }
|
||||
case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_y, id); }
|
||||
case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_z, id); }
|
||||
case E: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_e, id); }
|
||||
default: { return 0.0f; }
|
||||
}
|
||||
}
|
||||
|
||||
Vec3f GCodeProcessor::get_xyz_max_jerk(PrintEstimatedStatistics::ETimeMode mode) const
|
||||
{
|
||||
return Vec3f(get_option_value(m_time_processor.machine_limits.machine_max_jerk_x, static_cast<size_t>(mode)),
|
||||
get_option_value(m_time_processor.machine_limits.machine_max_jerk_y, static_cast<size_t>(mode)),
|
||||
get_option_value(m_time_processor.machine_limits.machine_max_jerk_z, static_cast<size_t>(mode)));
|
||||
// Default values from config
|
||||
const size_t id = static_cast<size_t>(mode);
|
||||
float jx = 0.0f;
|
||||
float jy = 0.0f;
|
||||
float jz = 0.0f;
|
||||
const float jd = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, id);
|
||||
|
||||
// Classic Jerk: Junction Deviation is only supported by Marlin firmware when using a JD value grater than 0.
|
||||
if (m_flavor != gcfMarlinFirmware || jd <= 0.0f)
|
||||
{
|
||||
jx = get_option_value(m_time_processor.machine_limits.machine_max_jerk_x, id);
|
||||
jy = get_option_value(m_time_processor.machine_limits.machine_max_jerk_y, id);
|
||||
jz = get_option_value(m_time_processor.machine_limits.machine_max_jerk_z, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
jx = get_axis_max_jerk_with_jd(mode, X);
|
||||
jy = get_axis_max_jerk_with_jd(mode, Y);
|
||||
jz = get_axis_max_jerk_with_jd(mode, Z);
|
||||
}
|
||||
|
||||
return Vec3f(jx, jy, jz);
|
||||
}
|
||||
|
||||
float GCodeProcessor::get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const
|
||||
@@ -5897,4 +5984,3 @@ int GCodeProcessor::get_extruder_id(bool force_initialize)const
|
||||
}
|
||||
|
||||
} /* namespace Slic3r */
|
||||
|
||||
@@ -184,6 +184,8 @@ class Print;
|
||||
float travel_dist{ 0.0f }; // mm
|
||||
float fan_speed{ 0.0f }; // percentage
|
||||
float temperature{ 0.0f }; // Celsius degrees
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
float pressure_advance{ 0.0f };
|
||||
std::array<float, static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count)> time{ 0.0f, 0.0f }; // s
|
||||
float layer_duration{ 0.0f }; // s
|
||||
unsigned int layer_id{ 0 };
|
||||
@@ -777,6 +779,8 @@ class Print;
|
||||
float m_travel_dist; // mm
|
||||
float m_fan_speed; // percentage
|
||||
float m_z_offset; // mm
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
float m_pressure_advance;
|
||||
ExtrusionRole m_extrusion_role;
|
||||
std::vector<int> m_filament_maps;
|
||||
std::vector<unsigned char> m_last_filament_id;
|
||||
@@ -981,6 +985,12 @@ class Print;
|
||||
// Disable fan
|
||||
void process_M107(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
// Set pressure advance
|
||||
void process_M900(const GCodeReader::GCodeLine& line);
|
||||
void process_M572(const GCodeReader::GCodeLine &line);
|
||||
void process_SET_PRESSURE_ADVANCE(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set tool (Sailfish)
|
||||
void process_M108(const GCodeReader::GCodeLine& line);
|
||||
|
||||
@@ -1059,8 +1069,12 @@ class Print;
|
||||
|
||||
float minimum_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const;
|
||||
float minimum_travel_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const;
|
||||
float get_axis_max_feedrate(PrintEstimatedStatistics::ETimeMode mode, Axis axis, int extruder_id) const;
|
||||
float get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis, int extruder_id) const;
|
||||
// Machine limit arrays are indexed by time mode only: [0]=Normal, [1]=Stealth.
|
||||
// Do NOT add an extruder_id parameter — OrcaSlicer does not use BambuStudio's
|
||||
// per-nozzle machine limits (filament_map_2 / get_config_idx_for_filament).
|
||||
float get_axis_max_feedrate(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
|
||||
float get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
|
||||
float get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
|
||||
float get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const;
|
||||
Vec3f get_xyz_max_jerk(PrintEstimatedStatistics::ETimeMode mode) const;
|
||||
float get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const;
|
||||
|
||||
@@ -541,10 +541,17 @@ void PressureEqualizer::output_gcode_line(const size_t line_idx)
|
||||
// We don't have enough time to accel to max possible extrusion rate
|
||||
// now we calculate the actual possible value
|
||||
target_max_extrusion_rate = std::sqrt((2 * max_sloped_extrusion * sp * sn + sn * e0_2 + sp * e1_2) / (sp + sn));
|
||||
|
||||
// Worst case: we don't have enough time to do an accl-steady-decel movement at all, fallback to the old fashion
|
||||
// single slope mode
|
||||
if (target_max_extrusion_rate <= line.volumetric_extrusion_rate_start ||
|
||||
target_max_extrusion_rate <= line.volumetric_extrusion_rate_end) {
|
||||
goto single_slope_fallback; // TODO: FIXIT: better way than a goto?
|
||||
}
|
||||
}
|
||||
assert(target_max_extrusion_rate > line.volumetric_extrusion_rate_start);
|
||||
assert(target_max_extrusion_rate > line.volumetric_extrusion_rate_end);
|
||||
assert(target_max_extrusion_rate >= line.volumetric_extrusion_rate);
|
||||
assert(target_max_extrusion_rate <= line.volumetric_extrusion_rate);
|
||||
|
||||
// if the extrusion rate change is trivial, then ignore this algorithm and use the single sloped version instead
|
||||
delta_volumetric_rate = std::round(std::min({ // important! it's MIN here not max!
|
||||
@@ -626,7 +633,7 @@ void PressureEqualizer::output_gcode_line(const size_t line_idx)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
single_slope_fallback:
|
||||
bool accelerating = line.volumetric_extrusion_rate_start < line.volumetric_extrusion_rate_end;
|
||||
float feed_avg = 0.5f * (line.pos_start[4] + line.pos_end[4]);
|
||||
// Limiting volumetric extrusion rate slope for this segment.
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
static constexpr float flat_iron_area = 4.f;
|
||||
constexpr float flat_iron_speed = 10.f * 60.f;
|
||||
static const double wipe_tower_wall_infill_overlap = 0.0;
|
||||
static constexpr double WIPE_TOWER_RESOLUTION = 0.1;
|
||||
@@ -1243,7 +1242,8 @@ WipeTower::ToolChangeResult WipeTower::construct_tcr(WipeTowerWriter& writer,
|
||||
size_t old_tool,
|
||||
bool is_finish,
|
||||
bool is_tool_change,
|
||||
float purge_volume) const
|
||||
float purge_volume,
|
||||
bool is_contact) const
|
||||
{
|
||||
ToolChangeResult result;
|
||||
result.priming = priming;
|
||||
@@ -1260,6 +1260,7 @@ WipeTower::ToolChangeResult WipeTower::construct_tcr(WipeTowerWriter& writer,
|
||||
result.is_finish_first = is_finish;
|
||||
result.nozzle_change_result = m_nozzle_change_result;
|
||||
result.is_tool_change = is_tool_change;
|
||||
result.is_contact = is_contact;
|
||||
result.tool_change_start_pos = is_tool_change ? result.start_pos : Vec2f(0, 0);
|
||||
|
||||
// BBS
|
||||
@@ -1283,6 +1284,7 @@ WipeTower::ToolChangeResult WipeTower::construct_block_tcr(WipeTowerWriter &writ
|
||||
result.wipe_path = std::move(writer.wipe_path());
|
||||
result.is_finish_first = is_finish;
|
||||
result.is_tool_change = false;
|
||||
result.is_contact = false;
|
||||
result.tool_change_start_pos = Vec2f(0, 0);
|
||||
// BBS
|
||||
result.purge_volume = purge_volume;
|
||||
@@ -1486,7 +1488,9 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi
|
||||
m_used_fillet(config.wipe_tower_fillet_wall.value),
|
||||
m_extra_spacing((float)config.prime_tower_infill_gap.value/100.f),
|
||||
m_tower_framework(config.prime_tower_enable_framework.value),
|
||||
m_flat_ironing(config.prime_tower_flat_ironing.value)
|
||||
m_flat_ironing(config.prime_tower_flat_ironing.value),
|
||||
m_enable_tower_interface_features(config.enable_tower_interface_features.value),
|
||||
m_enable_tower_interface_cooldown_during_tower(config.enable_tower_interface_cooldown_during_tower.value)
|
||||
{
|
||||
m_flat_ironing = (m_flat_ironing && m_use_gap_wall);
|
||||
// Read absolute value of first layer speed, if given as percentage,
|
||||
@@ -1546,6 +1550,16 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config)
|
||||
m_filpar[idx].nozzle_temperature = config.nozzle_temperature.get_at(idx);
|
||||
m_filpar[idx].nozzle_temperature_initial_layer = config.nozzle_temperature_initial_layer.get_at(idx);
|
||||
m_filpar[idx].category = config.filament_adhesiveness_category.get_at(idx);
|
||||
{
|
||||
int interface_temp = config.filament_tower_interface_print_temp.get_at(idx);
|
||||
if (interface_temp == -1)
|
||||
interface_temp = config.nozzle_temperature_range_high.get_at(idx);
|
||||
m_filpar[idx].interface_print_temperature = interface_temp;
|
||||
}
|
||||
m_filpar[idx].tower_interface_pre_extrusion_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx);
|
||||
m_filpar[idx].tower_interface_pre_extrusion_length = config.filament_tower_interface_pre_extrusion_length.get_at(idx);
|
||||
m_filpar[idx].tower_ironing_area = config.filament_tower_ironing_area.get_at(idx);
|
||||
m_filpar[idx].tower_interface_purge_length = config.filament_tower_interface_purge_volume.get_at(idx);
|
||||
|
||||
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
||||
// Otherwise, the defaults will be used to turn off the SE stuff.
|
||||
@@ -1608,7 +1622,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
|
||||
return std::vector<ToolChangeResult>();
|
||||
}
|
||||
|
||||
Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length)
|
||||
Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length, bool interface_layer, size_t interface_tool)
|
||||
{
|
||||
const float &xl = cleaning_box.ld.x();
|
||||
const float &xr = cleaning_box.rd.x();
|
||||
@@ -1740,7 +1754,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||
}
|
||||
}
|
||||
|
||||
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length);
|
||||
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length, false, tool);
|
||||
writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
||||
|
||||
if (extrude_perimeter) {
|
||||
@@ -1796,7 +1810,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, false, true, purge_volume);
|
||||
return construct_tcr(writer, false, old_tool, false, true, purge_volume, false);
|
||||
}
|
||||
|
||||
WipeTower::NozzleChangeResult WipeTower::nozzle_change(int old_filament_id, int new_filament_id)
|
||||
@@ -2284,6 +2298,8 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool
|
||||
bool first_layer = is_first_layer();
|
||||
// BBS: speed up perimeter speed to 90mm/s for non-first layer
|
||||
float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, 5400.f);
|
||||
if (m_enable_tower_interface_features && m_prev_layer_had_interface)
|
||||
feedrate = std::min(feedrate, 20.f * 60.f);
|
||||
float fill_box_y = m_layer_info->toolchanges_depth() + m_perimeter_width;
|
||||
box_coordinates fill_box(Vec2f(m_perimeter_width, fill_box_y),
|
||||
m_wipe_tower_width - 2 * m_perimeter_width, m_layer_info->depth - fill_box_y);
|
||||
@@ -2426,7 +2442,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, true, false, 0.f);
|
||||
return construct_tcr(writer, false, old_tool, true, false, 0.f, false);
|
||||
}
|
||||
|
||||
// Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box
|
||||
@@ -2646,6 +2662,7 @@ static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first,
|
||||
{
|
||||
assert(first.new_tool == second.initial_tool);
|
||||
WipeTower::ToolChangeResult out = first;
|
||||
out.is_contact = first.is_contact || second.is_contact;
|
||||
if ((first.end_pos - second.start_pos).norm() > (float)EPSILON) {
|
||||
std::string travel_gcode = "G1 X" + Slic3r::float_to_string_decimal_point(second.start_pos.x(), 3) + " Y" +
|
||||
Slic3r::float_to_string_decimal_point(second.start_pos.y(), 3) + " F5400" + "\n";
|
||||
@@ -2769,6 +2786,15 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
}
|
||||
}
|
||||
|
||||
bool interface_layer = solid_toolchange && m_enable_tower_interface_features;
|
||||
if (interface_layer && new_tool < m_filpar.size()) {
|
||||
float extra_purge_length = m_filpar[new_tool].tower_interface_purge_length;
|
||||
if (extra_purge_length > 0.f) {
|
||||
purge_volume += extra_purge_length * m_filpar[new_tool].filament_area;
|
||||
wipe_length += extra_purge_length;
|
||||
}
|
||||
}
|
||||
|
||||
WipeTowerBlock* block = get_block_by_category(m_filpar[new_tool].category, false);
|
||||
if (!block) {
|
||||
assert(block != nullptr);
|
||||
@@ -2795,7 +2821,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
|
||||
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
|
||||
if (new_tool != (unsigned int) -1) { // This is not the last change.
|
||||
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length);
|
||||
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length, interface_layer, new_tool);
|
||||
writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
||||
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n");
|
||||
@@ -2804,6 +2830,23 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
toolchange_Change(writer, new_tool, m_filpar[new_tool].material); // Change the tool, set a speed override for soluble and flex materials.
|
||||
toolchange_Load(writer, cleaning_box);
|
||||
|
||||
int base_temp = is_first_layer() ? m_filpar[new_tool].nozzle_temperature_initial_layer : m_filpar[new_tool].nozzle_temperature;
|
||||
if (interface_layer) {
|
||||
int interface_temp = m_filpar[new_tool].interface_print_temperature;
|
||||
if (interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(interface_temp, true);
|
||||
if (m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(base_temp, false);
|
||||
float pre_dist = m_filpar[new_tool].tower_interface_pre_extrusion_dist;
|
||||
float pre_len = m_filpar[new_tool].tower_interface_pre_extrusion_length;
|
||||
if (pre_dist > 0.f && pre_len > 0.f) {
|
||||
bool start_left = (m_cur_layer_id % 4 == 0 || m_cur_layer_id % 4 == 3);
|
||||
float target_x = writer.x() + (start_left ? pre_dist : -pre_dist);
|
||||
target_x = std::max(cleaning_box.ld.x(), std::min(cleaning_box.rd.x(), target_x));
|
||||
writer.extrude_explicit(target_x, writer.y(), pre_len, 600.f);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_is_multi_extruder && is_tpu_filament(new_tool)) {
|
||||
float dy = m_layer_info->extra_spacing * m_nozzle_change_perimeter_width;
|
||||
if (m_layer_info->extra_spacing < m_tpu_fixed_spacing) {
|
||||
@@ -2838,6 +2881,13 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
|
||||
toolchange_wipe_new(writer, cleaning_box, wipe_length, solid_toolchange);
|
||||
|
||||
if (interface_layer) {
|
||||
int base_temp = is_first_layer() ? m_filpar[new_tool].nozzle_temperature_initial_layer : m_filpar[new_tool].nozzle_temperature;
|
||||
int interface_temp = m_filpar[new_tool].interface_print_temperature;
|
||||
if (!m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(base_temp, false);
|
||||
}
|
||||
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n");
|
||||
++m_num_tool_changes;
|
||||
} else
|
||||
@@ -2859,7 +2909,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool sol
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, false, true, purge_volume);
|
||||
return construct_tcr(writer, false, old_tool, false, true, purge_volume, interface_layer);
|
||||
}
|
||||
|
||||
WipeTower::NozzleChangeResult WipeTower::nozzle_change_new(int old_filament_id, int new_filament_id, bool solid_infill)
|
||||
@@ -3157,7 +3207,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer_new(bool extrude_perimeter,
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
m_nozzle_change_result.gcode.clear();
|
||||
return construct_tcr(writer, false, m_current_tool, true, false, 0.f);
|
||||
return construct_tcr(writer, false, m_current_tool, true, false, 0.f, false);
|
||||
}
|
||||
|
||||
WipeTower::ToolChangeResult WipeTower::finish_block(const WipeTowerBlock &block, int filament_id, bool extrude_fill)
|
||||
@@ -3350,6 +3400,8 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat
|
||||
}
|
||||
float retract_length = m_filpar[m_current_tool].retract_length;
|
||||
float retract_speed = m_filpar[m_current_tool].retract_speed * 60;
|
||||
const float ironing_area = m_filpar[m_current_tool].tower_ironing_area;
|
||||
const bool do_ironing = m_flat_ironing && (!solid_tool_toolchange || !m_enable_tower_interface_features);
|
||||
|
||||
const float &xl = cleaning_box.ld.x();
|
||||
const float &xr = cleaning_box.rd.x();
|
||||
@@ -3393,10 +3445,10 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat
|
||||
writer.extrude(writer.x() + ironing_length, writer.y(), wipe_speed);
|
||||
writer.retract(retract_length, retract_speed);
|
||||
writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 600.);
|
||||
if (m_flat_ironing) {
|
||||
if (do_ironing && ironing_area > 0.f) {
|
||||
writer.travel(writer.x() + 0.5f * ironing_length, writer.y(), 240.);
|
||||
Vec2f pos{writer.x() + 1.f * ironing_length, writer.y()};
|
||||
writer.spiral_flat_ironing(writer.pos(), flat_iron_area, m_perimeter_width, flat_iron_speed);
|
||||
writer.spiral_flat_ironing(writer.pos(), ironing_area, m_perimeter_width, flat_iron_speed);
|
||||
writer.travel(pos, wipe_speed);
|
||||
} else
|
||||
writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 240.);
|
||||
@@ -3408,10 +3460,10 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat
|
||||
writer.extrude(writer.x() - ironing_length, writer.y(), wipe_speed);
|
||||
writer.retract(retract_length, retract_speed);
|
||||
writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 600.);
|
||||
if (m_flat_ironing) {
|
||||
if (do_ironing && ironing_area > 0.f) {
|
||||
writer.travel(writer.x() - 0.5f * ironing_length, writer.y(), 240.);
|
||||
Vec2f pos{writer.x() - 1.0f * ironing_length, writer.y()};
|
||||
writer.spiral_flat_ironing(writer.pos(), flat_iron_area, m_perimeter_width, flat_iron_speed);
|
||||
writer.spiral_flat_ironing(writer.pos(), ironing_area, m_perimeter_width, flat_iron_speed);
|
||||
writer.travel(pos, wipe_speed);
|
||||
}else
|
||||
writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 240.);
|
||||
@@ -3837,6 +3889,8 @@ void WipeTower::generate_new(std::vector<std::vector<WipeTower::ToolChangeResult
|
||||
for (auto layer : m_plan) {
|
||||
reset_block_status();
|
||||
m_cur_layer_id = index++;
|
||||
m_prev_layer_had_interface = m_current_layer_has_interface;
|
||||
m_current_layer_has_interface = !solid_blocks_id.empty();
|
||||
set_layer(layer.z, layer.height, 0, false, layer.z == m_plan.back().z);
|
||||
|
||||
if (m_layer_info->depth < m_perimeter_width) continue;
|
||||
@@ -4188,7 +4242,7 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall(bool is_new_mode)
|
||||
if (!m_no_sparse_layers || toolchanges_on_layer)
|
||||
if (m_current_tool < m_used_filament_length.size()) m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, true, false, 0.f);
|
||||
return construct_tcr(writer, false, old_tool, true, false, 0.f, false);
|
||||
}
|
||||
|
||||
Polygon WipeTower::generate_rib_polygon(const box_coordinates &wt_box)
|
||||
|
||||
@@ -83,6 +83,7 @@ public:
|
||||
bool priming;
|
||||
|
||||
bool is_tool_change{false};
|
||||
bool is_contact{false};
|
||||
Vec2f tool_change_start_pos;
|
||||
|
||||
// Pass a polyline so that normal G-code generator can do a wipe for us.
|
||||
@@ -160,8 +161,9 @@ public:
|
||||
bool priming,
|
||||
size_t old_tool,
|
||||
bool is_finish,
|
||||
bool is_tool_change,
|
||||
float purge_volume) const;
|
||||
bool is_tool_change,
|
||||
float purge_volume,
|
||||
bool is_contact = false) const;
|
||||
|
||||
ToolChangeResult construct_block_tcr(WipeTowerWriter& writer,
|
||||
bool priming,
|
||||
@@ -319,6 +321,7 @@ public:
|
||||
bool is_support = false;
|
||||
int nozzle_temperature = 0;
|
||||
int nozzle_temperature_initial_layer = 0;
|
||||
int interface_print_temperature = 0;
|
||||
float loading_speed = 0.f;
|
||||
float loading_speed_start = 0.f;
|
||||
float unloading_speed = 0.f;
|
||||
@@ -336,6 +339,10 @@ public:
|
||||
float retract_length;
|
||||
float retract_speed;
|
||||
float wipe_dist;
|
||||
float tower_interface_pre_extrusion_dist = 0.f;
|
||||
float tower_interface_pre_extrusion_length = 0.f;
|
||||
float tower_ironing_area = 4.f;
|
||||
float tower_interface_purge_length = 0.f;
|
||||
};
|
||||
|
||||
|
||||
@@ -492,6 +499,10 @@ private:
|
||||
std::map<float,Polylines> m_outer_wall;
|
||||
bool is_first_layer() const { return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; }
|
||||
bool m_flat_ironing=false;
|
||||
bool m_enable_tower_interface_features=false;
|
||||
bool m_enable_tower_interface_cooldown_during_tower=false;
|
||||
bool m_prev_layer_had_interface=false;
|
||||
bool m_current_layer_has_interface=false;
|
||||
// Calculates length of extrusion line to extrude given volume
|
||||
float volume_to_length(float volume, float line_width, float layer_height) const {
|
||||
return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f))));
|
||||
@@ -503,7 +514,7 @@ private:
|
||||
// Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental
|
||||
void make_wipe_tower_square();
|
||||
|
||||
Vec2f get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length);
|
||||
Vec2f get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length, bool interface_layer, size_t interface_tool);
|
||||
|
||||
// Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe
|
||||
void save_on_last_wipe();
|
||||
|
||||
@@ -972,6 +972,25 @@ public:
|
||||
return add_wipe_point(Vec2f(x, y));
|
||||
}
|
||||
|
||||
void spiral_flat_ironing(const Vec2f ¢er, float area, float step_length, float feedrate)
|
||||
{
|
||||
float edge_length = std::sqrt(area);
|
||||
Vec2f box_max = center + Vec2f{step_length, step_length};
|
||||
Vec2f box_min = center - Vec2f{step_length, step_length};
|
||||
int n = std::ceil(edge_length / step_length / 2.f);
|
||||
if (n <= 0)
|
||||
return;
|
||||
while (n--) {
|
||||
travel(box_max.x(), m_current_pos.y(), feedrate);
|
||||
travel(m_current_pos.x(), box_max.y(), feedrate);
|
||||
travel(box_min.x(), m_current_pos.y(), feedrate);
|
||||
travel(m_current_pos.x(), box_min.y(), feedrate);
|
||||
|
||||
box_max += Vec2f{step_length, step_length};
|
||||
box_min -= Vec2f{step_length, step_length};
|
||||
}
|
||||
}
|
||||
|
||||
// Extrude with an explicitely provided amount of extrusion.
|
||||
WipeTowerWriter2& extrude_arc_explicit(ArcSegment& arc,
|
||||
float f = 0.f,
|
||||
@@ -1200,7 +1219,8 @@ private:
|
||||
WipeTower::ToolChangeResult WipeTower2::construct_tcr(WipeTowerWriter2& writer,
|
||||
bool priming,
|
||||
size_t old_tool,
|
||||
bool is_finish) const
|
||||
bool is_finish,
|
||||
bool is_contact) const
|
||||
{
|
||||
WipeTower::ToolChangeResult result;
|
||||
result.priming = priming;
|
||||
@@ -1215,6 +1235,7 @@ WipeTower::ToolChangeResult WipeTower2::construct_tcr(WipeTowerWriter2& writer,
|
||||
result.extrusions = std::move(writer.extrusions());
|
||||
result.wipe_path = std::move(writer.wipe_path());
|
||||
result.is_finish_first = is_finish;
|
||||
result.is_contact = is_contact;
|
||||
// ORCA: Always initialize the tool_change_start_pos with a valid position
|
||||
// to avoid undefined variable travel on X in Gcode.cpp function std::string WipeTowerIntegration::post_process_wipe_tower_moves
|
||||
result.tool_change_start_pos = result.start_pos; // always valid fallback
|
||||
@@ -1250,7 +1271,10 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau
|
||||
m_used_fillet(config.wipe_tower_fillet_wall),
|
||||
m_rib_width(config.wipe_tower_rib_width),
|
||||
m_extra_rib_length(config.wipe_tower_extra_rib_length),
|
||||
m_wall_type((int)config.wipe_tower_wall_type)
|
||||
m_wall_type((int)config.wipe_tower_wall_type),
|
||||
m_flat_ironing(config.prime_tower_flat_ironing.value),
|
||||
m_enable_tower_interface_features(config.enable_tower_interface_features.value),
|
||||
m_enable_tower_interface_cooldown_during_tower(config.enable_tower_interface_cooldown_during_tower.value)
|
||||
{
|
||||
// Read absolute value of first layer speed, if given as percentage,
|
||||
// it is taken over following default. Speeds from config are not
|
||||
@@ -1317,6 +1341,16 @@ void WipeTower2::set_extruder(size_t idx, const PrintConfig& config)
|
||||
m_filpar[idx].temperature = config.nozzle_temperature.get_at(idx);
|
||||
m_filpar[idx].first_layer_temperature = config.nozzle_temperature_initial_layer.get_at(idx);
|
||||
m_filpar[idx].filament_minimal_purge_on_wipe_tower = config.filament_minimal_purge_on_wipe_tower.get_at(idx);
|
||||
{
|
||||
int interface_temp = config.filament_tower_interface_print_temp.get_at(idx);
|
||||
if (interface_temp == -1)
|
||||
interface_temp = config.nozzle_temperature_range_high.get_at(idx);
|
||||
m_filpar[idx].interface_print_temperature = interface_temp;
|
||||
}
|
||||
m_filpar[idx].tower_interface_pre_extrusion_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx);
|
||||
m_filpar[idx].tower_interface_pre_extrusion_length = config.filament_tower_interface_pre_extrusion_length.get_at(idx);
|
||||
m_filpar[idx].tower_ironing_area = config.filament_tower_ironing_area.get_at(idx);
|
||||
m_filpar[idx].tower_interface_purge_length = config.filament_tower_interface_purge_volume.get_at(idx);
|
||||
|
||||
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
||||
// Otherwise, the defaults will be used to turn off the SE stuff.
|
||||
@@ -1440,11 +1474,11 @@ std::vector<WipeTower::ToolChangeResult> WipeTower2::prime(
|
||||
toolchange_Load(writer, cleaning_box); // Prime the tool.
|
||||
if (idx_tool + 1 == tools.size()) {
|
||||
// Last tool should not be unloaded, but it should be wiped enough to become of a pure color.
|
||||
toolchange_Wipe(writer, cleaning_box, wipe_volumes[tools[idx_tool-1]][tool]);
|
||||
toolchange_Wipe(writer, cleaning_box, wipe_volumes[tools[idx_tool-1]][tool], false);
|
||||
} else {
|
||||
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
|
||||
//writer.travel(writer.x(), writer.y() + m_perimeter_width, 7200);
|
||||
toolchange_Wipe(writer, cleaning_box , 20.f);
|
||||
toolchange_Wipe(writer, cleaning_box , 20.f, false);
|
||||
WipeTower::box_coordinates box = cleaning_box;
|
||||
box.translate(0.f, writer.y() - cleaning_box.ld.y() + m_perimeter_width);
|
||||
toolchange_Unload(writer, box , m_filpar[m_current_tool].material, m_filpar[m_current_tool].first_layer_temperature, m_filpar[tools[idx_tool + 1]].first_layer_temperature);
|
||||
@@ -1472,7 +1506,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower2::prime(
|
||||
"\n\n");
|
||||
}
|
||||
|
||||
results.emplace_back(construct_tcr(writer, true, old_tool, true));
|
||||
results.emplace_back(construct_tcr(writer, true, old_tool, true, false));
|
||||
}
|
||||
|
||||
m_old_temperature = -1; // If the priming is turned off in config, the temperature changing commands will not actually appear
|
||||
@@ -1487,6 +1521,7 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
|
||||
|
||||
float wipe_area = 0.f;
|
||||
float wipe_volume = 0.f;
|
||||
bool interface_layer = m_enable_tower_interface_features && m_current_layer_has_interface;
|
||||
|
||||
// Finds this toolchange info
|
||||
if (tool != (unsigned int)(-1))
|
||||
@@ -1501,6 +1536,12 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
|
||||
else {
|
||||
// Otherwise we are going to Unload only. And m_layer_info would be invalid.
|
||||
}
|
||||
if (interface_layer && tool != (unsigned int)(-1) && tool < m_filpar.size()) {
|
||||
float extra_purge_length = m_filpar[tool].tower_interface_purge_length;
|
||||
if (extra_purge_length > 0.f) {
|
||||
wipe_volume += extra_purge_length * m_filpar[tool].filament_area;
|
||||
}
|
||||
}
|
||||
|
||||
WipeTower::box_coordinates cleaning_box(
|
||||
Vec2f(m_perimeter_width / 2.f, m_perimeter_width / 2.f),
|
||||
@@ -1542,7 +1583,27 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
|
||||
toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials.
|
||||
toolchange_Load(writer, cleaning_box);
|
||||
writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road
|
||||
toolchange_Wipe(writer, cleaning_box, wipe_volume); // Wipe the newly loaded filament until the end of the assigned wipe area.
|
||||
int base_temp = is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature;
|
||||
if (interface_layer) {
|
||||
int interface_temp = m_filpar[tool].interface_print_temperature;
|
||||
if (interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(interface_temp, true);
|
||||
if (m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(base_temp, false);
|
||||
float pre_dist = m_filpar[tool].tower_interface_pre_extrusion_dist;
|
||||
float pre_len = m_filpar[tool].tower_interface_pre_extrusion_length;
|
||||
if (pre_dist > 0.f && pre_len > 0.f) {
|
||||
float target_x = writer.x() + pre_dist;
|
||||
target_x = std::max(cleaning_box.ld.x(), std::min(cleaning_box.rd.x(), target_x));
|
||||
writer.extrude_explicit(target_x, writer.y(), pre_len, 600.f);
|
||||
}
|
||||
}
|
||||
toolchange_Wipe(writer, cleaning_box, wipe_volume, interface_layer); // Wipe the newly loaded filament until the end of the assigned wipe area.
|
||||
if (interface_layer) {
|
||||
int interface_temp = m_filpar[tool].interface_print_temperature;
|
||||
if (!m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
|
||||
writer.set_extruder_temp(base_temp, false);
|
||||
}
|
||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n");
|
||||
++ m_num_tool_changes;
|
||||
} else
|
||||
@@ -1564,7 +1625,7 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
|
||||
return construct_tcr(writer, false, old_tool, false);
|
||||
return construct_tcr(writer, false, old_tool, false, interface_layer);
|
||||
}
|
||||
|
||||
|
||||
@@ -1854,7 +1915,8 @@ void WipeTower2::toolchange_Load(
|
||||
void WipeTower2::toolchange_Wipe(
|
||||
WipeTowerWriter2 &writer,
|
||||
const WipeTower::box_coordinates &cleaning_box,
|
||||
float wipe_volume)
|
||||
float wipe_volume,
|
||||
bool interface_layer)
|
||||
{
|
||||
// Increase flow on first layer, slow down print.
|
||||
writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? 1.18f : 1.f))
|
||||
@@ -1884,6 +1946,9 @@ void WipeTower2::toolchange_Wipe(
|
||||
m_left_to_right = !m_left_to_right;
|
||||
}
|
||||
|
||||
const bool do_ironing = m_flat_ironing && (!interface_layer || !m_enable_tower_interface_features);
|
||||
const float ironing_area = m_filpar[m_current_tool].tower_ironing_area;
|
||||
|
||||
// now the wiping itself:
|
||||
for (int i = 0; true; ++i) {
|
||||
if (i!=0) {
|
||||
@@ -1899,6 +1964,11 @@ void WipeTower2::toolchange_Wipe(
|
||||
else
|
||||
writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5f*line_width), writer.y(), wipe_speed);
|
||||
|
||||
if (i == 0 && do_ironing && ironing_area > 0.f) {
|
||||
writer.travel(writer.x(), writer.y(), 600.f);
|
||||
writer.spiral_flat_ironing(writer.pos(), ironing_area, m_perimeter_width, 10.f * 60.f);
|
||||
}
|
||||
|
||||
if (writer.y()+float(EPSILON) > cleaning_box.lu.y()-0.5f*line_width)
|
||||
break; // in case next line would not fit
|
||||
|
||||
@@ -1943,10 +2013,12 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer()
|
||||
.set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f));
|
||||
|
||||
|
||||
// Slow down on the 1st layer.
|
||||
// Slow down on the 1st layer.
|
||||
// If spare layers are excluded -> if 1 or less toolchange has been done, it must be still the first layer, too. So slow down.
|
||||
bool first_layer = is_first_layer() || (m_num_tool_changes <= 1 && m_no_sparse_layers);
|
||||
float feedrate = first_layer ? m_first_layer_speed * 60.f : std::min(m_wipe_tower_max_purge_speed * 60.f, m_infill_speed * 60.f);
|
||||
if (m_enable_tower_interface_features && m_prev_layer_had_interface)
|
||||
feedrate = std::min(feedrate, 20.f * 60.f);
|
||||
float current_depth = m_layer_info->depth - m_layer_info->toolchanges_depth();
|
||||
WipeTower::box_coordinates fill_box(Vec2f(m_perimeter_width, m_layer_info->depth-(current_depth-m_perimeter_width)),
|
||||
m_wipe_tower_width - 2 * m_perimeter_width, current_depth-m_perimeter_width);
|
||||
@@ -2062,6 +2134,11 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer()
|
||||
// Save actual brim width to be later passed to the Print object, which will use it
|
||||
// for skirt calculation and pass it to GLCanvas for precise preview box
|
||||
m_wipe_tower_brim_width_real = loops_num * spacing;
|
||||
|
||||
// Compute actual first-layer bounding box from the outermost brim polygon,
|
||||
// matching how WipeTower::get_bbx() uses m_outer_wall extents.
|
||||
BoundingBox first_layer_box = get_extents(poly);
|
||||
m_first_layer_bbx = BoundingBoxf(unscale(first_layer_box.min), unscale(first_layer_box.max));
|
||||
}
|
||||
|
||||
// Now prepare future wipe.
|
||||
@@ -2077,7 +2154,7 @@ WipeTower::ToolChangeResult WipeTower2::finish_layer()
|
||||
m_current_height += m_layer_info->height;
|
||||
}
|
||||
|
||||
return construct_tcr(writer, false, old_tool, true);
|
||||
return construct_tcr(writer, false, old_tool, true, false);
|
||||
}
|
||||
|
||||
// Static method to get the radius and x-scaling of the stabilizing cone base.
|
||||
@@ -2156,7 +2233,18 @@ void WipeTower2::plan_toolchange(float z_par, float layer_height_par, unsigned i
|
||||
float first_wipe_line = - (width*((length_to_extrude / width)-int(length_to_extrude / width)) - width);
|
||||
|
||||
float first_wipe_volume = length_to_volume(first_wipe_line, m_perimeter_width * m_extra_flow, layer_height_par);
|
||||
float wiping_depth = get_wipe_depth(wipe_volume - first_wipe_volume, layer_height_par, m_perimeter_width, m_extra_flow, m_extra_spacing_wipe, width);
|
||||
|
||||
// ORCA: Keep wipe-depth planning consistent with toolchange_Wipe().
|
||||
// ORCA: On the first layer, toolchange_Wipe() advances purge rows using
|
||||
// ORCA: m_extra_flow * m_perimeter_width, while later layers use
|
||||
// ORCA: m_extra_spacing_wipe * m_perimeter_width.
|
||||
// ORCA: float dy = (is_first_layer() ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width;
|
||||
// ORCA: Use the same spacing here so reserved depth matches consumed depth
|
||||
// ORCA: and first-layer purge segments do not leave visible gaps.
|
||||
const bool first_layer_plan = (m_plan.size() - 1) == m_first_layer_idx;
|
||||
const float planning_spacing = first_layer_plan ? m_extra_flow : m_extra_spacing_wipe;
|
||||
|
||||
float wiping_depth = get_wipe_depth(wipe_volume - first_wipe_volume, layer_height_par, m_perimeter_width, m_extra_flow, planning_spacing, width);
|
||||
|
||||
m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool, ramming_depth + wiping_depth, ramming_depth, first_wipe_line, wipe_volume));
|
||||
}
|
||||
@@ -2213,7 +2301,18 @@ void WipeTower2::save_on_last_wipe()
|
||||
float volume_to_save = length_to_volume(finish_layer().total_extrusion_length_in_plane(), m_perimeter_width, m_layer_info->height);
|
||||
float volume_left_to_wipe = std::max(m_filpar[toolchange.new_tool].filament_minimal_purge_on_wipe_tower, toolchange.wipe_volume_total - volume_to_save);
|
||||
float volume_we_need_depth_for = std::max(0.f, volume_left_to_wipe - length_to_volume(toolchange.first_wipe_line, m_perimeter_width*m_extra_flow, m_layer_info->height));
|
||||
float depth_to_wipe = get_wipe_depth(volume_we_need_depth_for, m_layer_info->height, m_perimeter_width, m_extra_flow, m_extra_spacing_wipe, width);
|
||||
|
||||
// ORCA: Keep wipe-depth planning consistent with toolchange_Wipe().
|
||||
// ORCA: On the first layer, toolchange_Wipe() advances purge rows using
|
||||
// ORCA: m_extra_flow * m_perimeter_width, while later layers use
|
||||
// ORCA: m_extra_spacing_wipe * m_perimeter_width.
|
||||
// ORCA: float dy = (is_first_layer() ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width;
|
||||
// ORCA: Use the same spacing here so reserved depth matches consumed depth
|
||||
// ORCA: and first-layer purge segments do not leave visible gaps.
|
||||
const bool first_layer_plan = size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx;
|
||||
const float planning_spacing = first_layer_plan ? m_extra_flow : m_extra_spacing_wipe;
|
||||
|
||||
float depth_to_wipe = get_wipe_depth(volume_we_need_depth_for, m_layer_info->height, m_perimeter_width, m_extra_flow, planning_spacing, width);
|
||||
|
||||
toolchange.required_depth = toolchange.ramming_depth + depth_to_wipe;
|
||||
toolchange.wipe_volume = volume_left_to_wipe;
|
||||
@@ -2245,6 +2344,7 @@ static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first,
|
||||
{
|
||||
assert(first.new_tool == second.initial_tool);
|
||||
WipeTower::ToolChangeResult out = first;
|
||||
out.is_contact = first.is_contact || second.is_contact;
|
||||
if (first.end_pos != second.start_pos)
|
||||
out.gcode += "G1 X" + Slic3r::float_to_string_decimal_point(second.start_pos.x(), 3)
|
||||
+ " Y" + Slic3r::float_to_string_decimal_point(second.start_pos.y(), 3)
|
||||
|
||||
@@ -31,7 +31,8 @@ public:
|
||||
WipeTower::ToolChangeResult construct_tcr(WipeTowerWriter2& writer,
|
||||
bool priming,
|
||||
size_t old_tool,
|
||||
bool is_finish) const;
|
||||
bool is_finish,
|
||||
bool is_contact = false) const;
|
||||
|
||||
// x -- x coordinates of wipe tower in mm ( left bottom corner )
|
||||
// y -- y coordinates of wipe tower in mm ( left bottom corner )
|
||||
@@ -60,16 +61,19 @@ public:
|
||||
float get_wipe_tower_height() const { return m_wipe_tower_height; }
|
||||
// ORCA: Match WipeTower API used by Print skirt/brim planning.
|
||||
// Returned bounding box is in WIPE-TOWER-LOCAL coordinates (before placement on the bed).
|
||||
// Include brim and y-shift to match what WT gcode actually prints.
|
||||
BoundingBoxf get_bbx() const{
|
||||
// Computed from the actual first-layer polygon (including brim), like WipeTower::get_bbx().
|
||||
BoundingBoxf get_bbx() const {
|
||||
if (m_first_layer_bbx.defined)
|
||||
return m_first_layer_bbx;
|
||||
// Fallback: nominal rectangle (used if generate() hasn't run yet)
|
||||
const float brim = m_wipe_tower_brim_width_real;
|
||||
const Vec2d min(-brim, -brim + double(m_y_shift));
|
||||
const Vec2d max(double(m_wipe_tower_width) + brim, double(m_wipe_tower_depth) + brim + double(m_y_shift));
|
||||
return BoundingBoxf(min, max);
|
||||
return BoundingBoxf(Vec2d(-brim, -brim), Vec2d(double(m_wipe_tower_width) + brim, double(m_wipe_tower_depth) + brim));
|
||||
}
|
||||
// WT2 doesn't currently compute a rib-origin compensation like WipeTower (m_rib_offset),
|
||||
// so expose a zero offset for consistency purposes (to maintain API parity).
|
||||
Vec2f get_rib_offset() const { return Vec2f::Zero(); }
|
||||
float get_rib_width() const { return m_rib_width; }
|
||||
float get_rib_length() const { return m_rib_length; }
|
||||
|
||||
// Switch to a next layer.
|
||||
void set_layer(
|
||||
@@ -88,11 +92,13 @@ public:
|
||||
m_layer_height = layer_height;
|
||||
m_depth_traversed = 0.f;
|
||||
m_current_layer_finished = false;
|
||||
m_prev_layer_had_interface = m_current_layer_has_interface;
|
||||
|
||||
|
||||
// Advance m_layer_info iterator, making sure we got it right
|
||||
while (!m_plan.empty() && m_layer_info->z < print_z - WT_EPSILON && m_layer_info+1 != m_plan.end())
|
||||
++m_layer_info;
|
||||
m_current_layer_has_interface = (m_layer_info != m_plan.end()) && (m_layer_info->toolchanges_depth() > WT_EPSILON);
|
||||
|
||||
//m_current_shape = (! this->is_first_layer() && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL;
|
||||
m_current_shape = SHAPE_NORMAL;
|
||||
@@ -145,6 +151,7 @@ public:
|
||||
bool is_soluble = false;
|
||||
int temperature = 0;
|
||||
int first_layer_temperature = 0;
|
||||
int interface_print_temperature = 0;
|
||||
float loading_speed = 0.f;
|
||||
float loading_speed_start = 0.f;
|
||||
float unloading_speed = 0.f;
|
||||
@@ -168,6 +175,10 @@ public:
|
||||
float filament_minimal_purge_on_wipe_tower = 0.f;
|
||||
float retract_length;
|
||||
float retract_speed;
|
||||
float tower_interface_pre_extrusion_dist = 0.f;
|
||||
float tower_interface_pre_extrusion_length = 0.f;
|
||||
float tower_ironing_area = 4.f;
|
||||
float tower_interface_purge_length = 0.f;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -195,6 +206,7 @@ private:
|
||||
float m_wipe_tower_cone_angle = 0.f;
|
||||
float m_wipe_tower_brim_width = 0.f; // Width of brim (mm) from config
|
||||
float m_wipe_tower_brim_width_real = 0.f; // Width of brim (mm) after generation
|
||||
BoundingBoxf m_first_layer_bbx; // Actual first-layer bounding box (incl. brim/ribs)
|
||||
float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis)
|
||||
float m_internal_rotation = 0.f;
|
||||
float m_y_shift = 0.f; // y shift passed to writer
|
||||
@@ -208,6 +220,11 @@ private:
|
||||
float m_perimeter_speed = 0.f;
|
||||
float m_first_layer_speed = 0.f;
|
||||
size_t m_first_layer_idx = size_t(-1);
|
||||
bool m_flat_ironing = false;
|
||||
bool m_enable_tower_interface_features = false;
|
||||
bool m_enable_tower_interface_cooldown_during_tower = false;
|
||||
bool m_prev_layer_had_interface = false;
|
||||
bool m_current_layer_has_interface = false;
|
||||
|
||||
int m_wall_type;
|
||||
bool m_used_fillet = true;
|
||||
@@ -335,7 +352,8 @@ private:
|
||||
void toolchange_Wipe(
|
||||
WipeTowerWriter2 &writer,
|
||||
const WipeTower::box_coordinates &cleaning_box,
|
||||
float wipe_volume);
|
||||
float wipe_volume,
|
||||
bool interface_layer);
|
||||
|
||||
|
||||
Polygon generate_support_rib_wall(WipeTowerWriter2& writer,
|
||||
|
||||
@@ -49,6 +49,9 @@ void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids)
|
||||
{
|
||||
std::sort(extruder_ids.begin(), extruder_ids.end());
|
||||
m_filament_extruders.clear();
|
||||
//ORCA: Reset current extruder ID and clear pointers to prevent dangling pointers when extruders are recreated.
|
||||
m_curr_extruder_id = -1;
|
||||
std::fill(m_curr_filament_extruder.begin(), m_curr_filament_extruder.end(), nullptr);
|
||||
m_filament_extruders.reserve(extruder_ids.size());
|
||||
for (unsigned int extruder_id : extruder_ids)
|
||||
m_filament_extruders.emplace_back(Extruder(extruder_id, &this->config, config.single_extruder_multi_material.value));
|
||||
@@ -56,7 +59,8 @@ void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids)
|
||||
/* we enable support for multiple extruder if any extruder greater than 0 is used
|
||||
(even if prints only uses that one) since we need to output Tx commands
|
||||
first extruder has index 0 */
|
||||
this->multiple_extruders = (*std::max_element(extruder_ids.begin(), extruder_ids.end())) > 0;
|
||||
//ORCA: Fix undefined behavior by checking if the vector is empty before taking max_element.
|
||||
this->multiple_extruders = !extruder_ids.empty() && (*std::max_element(extruder_ids.begin(), extruder_ids.end())) > 0;
|
||||
}
|
||||
|
||||
std::string GCodeWriter::preamble()
|
||||
|
||||
@@ -343,7 +343,7 @@ void segment(CGALMesh& src, std::vector<CGALMesh>& dst, double smoothing_alpha =
|
||||
std::cout << "* Number of facets in constructed patch: " << patch_facets.size() << std::endl;
|
||||
std::cout << " Number of vertices in constructed patch: " << patch_vertices.size() << std::endl;
|
||||
#else
|
||||
CGAL::Polygon_mesh_processing::triangulate_hole(out, h, std::back_inserter(patch_facets));
|
||||
CGAL::Polygon_mesh_processing::triangulate_hole(out, h, CGAL::parameters::default_values().face_output_iterator(std::back_inserter(patch_facets)));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1170,7 +1170,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
|
||||
this->sla_support_points = std::move(rhs.sla_support_points);
|
||||
this->sla_points_status = std::move(rhs.sla_points_status);
|
||||
this->sla_drain_holes = std::move(rhs.sla_drain_holes);
|
||||
this->brim_points = std::move(brim_points);
|
||||
this->brim_points = std::move(rhs.brim_points);
|
||||
this->layer_config_ranges = std::move(rhs.layer_config_ranges);
|
||||
this->layer_height_profile = std::move(rhs.layer_height_profile);
|
||||
this->printable = std::move(rhs.printable);
|
||||
|
||||
@@ -464,7 +464,7 @@ public:
|
||||
}
|
||||
cost += (costs.bottom < params.BOTTOM_MIN) * 100;// +(costs.height_to_bottom_hull_ratio > params.height_to_bottom_hull_ratio_MIN) * 110;
|
||||
|
||||
costs.unprintability = costs.unprintability = cost;
|
||||
costs.unprintability = cost;
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
@@ -923,6 +923,8 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"prime_tower_width", "prime_tower_brim_width", "prime_tower_skip_points", "prime_volume",
|
||||
"prime_tower_infill_gap",
|
||||
"prime_tower_flat_ironing",
|
||||
"enable_tower_interface_features",
|
||||
"enable_tower_interface_cooldown_during_tower",
|
||||
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits",
|
||||
"flush_into_infill", "flush_into_objects", "flush_into_support",
|
||||
"tree_support_branch_angle", "tree_support_angle_slow", "tree_support_wall_count", "tree_support_top_rate", "tree_support_branch_distance", "tree_support_tip_diameter",
|
||||
@@ -961,6 +963,8 @@ static std::vector<std::string> s_Preset_filament_options {/*"filament_colour",
|
||||
"filament_soluble", "filament_is_support", "filament_printable",
|
||||
"filament_max_volumetric_speed", "filament_adaptive_volumetric_speed",
|
||||
"filament_flow_ratio", "filament_density", "filament_adhesiveness_category", "filament_cost", "filament_minimal_purge_on_wipe_tower",
|
||||
"filament_tower_interface_pre_extrusion_dist", "filament_tower_interface_pre_extrusion_length", "filament_tower_ironing_area", "filament_tower_interface_purge_volume",
|
||||
"filament_tower_interface_print_temp",
|
||||
"nozzle_temperature", "nozzle_temperature_initial_layer",
|
||||
// BBS
|
||||
"cool_plate_temp", "textured_cool_plate_temp", "eng_plate_temp", "hot_plate_temp", "textured_plate_temp", "cool_plate_temp_initial_layer", "textured_cool_plate_temp_initial_layer", "eng_plate_temp_initial_layer", "hot_plate_temp_initial_layer", "textured_plate_temp_initial_layer", "supertack_plate_temp_initial_layer", "supertack_plate_temp",
|
||||
|
||||
+61
-21
@@ -317,6 +317,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
|| opt_key == "prime_tower_brim_width"
|
||||
|| opt_key == "prime_tower_skip_points"
|
||||
|| opt_key == "prime_tower_flat_ironing"
|
||||
|| opt_key == "enable_tower_interface_features"
|
||||
|| opt_key == "first_layer_print_sequence"
|
||||
|| opt_key == "other_layers_print_sequence"
|
||||
|| opt_key == "other_layers_print_sequence_nums"
|
||||
@@ -324,6 +325,11 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
|| opt_key == "filament_map_mode"
|
||||
|| opt_key == "filament_map"
|
||||
|| opt_key == "filament_adhesiveness_category"
|
||||
|| opt_key == "filament_tower_interface_pre_extrusion_dist"
|
||||
|| opt_key == "filament_tower_interface_pre_extrusion_length"
|
||||
|| opt_key == "filament_tower_ironing_area"
|
||||
|| opt_key == "filament_tower_interface_purge_volume"
|
||||
|| opt_key == "filament_tower_interface_print_temp"
|
||||
|| opt_key == "wipe_tower_bridging"
|
||||
|| opt_key == "wipe_tower_extra_flow"
|
||||
|| opt_key == "wipe_tower_no_sparse_layers"
|
||||
@@ -1231,7 +1237,7 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||
} else {
|
||||
if (m_config.enable_wrapping_detection && warning!=nullptr) {
|
||||
StringObjectException warningtemp;
|
||||
warningtemp.string = L("Prime tower is required for clumping detection; otherwise, there may be flaws on the model.");
|
||||
warningtemp.string = L("A prime tower is required for clumping detection; otherwise, there may be flaws on the model.");
|
||||
warningtemp.opt_key = "enable_prime_tower";
|
||||
warningtemp.is_warning = true;
|
||||
*warning = warningtemp;
|
||||
@@ -1484,18 +1490,42 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||
|
||||
// Prusa: Fixing crashes with invalid tip diameter or branch diameter
|
||||
// https://github.com/prusa3d/PrusaSlicer/commit/96b3ae85013ac363cd1c3e98ec6b7938aeacf46d
|
||||
if (is_tree(object->config().support_type.value) && (object->config().support_style == smsTreeOrganic ||
|
||||
// Orca: use organic as default
|
||||
object->config().support_style == smsDefault)) {
|
||||
float extrusion_width = std::min(
|
||||
support_material_flow(object).width(),
|
||||
support_material_interface_flow(object).width());
|
||||
if (object->config().tree_support_tip_diameter < extrusion_width - EPSILON)
|
||||
return { L("Organic support tree tip diameter must not be smaller than support material extrusion width."), object, "tree_support_tip_diameter" };
|
||||
if (object->config().tree_support_branch_diameter_organic < 2. * extrusion_width - EPSILON)
|
||||
return { L("Organic support branch diameter must not be smaller than 2x support material extrusion width."), object, "tree_support_branch_diameter_organic" };
|
||||
if (object->config().tree_support_branch_diameter_organic < object->config().tree_support_tip_diameter)
|
||||
return { L("Organic support branch diameter must not be smaller than support tree tip diameter."), object, "tree_support_branch_diameter_organic" };
|
||||
if (is_tree(object->config().support_type.value)) {
|
||||
if (object->config().support_style == smsTreeOrganic ||
|
||||
// Orca: use organic as default
|
||||
object->config().support_style == smsDefault) {
|
||||
|
||||
if (warning) {
|
||||
// Orca: check the support wall count and the base pattern
|
||||
if (object->config().tree_support_wall_count > 1 &&
|
||||
object->config().support_base_pattern != SupportMaterialPattern::smpNone &&
|
||||
object->config().support_base_pattern != SupportMaterialPattern::smpDefault) {
|
||||
warning->string = L("For Organic supports, two walls are supported only with the Hollow/Default base pattern.");
|
||||
warning->opt_key = "support_base_pattern";
|
||||
}
|
||||
|
||||
// Orca: check if the Lightning base pattern selected
|
||||
if (object->config().support_base_pattern == SupportMaterialPattern::smpLightning) {
|
||||
warning->string = L(
|
||||
"The Lightning base pattern is not supported by this support type; Rectilinear will be used instead.");
|
||||
warning->opt_key = "support_base_pattern";
|
||||
}
|
||||
}
|
||||
|
||||
float extrusion_width = std::min(
|
||||
support_material_flow(object).width(),
|
||||
support_material_interface_flow(object).width());
|
||||
if (object->config().tree_support_tip_diameter < extrusion_width - EPSILON)
|
||||
return { L("Organic support tree tip diameter must not be smaller than support material extrusion width."), object, "tree_support_tip_diameter" };
|
||||
if (object->config().tree_support_branch_diameter_organic < 2. * extrusion_width - EPSILON)
|
||||
return { L("Organic support branch diameter must not be smaller than 2x support material extrusion width."), object, "tree_support_branch_diameter_organic" };
|
||||
if (object->config().tree_support_branch_diameter_organic < object->config().tree_support_tip_diameter)
|
||||
return { L("Organic support branch diameter must not be smaller than support tree tip diameter."), object, "tree_support_branch_diameter_organic" };
|
||||
}
|
||||
} else if (object->config().support_base_pattern == SupportMaterialPattern::smpLightning && warning) {
|
||||
// Orca: check if the Lightning base pattern selected
|
||||
warning->string = L("The Lightning base pattern is not supported by this support type; Rectilinear will be used instead.");
|
||||
warning->opt_key = "support_base_pattern";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2739,14 +2769,6 @@ Vec2d Print::translate_to_print_space(const Point &point) const {
|
||||
|
||||
FilamentTempType Print::get_filament_temp_type(const std::string& filament_type)
|
||||
{
|
||||
// FilamentTempType Temperature-based logic
|
||||
int min_temp, max_temp;
|
||||
if (MaterialType::get_temperature_range(filament_type, min_temp, max_temp)) {
|
||||
if (max_temp <= 250) return FilamentTempType::LowTemp;
|
||||
else if (max_temp < 280) return FilamentTempType::HighLowCompatible;
|
||||
else return FilamentTempType::HighTemp;
|
||||
}
|
||||
|
||||
const static std::string HighTempFilamentStr = "high_temp_filament";
|
||||
const static std::string LowTempFilamentStr = "low_temp_filament";
|
||||
const static std::string HighLowCompatibleFilamentStr = "high_low_compatible_filament";
|
||||
@@ -2781,6 +2803,19 @@ FilamentTempType Print::get_filament_temp_type(const std::string& filament_type)
|
||||
return HighTemp;
|
||||
if (filament_temp_type_map[LowTempFilamentStr].find(filament_type) != filament_temp_type_map[LowTempFilamentStr].end())
|
||||
return LowTemp;
|
||||
|
||||
// Orca: prefer explicit definition from JSON, if the filament type is not defined in json, fallback to temperature-based logic to determine the filament temp type.
|
||||
// FilamentTempType Temperature-based logic
|
||||
int min_temp, max_temp;
|
||||
if (MaterialType::get_temperature_range(filament_type, min_temp, max_temp)) {
|
||||
if (max_temp <= 250)
|
||||
return FilamentTempType::LowTemp;
|
||||
else if (max_temp < 280)
|
||||
return FilamentTempType::HighLowCompatible;
|
||||
else
|
||||
return FilamentTempType::HighTemp;
|
||||
}
|
||||
|
||||
return Undefine;
|
||||
}
|
||||
|
||||
@@ -3379,6 +3414,11 @@ void Print::_make_wipe_tower()
|
||||
|
||||
m_wipe_tower_data.used_filament = wipe_tower.get_used_filament();
|
||||
m_wipe_tower_data.number_of_toolchanges = wipe_tower.get_number_of_toolchanges();
|
||||
m_wipe_tower_data.construct_mesh(wipe_tower.width(), wipe_tower.get_depth(),
|
||||
wipe_tower.get_wipe_tower_height(), wipe_tower.get_brim_width(),
|
||||
config().wipe_tower_wall_type.value == WipeTowerWallType::wtwRib,
|
||||
wipe_tower.get_rib_width(), wipe_tower.get_rib_length(),
|
||||
config().wipe_tower_fillet_wall.value);
|
||||
const Vec3d origin = Vec3d::Zero();
|
||||
m_fake_wipe_tower.set_fake_extrusion_data(wipe_tower.position(), wipe_tower.width(), wipe_tower.get_wipe_tower_height(),
|
||||
config().initial_layer_print_height, m_wipe_tower_data.depth,
|
||||
|
||||
@@ -771,6 +771,7 @@ struct WipeTowerData
|
||||
number_of_toolchanges = -1;
|
||||
depth = 0.f;
|
||||
brim_width = 0.f;
|
||||
rib_offset = Vec2f::Zero();
|
||||
wipe_tower_mesh_data = std::nullopt;
|
||||
}
|
||||
void construct_mesh(float width, float depth, float height, float brim_width, bool is_rib_wipe_tower, float rib_width, float rib_length, bool fillet_wall);
|
||||
|
||||
+245
-86
@@ -296,10 +296,10 @@ static t_config_enum_values s_keys_map_SupportMaterialStyle {
|
||||
{ "default", smsDefault },
|
||||
{ "grid", smsGrid },
|
||||
{ "snug", smsSnug },
|
||||
{ "organic", smsTreeOrganic },
|
||||
{ "tree_slim", smsTreeSlim },
|
||||
{ "tree_strong", smsTreeStrong },
|
||||
{ "tree_hybrid", smsTreeHybrid },
|
||||
{ "organic", smsTreeOrganic }
|
||||
{ "tree_hybrid", smsTreeHybrid }
|
||||
};
|
||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SupportMaterialStyle)
|
||||
|
||||
@@ -439,7 +439,7 @@ CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(OverhangFanThreshold)
|
||||
// BBS
|
||||
static const t_config_enum_values s_keys_map_BedType = {
|
||||
{ "Default Plate", btDefault },
|
||||
{ "Supertack Plate", btSuperTack },
|
||||
{ "SuperTack Plate", btSuperTack },
|
||||
{ "Cool Plate", btPC },
|
||||
{ "Engineering Plate", btEP },
|
||||
{ "High Temp Plate", btPEI },
|
||||
@@ -673,7 +673,7 @@ void PrintConfigDef::init_common_params()
|
||||
def = this->add("elefant_foot_compensation", coFloat);
|
||||
def->label = L("Elephant foot compensation");
|
||||
def->category = L("Quality");
|
||||
def->tooltip = L("Shrinks the initial layer on build plate to compensate for elephant foot effect.");
|
||||
def->tooltip = L("Shrinks the first layer on build plate to compensate for elephant foot effect.");
|
||||
def->sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
@@ -926,9 +926,9 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionInts{45});
|
||||
|
||||
def = this->add("supertack_plate_temp_initial_layer", coInts);
|
||||
def->label = L("Initial layer");
|
||||
def->full_label = L("Initial layer bed temperature");
|
||||
def->tooltip = L("Bed temperature of the initial layer. "
|
||||
def->label = L("First layer");
|
||||
def->full_label = L("First layer bed temperature");
|
||||
def->tooltip = L("Bed temperature of the first layer. "
|
||||
"A value of 0 means the filament does not support printing on the Cool Plate SuperTack.");
|
||||
def->sidetext = L(u8"\u2103" /* °C */); // degrees Celsius, CIS languages need translation
|
||||
def->min = 0;
|
||||
@@ -936,9 +936,9 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionInts{ 35 });
|
||||
|
||||
def = this->add("cool_plate_temp_initial_layer", coInts);
|
||||
def->label = L("Initial layer");
|
||||
def->full_label = L("Initial layer bed temperature");
|
||||
def->tooltip = L("Bed temperature of the initial layer. "
|
||||
def->label = L("First layer");
|
||||
def->full_label = L("First layer bed temperature");
|
||||
def->tooltip = L("Bed temperature of the first layer. "
|
||||
"A value of 0 means the filament does not support printing on the Cool Plate.");
|
||||
def->sidetext = L(u8"\u2103" /* °C */); // degrees Celsius, CIS languages need translation
|
||||
def->min = 0;
|
||||
@@ -946,9 +946,9 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionInts{ 35 });
|
||||
|
||||
def = this->add("textured_cool_plate_temp_initial_layer", coInts);
|
||||
def->label = L("Initial layer");
|
||||
def->full_label = L("Initial layer bed temperature");
|
||||
def->tooltip = L("Bed temperature of the initial layer. "
|
||||
def->label = L("First layer");
|
||||
def->full_label = L("First layer bed temperature");
|
||||
def->tooltip = L("Bed temperature of the first layer. "
|
||||
"A value of 0 means the filament does not support printing on the Textured Cool Plate.");
|
||||
def->sidetext = L(u8"\u2103" /* °C */); // degrees Celsius, CIS languages need translation
|
||||
def->min = 0;
|
||||
@@ -956,9 +956,9 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionInts{ 40 });
|
||||
|
||||
def = this->add("eng_plate_temp_initial_layer", coInts);
|
||||
def->label = L("Initial layer");
|
||||
def->full_label = L("Initial layer bed temperature");
|
||||
def->tooltip = L("Bed temperature of the initial layer. "
|
||||
def->label = L("First layer");
|
||||
def->full_label = L("First layer bed temperature");
|
||||
def->tooltip = L("Bed temperature of the first layer. "
|
||||
"A value of 0 means the filament does not support printing on the Engineering Plate.");
|
||||
def->sidetext = L(u8"\u2103" /* °C */); // degrees Celsius, CIS languages need translation
|
||||
def->min = 0;
|
||||
@@ -966,18 +966,18 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionInts{ 45 });
|
||||
|
||||
def = this->add("hot_plate_temp_initial_layer", coInts);
|
||||
def->label = L("Initial layer");
|
||||
def->full_label = L("Initial layer bed temperature");
|
||||
def->tooltip = L("Bed temperature of the initial layer. "
|
||||
def->label = L("First layer");
|
||||
def->full_label = L("First layer bed temperature");
|
||||
def->tooltip = L("Bed temperature of the first layer. "
|
||||
"A value of 0 means the filament does not support printing on the High Temp Plate.");
|
||||
def->sidetext = L(u8"\u2103" /* °C */); // degrees Celsius, CIS languages need translation
|
||||
def->max = 300;
|
||||
def->set_default_value(new ConfigOptionInts{ 45 });
|
||||
|
||||
def = this->add("textured_plate_temp_initial_layer", coInts);
|
||||
def->label = L("Initial layer");
|
||||
def->full_label = L("Initial layer bed temperature");
|
||||
def->tooltip = L("Bed temperature of the initial layer. "
|
||||
def->label = L("First layer");
|
||||
def->full_label = L("First layer bed temperature");
|
||||
def->tooltip = L("Bed temperature of the first layer. "
|
||||
"A value of 0 means the filament does not support printing on the Textured PEI Plate.");
|
||||
def->sidetext = L(u8"\u2103" /* °C */); // degrees Celsius, CIS languages need translation
|
||||
def->min = 0;
|
||||
@@ -995,7 +995,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_values.emplace_back("High Temp Plate");
|
||||
def->enum_values.emplace_back("Textured PEI Plate");
|
||||
def->enum_values.emplace_back("Textured Cool Plate");
|
||||
def->enum_values.emplace_back("Supertack Plate");
|
||||
def->enum_values.emplace_back("SuperTack Plate");
|
||||
def->enum_labels.emplace_back(L("Smooth Cool Plate"));
|
||||
def->enum_labels.emplace_back(L("Engineering Plate"));
|
||||
def->enum_labels.emplace_back(L("Smooth High Temp Plate"));
|
||||
@@ -1829,7 +1829,7 @@ void PrintConfigDef::init_fff_params()
|
||||
"unnecessary bridges. This works well for most difficult models\n"
|
||||
"3. No filtering - creates internal bridges on every potential internal overhang. This option is "
|
||||
"useful for heavily slanted top surface models; however, in most cases, it creates too many "
|
||||
"unnecessary bridges");
|
||||
"unnecessary bridges.");
|
||||
def->enum_keys_map = &ConfigOptionEnum<InternalBridgeFilter>::get_enum_values();
|
||||
def->enum_values.push_back("disabled");
|
||||
def->enum_values.push_back("limited");
|
||||
@@ -2159,9 +2159,9 @@ void PrintConfigDef::init_fff_params()
|
||||
"You may be able to tune this value to get a nice flat surface if there is slight overflow or underflow."
|
||||
"\n\nThe final object flow ratio is this value multiplied by the filament flow ratio.");
|
||||
def->mode = comAdvanced;
|
||||
def->max = 2;
|
||||
def->min = 0.01;
|
||||
def->set_default_value(new ConfigOptionFloat(1));
|
||||
def->max = 2.f;
|
||||
def->min = 0.01f;
|
||||
def->set_default_value(new ConfigOptionFloat(1.f));
|
||||
|
||||
def = this->add("enable_pressure_advance", coBools);
|
||||
def->label = L("Enable pressure advance");
|
||||
@@ -2208,7 +2208,7 @@ void PrintConfigDef::init_fff_params()
|
||||
"at the bottom of the page. The ideal PA value should be decreasing the higher the volumetric flow is. "
|
||||
"If it is not, confirm that your extruder is functioning correctly. The slower and with less acceleration you print, "
|
||||
"the larger the range of acceptable PA values. If no difference is visible, use the PA value from the faster test\n"
|
||||
"3. Enter the triplets of PA values, Flow and Accelerations in the text box here and save your filament profile");
|
||||
"3. Enter the triplets of PA values, Flow and Accelerations in the text box here and save your filament profile.");
|
||||
def->mode = comAdvanced;
|
||||
//def->gui_flags = "serialized";
|
||||
def->multiline = true;
|
||||
@@ -2405,13 +2405,13 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("bed_temperature_formula", coEnum);
|
||||
def->label = L("Bed temperature type");
|
||||
def->tooltip = L("This option determines how the bed temperature is set during slicing: based on the temperature of the first filament or the highest temperature of the printed filaments.");
|
||||
def->mode = comDevelop;
|
||||
def->mode = comAdvanced;
|
||||
def->enum_keys_map = &ConfigOptionEnum<BedTempFormula>::get_enum_values();
|
||||
def->enum_values.push_back("by_first_filament");
|
||||
def->enum_values.push_back("by_highest_temp");
|
||||
def->enum_labels.push_back(L("By First filament"));
|
||||
def->enum_labels.push_back(L("By Highest Temp"));
|
||||
def->set_default_value(new ConfigOptionEnum<BedTempFormula>(BedTempFormula::btfFirstFilament));
|
||||
def->set_default_value(new ConfigOptionEnum<BedTempFormula>(BedTempFormula::btfHighestTemp));
|
||||
|
||||
def = this->add("nozzle_flush_dataset", coInts);
|
||||
def->nullable = true;
|
||||
@@ -2460,8 +2460,9 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Adaptive volumetric speed");
|
||||
def->tooltip = L("When enabled, the extrusion flow is limited by the smaller of "
|
||||
"the fitted value (calculated from line width and layer height) and the user-defined maximum flow."
|
||||
" When disabled, only the user-defined maximum flow is applied.");
|
||||
def->mode = comAdvanced;
|
||||
" When disabled, only the user-defined maximum flow is applied.\n\n"
|
||||
"Note: Experimental and incomplete feature imported from BBS. Functional for some profiles that already have the variable saved.");
|
||||
def->mode = comDevelop;
|
||||
def->nullable = true;
|
||||
def->set_default_value(new ConfigOptionBoolsNullable {false});
|
||||
|
||||
@@ -2587,6 +2588,46 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloats { 15. });
|
||||
|
||||
def = this->add("filament_tower_interface_pre_extrusion_dist", coFloats);
|
||||
def->label = L("Interface layer pre-extrusion distance");
|
||||
def->tooltip = L("Pre-extrusion distance for prime tower interface layer (where different materials meet).");
|
||||
def->sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloats { 10. });
|
||||
|
||||
def = this->add("filament_tower_interface_pre_extrusion_length", coFloats);
|
||||
def->label = L("Interface layer pre-extrusion length");
|
||||
def->tooltip = L("Pre-extrusion length for prime tower interface layer (where different materials meet).");
|
||||
def->sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloats { 0. });
|
||||
|
||||
def = this->add("filament_tower_ironing_area", coFloats);
|
||||
def->label = L("Tower ironing area");
|
||||
def->tooltip = L("Ironing area for prime tower interface layer (where different materials meet).");
|
||||
def->sidetext = L(u8"mm²"); // square milimeters, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloats { 4. });
|
||||
|
||||
def = this->add("filament_tower_interface_purge_volume", coFloats);
|
||||
def->label = L("Interface layer purge length");
|
||||
def->tooltip = L("Purge length for prime tower interface layer (where different materials meet).");
|
||||
def->sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloats { 20. });
|
||||
|
||||
def = this->add("filament_tower_interface_print_temp", coInts);
|
||||
def->label = L("Interface layer print temperature");
|
||||
def->tooltip = L("Print temperature for prime tower interface layer (where different materials meet). If set to -1, use max recommended nozzle temperature.");
|
||||
def->sidetext = L(u8"\u2103" /* °C */); // degrees Celsius, CIS languages need translation
|
||||
def->min = -1;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionInts { -1 });
|
||||
|
||||
def = this->add("filament_cooling_final_speed", coFloats);
|
||||
def->label = L("Speed of the last cooling move");
|
||||
def->tooltip = L("Cooling moves are gradually accelerating towards this speed.");
|
||||
@@ -2972,9 +3013,9 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionFloatOrPercent(100, true));
|
||||
|
||||
def = this->add("initial_layer_acceleration", coFloat);
|
||||
def->label = L("Initial layer");
|
||||
def->label = L("First layer");
|
||||
def->category = L("Speed");
|
||||
def->tooltip = L("Acceleration of initial layer. Using a lower value can improve build plate adhesion.");
|
||||
def->tooltip = L("Acceleration of the first layer. Using a lower value can improve build plate adhesion.");
|
||||
def->sidetext = L(u8"mm/s²"); // milimeters per second per second, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
@@ -3011,9 +3052,10 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Speed");
|
||||
def->tooltip = L("Marlin Firmware Junction Deviation (replaces the traditional XY Jerk setting).");
|
||||
def->sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->min = 0.f;
|
||||
def->max = 0.5f;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
def->set_default_value(new ConfigOptionFloat(0.f));
|
||||
|
||||
def = this->add("outer_wall_jerk", coFloat);
|
||||
def->label = L("Outer wall");
|
||||
@@ -3052,9 +3094,9 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionFloat(9));
|
||||
|
||||
def = this->add("initial_layer_jerk", coFloat);
|
||||
def->label = L("Initial layer");
|
||||
def->label = L("First layer");
|
||||
def->category = L("Speed");
|
||||
def->tooltip = L("Jerk for initial layer.");
|
||||
def->tooltip = L("Jerk for the first layer.");
|
||||
def->sidetext = L("mm/s"); // milimeters per second, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
@@ -3070,9 +3112,9 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionFloat(12));
|
||||
|
||||
def = this->add("initial_layer_line_width", coFloatOrPercent);
|
||||
def->label = L("Initial layer");
|
||||
def->label = L("First layer");
|
||||
def->category = L("Quality");
|
||||
def->tooltip = L("Line width of initial layer. If expressed as a %, it will be computed over the nozzle diameter.");
|
||||
def->tooltip = L("Line width of the first layer. If expressed as a %, it will be computed over the nozzle diameter.");
|
||||
def->sidetext = L("mm or %");
|
||||
def->ratio_over = "nozzle_diameter";
|
||||
def->min = 0;
|
||||
@@ -3083,9 +3125,9 @@ void PrintConfigDef::init_fff_params()
|
||||
|
||||
|
||||
def = this->add("initial_layer_print_height", coFloat);
|
||||
def->label = L("Initial layer height");
|
||||
def->label = L("First layer height");
|
||||
def->category = L("Quality");
|
||||
def->tooltip = L("Height of initial layer. Making initial layer height to be thick slightly can improve build plate adhesion.");
|
||||
def->tooltip = L("Height of the first layer. Making the first layer height thicker can improve build plate adhesion.");
|
||||
def->sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->set_default_value(new ConfigOptionFloat(0.2));
|
||||
@@ -3099,24 +3141,24 @@ void PrintConfigDef::init_fff_params()
|
||||
//def->set_default_value(new ConfigOptionBool(0));
|
||||
|
||||
def = this->add("initial_layer_speed", coFloat);
|
||||
def->label = L("Initial layer");
|
||||
def->tooltip = L("Speed of initial layer except the solid infill part.");
|
||||
def->label = L("First layer");
|
||||
def->tooltip = L("Speed of the first layer except the solid infill part.");
|
||||
def->sidetext = L("mm/s"); // milimeters per second, CIS languages need translation
|
||||
def->min = 1;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(30));
|
||||
|
||||
def = this->add("initial_layer_infill_speed", coFloat);
|
||||
def->label = L("Initial layer infill");
|
||||
def->tooltip = L("Speed of solid infill part of initial layer.");
|
||||
def->label = L("First layer infill");
|
||||
def->tooltip = L("Speed of solid infill part of the first layer.");
|
||||
def->sidetext = L("mm/s"); // milimeters per second, CIS languages need translation
|
||||
def->min = 1;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(60.0));
|
||||
|
||||
def = this->add("initial_layer_travel_speed", coFloatOrPercent);
|
||||
def->label = L("Initial layer travel speed");
|
||||
def->tooltip = L("Travel speed of initial layer.");
|
||||
def->label = L("First layer travel speed");
|
||||
def->tooltip = L("Travel speed of the first layer.");
|
||||
def->category = L("Speed");
|
||||
def->sidetext = L("mm/s or %");
|
||||
def->ratio_over = "travel_speed";
|
||||
@@ -3135,9 +3177,9 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionInt(0));
|
||||
|
||||
def = this->add("nozzle_temperature_initial_layer", coInts);
|
||||
def->label = L("Initial layer");
|
||||
def->full_label = L("Initial layer nozzle temperature");
|
||||
def->tooltip = L("Nozzle temperature for printing initial layer when using this filament.");
|
||||
def->label = L("First layer");
|
||||
def->full_label = L("First layer nozzle temperature");
|
||||
def->tooltip = L("Nozzle temperature for printing the first layer when using this filament.");
|
||||
def->sidetext = L(u8"\u2103" /* °C */); // degrees Celsius, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->max = max_temp;
|
||||
@@ -3208,7 +3250,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Quality");
|
||||
def->tooltip = L("Filament-specific override for ironing line spacing. This allows you to customize the spacing "
|
||||
"between ironing lines for each filament type.");
|
||||
def->sidetext = "mm";
|
||||
def->sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->max = 1;
|
||||
def->mode = comAdvanced;
|
||||
@@ -3220,7 +3262,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Quality");
|
||||
def->tooltip = L("Filament-specific override for ironing inset. This allows you to customize the distance to keep "
|
||||
"from the edges when ironing for each filament type.");
|
||||
def->sidetext = "mm";
|
||||
def->sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->max = 100;
|
||||
def->mode = comAdvanced;
|
||||
@@ -3232,7 +3274,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Speed");
|
||||
def->tooltip = L("Filament-specific override for ironing speed. This allows you to customize the print speed "
|
||||
"of ironing lines for each filament type.");
|
||||
def->sidetext = "mm/s";
|
||||
def->sidetext = L("mm/s"); // milimeters per second, CIS languages need translation
|
||||
def->min = 1;
|
||||
def->mode = comAdvanced;
|
||||
def->nullable = true;
|
||||
@@ -3249,7 +3291,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_values.push_back("all");
|
||||
def->enum_values.push_back("allwalls");
|
||||
def->enum_values.push_back("disabled_fuzzy");
|
||||
def->enum_labels.push_back(L("None (allow paint)"));
|
||||
def->enum_labels.push_back(L("Painted only"));
|
||||
def->enum_labels.push_back(L("Contour"));
|
||||
def->enum_labels.push_back(L("Contour and hole"));
|
||||
def->enum_labels.push_back(L("All walls"));
|
||||
@@ -3272,10 +3314,10 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Others");
|
||||
def->tooltip = L("The average distance between the random points introduced on each line segment.");
|
||||
def->sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->max = 5;
|
||||
def->min = 0.01f; // point distance cannot be 0! Otherwise we get infinite loop + OOM due to infinite line division.
|
||||
def->max = 5.f;
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionFloat(0.3));
|
||||
def->set_default_value(new ConfigOptionFloat(0.3f));
|
||||
|
||||
def = this->add("fuzzy_skin_first_layer", coBool);
|
||||
def->label = L("Apply fuzzy skin to first layer");
|
||||
@@ -3335,7 +3377,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Others");
|
||||
def->tooltip = L("The base size of the coherent noise features, in mm. Higher values will result in larger features.");
|
||||
def->sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def->min = 0.1;
|
||||
def->min = 0.1f;
|
||||
def->max = 500;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(1.0));
|
||||
@@ -3353,7 +3395,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Fuzzy skin noise persistence");
|
||||
def->category = L("Others");
|
||||
def->tooltip = L("The decay rate for higher octaves of the coherent noise. Lower values will result in smoother noise.");
|
||||
def->min = 0.01;
|
||||
def->min = 0.01f;
|
||||
def->max = 1;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.5));
|
||||
@@ -3591,7 +3633,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("gcode_label_objects", coBool);
|
||||
def->label = L("Label objects");
|
||||
def->tooltip = L("Enable this to add comments into the G-code labeling print moves with what object they belong to,"
|
||||
" which is useful for the Octoprint CancelObject plugin. This settings is NOT compatible with "
|
||||
" which is useful for the Octoprint CancelObject plug-in. This setting is NOT compatible with "
|
||||
"Single Extruder Multi Material setup and Wipe into Object / Wipe into Infill.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(1));
|
||||
@@ -3922,7 +3964,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Ironing Type");
|
||||
def->category = L("Quality");
|
||||
def->tooltip = L("Ironing is using small flow to print on same height of surface again to make flat surface more smooth. "
|
||||
"This setting controls which layer being ironed");
|
||||
"This setting controls which layer being ironed.");
|
||||
def->enum_keys_map = &ConfigOptionEnum<IroningType>::get_enum_values();
|
||||
def->enum_values.push_back("no ironing");
|
||||
def->enum_values.push_back("top");
|
||||
@@ -4216,10 +4258,10 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = L("Maximum junction deviation (M205 J, only apply if JD > 0 for Marlin Firmware\nIf your Marlin 2 printer uses Classic Jerk set this value to 0.)");
|
||||
def->sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->max = 1;
|
||||
def->min = 0.f;
|
||||
def->max = 0.5f;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloats { 0.01});
|
||||
def->set_default_value(new ConfigOptionFloats{ 0.01f });
|
||||
|
||||
// M205 S... [mm/sec]
|
||||
def = this->add("machine_min_extruding_rate", coFloats);
|
||||
@@ -4682,7 +4724,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionFloat(1.5));
|
||||
|
||||
def = this->add("raft_first_layer_density", coPercent);
|
||||
def->label = L("Initial layer density");
|
||||
def->label = L("First layer density");
|
||||
def->category = L("Support");
|
||||
def->tooltip = L("Density of the first raft or support layer.");
|
||||
def->sidetext = "%";
|
||||
@@ -4692,7 +4734,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionPercent(90));
|
||||
|
||||
def = this->add("raft_first_layer_expansion", coFloat);
|
||||
def->label = L("Initial layer expansion");
|
||||
def->label = L("First layer expansion");
|
||||
def->category = L("Support");
|
||||
def->tooltip = L("Expand the first raft or support layer to improve bed plate adhesion.");
|
||||
def->sidetext = L("mm"); // milimeters, CIS languages need translation
|
||||
@@ -5408,7 +5450,7 @@ void PrintConfigDef::init_fff_params()
|
||||
"If smooth mode is selected, the toolhead will move to the excess chute after each layer is printed "
|
||||
"and then take a snapshot. "
|
||||
"Since the melt filament may leak from the nozzle during the process of taking a snapshot, "
|
||||
"prime tower is required for smooth mode to wipe nozzle.");
|
||||
"a prime tower is required for smooth mode to wipe nozzle.");
|
||||
def->enum_keys_map = &ConfigOptionEnum<TimelapseType>::get_enum_values();
|
||||
def->enum_values.emplace_back("0");
|
||||
def->enum_values.emplace_back("1");
|
||||
@@ -5423,7 +5465,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->tooltip = L("Temperature difference to be applied when an extruder is not active. "
|
||||
"The value is not used when 'idle_temperature' in filament settings "
|
||||
"is set to non-zero value.");
|
||||
def->sidetext = L(u8"∆\u2103"); // delta degrees Celsius, CIS languages need translation
|
||||
def->sidetext = L(u8"\u2206\u2103" /* ∆°C */); // delta degrees Celsius, CIS languages need translation
|
||||
def->min = -max_temp;
|
||||
def->max = max_temp;
|
||||
def->mode = comAdvanced;
|
||||
@@ -5785,7 +5827,12 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("support_base_pattern", coEnum);
|
||||
def->label = L("Base pattern");
|
||||
def->category = L("Support");
|
||||
def->tooltip = L("Line pattern of support.");
|
||||
def->tooltip = L("Line pattern of support.\n\n"
|
||||
"The Default option for Tree supports is Hollow, which means no base pattern. "
|
||||
"For other support types, the Default option is the Rectilinear pattern.\n\n"
|
||||
"NOTE: For Organic supports, the two walls are supported only with the Hollow/Default base pattern. "
|
||||
"The Lightning base pattern is supported only by Tree Slim/Strong/Hybrid supports. "
|
||||
"For the other support types, the Rectilinear will be used instead of Lightning.");
|
||||
def->enum_keys_map = &ConfigOptionEnum<SupportMaterialPattern>::get_enum_values();
|
||||
def->enum_values.push_back("default");
|
||||
def->enum_values.push_back("rectilinear");
|
||||
@@ -6401,9 +6448,9 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_values.emplace_back("rectangle");
|
||||
def->enum_values.emplace_back("cone");
|
||||
def->enum_values.emplace_back("rib");
|
||||
def->enum_labels.emplace_back("Rectangle");
|
||||
def->enum_labels.emplace_back("Cone");
|
||||
def->enum_labels.emplace_back("Rib");
|
||||
def->enum_labels.emplace_back(L("Rectangle"));
|
||||
def->enum_labels.emplace_back(L("Cone"));
|
||||
def->enum_labels.emplace_back(L("Rib"));
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionEnum<WipeTowerWallType>(wtwRectangle));
|
||||
|
||||
@@ -6459,6 +6506,18 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("enable_tower_interface_features", coBool);
|
||||
def->label = L("Enable tower interface features");
|
||||
def->tooltip = L("Enable optimized prime tower interface behavior when different materials meet.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("enable_tower_interface_cooldown_during_tower", coBool);
|
||||
def->label = L("Cool down from interface boost during prime tower");
|
||||
def->tooltip = L("When interface-layer temperature boost is active, set the nozzle back to print temperature at the start of the prime tower so it cools down during the tower.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("prime_tower_infill_gap", coPercent);
|
||||
def->label = L("Infill gap");
|
||||
def->tooltip = L("Infill gap.");
|
||||
@@ -6766,6 +6825,7 @@ void PrintConfigDef::init_extruder_option_keys()
|
||||
// ConfigOptionFloats, ConfigOptionPercents, ConfigOptionBools, ConfigOptionStrings
|
||||
m_extruder_option_keys = {
|
||||
"extruder_type", "nozzle_diameter", "default_nozzle_volume_type", "min_layer_height", "max_layer_height", "extruder_offset",
|
||||
"extruder_printable_height", "nozzle_volume", "nozzle_type", "nozzle_flush_dataset",
|
||||
"retraction_length", "z_hop", "z_hop_types", "travel_slope", "retract_lift_above", "retract_lift_below", "retract_lift_enforce", "retraction_speed", "deretraction_speed",
|
||||
"retract_before_wipe", "retract_restart_extra", "retraction_minimum_travel", "wipe", "wipe_distance",
|
||||
"retract_when_changing_layer", "retract_length_toolchange", "retract_restart_extra_toolchange", "extruder_colour",
|
||||
@@ -9287,6 +9347,61 @@ void DynamicPrintConfig::update_values_to_printer_extruders_for_multiple_filamen
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Options in printer_options_with_variant_2 are stored as (normal,silent) pairs per printer variant.
|
||||
// Some legacy presets/projects carry a variant list but still store only one pair; normalize to avoid crashes.
|
||||
static void normalize_stride2_floats(ConfigOptionFloats &opt, size_t expected_size)
|
||||
{
|
||||
auto &v = opt.values;
|
||||
if (expected_size == 0) {
|
||||
v.clear();
|
||||
return;
|
||||
}
|
||||
if (v.empty()) {
|
||||
// Fallback: keep behavior predictable instead of crashing. This should be rare.
|
||||
v.resize(expected_size, 0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
const double first = v[0];
|
||||
const double second = (v.size() >= 2) ? v[1] : first;
|
||||
|
||||
// Ensure we have at least one (normal,silent) pair to replicate.
|
||||
if (v.size() < 2) {
|
||||
v.resize(2, first);
|
||||
v[1] = second;
|
||||
}
|
||||
// Keep pair alignment if some legacy preset produced odd length.
|
||||
if (v.size() % 2 != 0)
|
||||
v.push_back(second);
|
||||
|
||||
if (v.size() > expected_size) {
|
||||
v.resize(expected_size);
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t have_variants = v.size() / 2;
|
||||
const size_t want_variants = expected_size / 2;
|
||||
v.resize(expected_size);
|
||||
for (size_t vi = have_variants; vi < want_variants; ++vi) {
|
||||
v[vi * 2] = first;
|
||||
if (vi * 2 + 1 < v.size())
|
||||
v[vi * 2 + 1] = second;
|
||||
}
|
||||
}
|
||||
|
||||
static void log_normalize_legacy_vector_size(const char *fn, const std::string &key, int stride, size_t src_size, size_t dest_size, size_t expected_size,
|
||||
size_t restore_n, int cur_variant_count, int target_variant_count, size_t cur_ids, size_t target_ids,
|
||||
const ConfigOption *opt_src, const ConfigOption *opt_target)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << fn << ": normalizing legacy vector size for key '" << key << "'"
|
||||
<< " stride=" << stride << " src_size=" << src_size << " dest_size=" << dest_size << " expected=" << expected_size
|
||||
<< " restore_index.size=" << restore_n << " cur_variants=" << cur_variant_count << " target_variants=" << target_variant_count
|
||||
<< " cur_ids=" << cur_ids << " target_ids=" << target_ids << " cur_value=" << opt_src->serialize()
|
||||
<< " target_value=" << opt_target->serialize();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfig& new_config, const t_config_option_keys& keys, const std::set<std::string>& different_keys,
|
||||
std::string extruder_id_name, std::string extruder_variant_name, std::set<std::string>& key_set1, std::set<std::string>& key_set2)
|
||||
{
|
||||
@@ -9309,7 +9424,10 @@ void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfi
|
||||
|
||||
variant_index.resize(target_variant_count, -1);
|
||||
if (cur_variant_count == 0) {
|
||||
variant_index[0] = 0;
|
||||
// Defensive: target_variant_count may be 0 if the preset doesn't carry extruder_variant_name.
|
||||
// In that case keep variant_index empty and let the downstream size checks produce a useful error.
|
||||
if (!variant_index.empty())
|
||||
variant_index[0] = 0;
|
||||
}
|
||||
else if ((cur_extruder_ids.size() > 0) && cur_variant_count != cur_extruder_ids.size()){
|
||||
//should not happen
|
||||
@@ -9351,12 +9469,53 @@ void DynamicPrintConfig::update_non_diff_values_to_base_config(DynamicPrintConfi
|
||||
//nothing to do, keep the original one
|
||||
}
|
||||
else {
|
||||
ConfigOptionVectorBase* opt_vec_src = static_cast<ConfigOptionVectorBase*>(opt_src);
|
||||
const ConfigOptionVectorBase* opt_vec_dest = static_cast<const ConfigOptionVectorBase*>(opt_target);
|
||||
int stride = 1;
|
||||
if (key_set2.find(opt) != key_set2.end())
|
||||
stride = 2;
|
||||
opt_vec_src->set_with_restore(opt_vec_dest, variant_index, stride);
|
||||
|
||||
const size_t restore_n = variant_index.size();
|
||||
const size_t expected_size = restore_n * size_t(stride);
|
||||
|
||||
if (stride == 2) {
|
||||
// Options in key_set2 are machine limits stored as (normal,silent) pairs per printer variant.
|
||||
if (opt_src->type() != coFloats || opt_target->type() != coFloats)
|
||||
throw ConfigurationError((boost::format("%1%: key '%2%' is expected to be ConfigOptionFloats for stride=2.") % __FUNCTION__ % opt).str());
|
||||
|
||||
auto *src_f = static_cast<ConfigOptionFloats*>(opt_src);
|
||||
ConfigOptionFloats rhs_tmp(*static_cast<const ConfigOptionFloats*>(opt_target));
|
||||
|
||||
const size_t src_size = src_f->values.size();
|
||||
const size_t dest_size = rhs_tmp.values.size();
|
||||
if (src_size != expected_size || dest_size != expected_size)
|
||||
log_normalize_legacy_vector_size(__FUNCTION__, opt, stride, src_size, dest_size, expected_size, restore_n, cur_variant_count,
|
||||
target_variant_count, cur_extruder_ids.size(), target_extruder_ids.size(), opt_src, opt_target);
|
||||
|
||||
// Normalize src in-place so backup_values indexing is safe, normalize rhs via a temporary copy.
|
||||
normalize_stride2_floats(*src_f, expected_size);
|
||||
normalize_stride2_floats(rhs_tmp, expected_size);
|
||||
src_f->set_with_restore(&rhs_tmp, variant_index, stride);
|
||||
} else {
|
||||
ConfigOptionVectorBase* opt_vec_src = static_cast<ConfigOptionVectorBase*>(opt_src);
|
||||
|
||||
const size_t src_size = opt_vec_src->size();
|
||||
const size_t dest_size = static_cast<const ConfigOptionVectorBase*>(opt_target)->size();
|
||||
if (src_size != expected_size || dest_size != expected_size)
|
||||
log_normalize_legacy_vector_size(__FUNCTION__, opt, stride, src_size, dest_size, expected_size, restore_n, cur_variant_count,
|
||||
target_variant_count, cur_extruder_ids.size(), target_extruder_ids.size(), opt_src, opt_target);
|
||||
|
||||
if (opt_vec_src->size() != expected_size)
|
||||
opt_vec_src->resize(expected_size, opt_target);
|
||||
|
||||
// Normalize rhs via a cloned temporary (rhs itself is const).
|
||||
ConfigOptionUniquePtr rhs_owner(opt_target->clone());
|
||||
ConfigOptionVectorBase *rhs_vec = dynamic_cast<ConfigOptionVectorBase*>(rhs_owner.get());
|
||||
if (rhs_vec == nullptr)
|
||||
throw ConfigurationError((boost::format("%1%: key '%2%' is expected to be a vector option.") % __FUNCTION__ % opt).str());
|
||||
if (rhs_vec->size() != expected_size)
|
||||
rhs_vec->resize(expected_size, opt_target);
|
||||
|
||||
opt_vec_src->set_with_restore(rhs_vec, variant_index, stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9667,13 +9826,13 @@ std::map<std::string, std::string> validate(const FullPrintConfig &cfg, bool und
|
||||
case coFloatOrPercent:
|
||||
{
|
||||
auto *fopt = static_cast<const ConfigOptionFloat*>(opt);
|
||||
out_of_range = fopt->value < optdef->min || fopt->value > optdef->max;
|
||||
out_of_range = !optdef->is_value_valid(fopt->value);
|
||||
break;
|
||||
}
|
||||
case coFloats:
|
||||
case coPercents:
|
||||
for (double v : static_cast<const ConfigOptionVector<double>*>(opt)->values)
|
||||
if (v < optdef->min || v > optdef->max) {
|
||||
if (!optdef->is_value_valid(v)) {
|
||||
out_of_range = true;
|
||||
break;
|
||||
}
|
||||
@@ -9681,12 +9840,12 @@ std::map<std::string, std::string> validate(const FullPrintConfig &cfg, bool und
|
||||
case coInt:
|
||||
{
|
||||
auto *iopt = static_cast<const ConfigOptionInt*>(opt);
|
||||
out_of_range = iopt->value < optdef->min || iopt->value > optdef->max;
|
||||
out_of_range = !optdef->is_value_valid(iopt->value);
|
||||
break;
|
||||
}
|
||||
case coInts:
|
||||
for (int v : static_cast<const ConfigOptionVector<int>*>(opt)->values)
|
||||
if (v < optdef->min || v > optdef->max) {
|
||||
if (!optdef->is_value_valid(v)) {
|
||||
out_of_range = true;
|
||||
break;
|
||||
}
|
||||
@@ -10065,7 +10224,7 @@ CLIMiscConfigDef::CLIMiscConfigDef()
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("downward_settings", coStrings);
|
||||
def->label = L("downward machines settings");
|
||||
def->label = L("Downward machines settings");
|
||||
def->tooltip = L("The machine settings list needs to do downward checking.");
|
||||
def->cli_params = "\"machine1.json;machine2.json;...\"";
|
||||
def->set_default_value(new ConfigOptionStrings());
|
||||
@@ -10411,11 +10570,11 @@ DimensionsConfigDef::DimensionsConfigDef()
|
||||
"'[x, y]' (x and y are floating-point numbers in mm).");
|
||||
|
||||
def = this->add("first_layer_print_min", coFloats);
|
||||
def->label = L("Bottom-left corner of first layer bounding box");
|
||||
def->label = L("Bottom-left corner of the first layer bounding box");
|
||||
def->tooltip = point_tooltip;
|
||||
|
||||
def = this->add("first_layer_print_max", coFloats);
|
||||
def->label = L("Top-right corner of first layer bounding box");
|
||||
def->label = L("Top-right corner of the first layer bounding box");
|
||||
def->tooltip = point_tooltip;
|
||||
|
||||
def = this->add("first_layer_print_size", coFloats);
|
||||
@@ -10443,8 +10602,8 @@ TemperaturesConfigDef::TemperaturesConfigDef()
|
||||
ConfigOptionDef* def;
|
||||
|
||||
new_def("bed_temperature", coInts, "Bed temperature", "Vector of bed temperatures for each extruder/filament.")
|
||||
new_def("bed_temperature_initial_layer", coInts, "Initial layer bed temperature", "Vector of initial layer bed temperatures for each extruder/filament. Provides the same value as first_layer_bed_temperature.")
|
||||
new_def("bed_temperature_initial_layer_single", coInt, "Initial layer bed temperature (initial extruder)", "Initial layer bed temperature for the initial extruder. Same as bed_temperature_initial_layer[initial_extruder]")
|
||||
new_def("bed_temperature_initial_layer", coInts, "First layer bed temperature", "Vector of first layer bed temperatures for each extruder/filament. Provides the same value as first_layer_bed_temperature.")
|
||||
new_def("bed_temperature_initial_layer_single", coInt, "First layer bed temperature (initial extruder)", "First layer bed temperature for the initial extruder. Same as bed_temperature_initial_layer[initial_extruder]")
|
||||
new_def("chamber_temperature", coInts, "Chamber temperature", "Vector of chamber temperatures for each extruder/filament.")
|
||||
new_def("overall_chamber_temperature", coInt, "Overall chamber temperature", "Overall chamber temperature. This value is the maximum chamber temperature of any extruder/filament used.")
|
||||
new_def("first_layer_bed_temperature", coInts, "First layer bed temperature", "Vector of first layer bed temperatures for each extruder/filament. Provides the same value as bed_temperature_initial_layer.")
|
||||
|
||||
@@ -160,7 +160,7 @@ enum SupportMaterialPattern {
|
||||
};
|
||||
|
||||
enum SupportMaterialStyle {
|
||||
smsDefault, smsGrid, smsSnug, smsTreeSlim, smsTreeStrong, smsTreeHybrid, smsTreeOrganic,
|
||||
smsDefault, smsGrid, smsSnug, smsTreeOrganic, smsTreeSlim, smsTreeStrong, smsTreeHybrid,
|
||||
};
|
||||
|
||||
enum LongRectrationLevel
|
||||
@@ -1386,6 +1386,11 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionInts, filament_cooling_moves))
|
||||
((ConfigOptionFloats, filament_cooling_initial_speed))
|
||||
((ConfigOptionFloats, filament_minimal_purge_on_wipe_tower))
|
||||
((ConfigOptionFloats, filament_tower_interface_pre_extrusion_dist))
|
||||
((ConfigOptionFloats, filament_tower_interface_pre_extrusion_length))
|
||||
((ConfigOptionFloats, filament_tower_ironing_area))
|
||||
((ConfigOptionFloats, filament_tower_interface_purge_volume))
|
||||
((ConfigOptionInts, filament_tower_interface_print_temp))
|
||||
((ConfigOptionFloats, filament_cooling_final_speed))
|
||||
((ConfigOptionStrings, filament_ramming_parameters))
|
||||
((ConfigOptionBools, filament_multitool_ramming))
|
||||
@@ -1515,6 +1520,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||
((ConfigOptionPercent, prime_tower_infill_gap))
|
||||
((ConfigOptionBool, prime_tower_skip_points))
|
||||
((ConfigOptionBool, prime_tower_flat_ironing))
|
||||
((ConfigOptionBool, enable_tower_interface_features))
|
||||
((ConfigOptionBool, enable_tower_interface_cooldown_during_tower))
|
||||
((ConfigOptionFloat, wipe_tower_bridging))
|
||||
((ConfigOptionPercent, wipe_tower_extra_flow))
|
||||
((ConfigOptionFloats, flush_volumes_matrix))
|
||||
|
||||
@@ -1576,8 +1576,10 @@ void generate_support_toolpaths(
|
||||
{
|
||||
SupportLayer &support_layer = *support_layers[support_layer_id];
|
||||
LayerCache &layer_cache = layer_caches[support_layer_id];
|
||||
const float support_interface_angle = (support_params.support_style == smsGrid || config.support_interface_pattern == smipRectilinear) ?
|
||||
support_params.interface_angle : support_params.raft_interface_angle(support_layer.interface_id());
|
||||
const float support_interface_angle = (config.support_interface_pattern == smipRectilinearInterlaced) ?
|
||||
support_params.raft_interface_angle(support_layer.interface_id()) :
|
||||
((support_params.support_style == smsGrid || config.support_interface_pattern == smipRectilinear) ?
|
||||
support_params.interface_angle : support_params.raft_interface_angle(support_layer.interface_id()));
|
||||
|
||||
// Find polygons with the same print_z.
|
||||
SupportGeneratorLayerExtruded &bottom_contact_layer = layer_cache.bottom_contact_layer;
|
||||
@@ -1744,8 +1746,10 @@ void generate_support_toolpaths(
|
||||
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
|
||||
sheath = true;
|
||||
no_sort = true;
|
||||
} else if (support_params.support_style == SupportMaterialStyle::smsTreeOrganic) {
|
||||
// if the tree supports are too tall, use double wall to make it stronger
|
||||
} else if (support_params.support_style == SupportMaterialStyle::smsTreeOrganic &&
|
||||
(config.support_base_pattern == smpNone || config.support_base_pattern == smpDefault)) {
|
||||
// Orca: A special case for the hollow Organic supports
|
||||
// Orca: If the tree supports are too tall, use a double wall to make it stronger
|
||||
SupportParameters support_params2 = support_params;
|
||||
if (support_layer.print_z > 100.0)
|
||||
support_params2.tree_branch_diameter_double_wall_area_scaled = 0.1;
|
||||
|
||||
@@ -3549,7 +3549,6 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons
|
||||
if (layer) layer->polygons = intersection(layer->polygons, volumes.m_bed_area);
|
||||
});
|
||||
|
||||
// Don't fill in the tree supports, make them hollow with just a single sheath line.
|
||||
print.set_status(69, _L("Generating support"));
|
||||
generate_support_toolpaths(print_object.support_layers(), print_object.config(), support_params, print_object.slicing_parameters(),
|
||||
raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers);
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "TriangleMeshDeal.hpp"
|
||||
|
||||
#include <igl/read_triangle_mesh.h>
|
||||
#include <igl/loop.h>
|
||||
#include <igl/upsample.h>
|
||||
#include <igl/false_barycentric_subdivision.h>
|
||||
|
||||
namespace Slic3r {
|
||||
TriangleMesh TriangleMeshDeal::smooth_triangle_mesh(const TriangleMesh &mesh, bool &ok)
|
||||
{
|
||||
{
|
||||
using namespace std;
|
||||
using namespace igl;
|
||||
Eigen::MatrixXi OF, F;
|
||||
Eigen::MatrixXd OV, V;
|
||||
auto vertices_count = mesh.its.vertices.size();
|
||||
OV = Eigen::MatrixXd(vertices_count, 3);
|
||||
for (int i = 0; i < vertices_count; i++) {
|
||||
auto v = mesh.its.vertices[i];
|
||||
OV.row(i) << v[0], v[1], v[2];
|
||||
}
|
||||
auto indices_count = mesh.its.indices.size();
|
||||
OF = Eigen::MatrixXi(indices_count, 3);
|
||||
for (int i = 0; i < indices_count; i++) {
|
||||
auto face = mesh.its.indices[i];
|
||||
OF.row(i) << face[0], face[1], face[2];
|
||||
}
|
||||
//igl:: read_triangle_mesh( "E:/Download/libigl-2.6.0/out/build/x64-Debug/_deps/libigl_tutorial_data-src/decimated-knight.off", OV, OF);
|
||||
V = OV;
|
||||
F = OF;
|
||||
|
||||
//igl::upsample(Eigen::MatrixXd(V), Eigen::MatrixXi(F), V, F);
|
||||
ok = true;
|
||||
if (!igl::loop(Eigen::MatrixXd(V), Eigen::MatrixXi(F), V, F)) {
|
||||
ok = false;
|
||||
return TriangleMesh();
|
||||
}
|
||||
//igl::false_barycentric_subdivision(Eigen::MatrixXd(V), Eigen::MatrixXi(F), V, F);
|
||||
indexed_triangle_set its;
|
||||
int vertex_count = V.rows();
|
||||
its.vertices.resize(vertex_count);
|
||||
for (int i = 0; i < vertex_count; i++) {
|
||||
its.vertices[i] = V.row(i).cast<float>();
|
||||
}
|
||||
int indice_count = F.rows();
|
||||
its.indices.resize(indice_count);
|
||||
for (int i = 0; i < indice_count; i++) {
|
||||
auto cur = F.row(i);
|
||||
its.indices[i] = Slic3r::Vec3i32(cur[0], cur[1], cur[2]);
|
||||
}
|
||||
TriangleMesh result_mesh(its);
|
||||
return result_mesh;
|
||||
}
|
||||
}
|
||||
} // namespace Slic3r
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef libslic3r_Timer_hpp_
|
||||
#define libslic3r_Timer_hpp_
|
||||
|
||||
#include "TriangleMesh.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
class TriangleMeshDeal
|
||||
{
|
||||
public:
|
||||
static TriangleMesh smooth_triangle_mesh(const TriangleMesh &mesh,bool& ok);
|
||||
};
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // libslic3r_Timer_hpp_
|
||||
@@ -86,6 +86,11 @@ struct PathVertex
|
||||
// Layer duration in seconds
|
||||
//
|
||||
float layer_duration{ 0.0f };
|
||||
//
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
// Pressure advance value
|
||||
//
|
||||
float pressure_advance{ 0.0f };
|
||||
|
||||
//
|
||||
// Return true if the segment is an extrusion move
|
||||
|
||||
@@ -92,6 +92,8 @@ enum class EViewType : uint8_t
|
||||
LayerTimeLogarithmic,
|
||||
FanSpeed,
|
||||
Temperature,
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
PressureAdvance,
|
||||
Tool,
|
||||
COUNT
|
||||
};
|
||||
|
||||
@@ -169,6 +169,8 @@ public:
|
||||
// EViewType::ActualSpeed
|
||||
// EViewType::FanSpeed
|
||||
// EViewType::Temperature
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
// EViewType::PressureAdvance
|
||||
// EViewType::VolumetricFlowRate
|
||||
// EViewType::ActualVolumetricFlowRate
|
||||
// EViewType::LayerTimeLinear
|
||||
@@ -185,6 +187,8 @@ public:
|
||||
// EViewType::ActualSpeed
|
||||
// EViewType::FanSpeed
|
||||
// EViewType::Temperature
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
// EViewType::PressureAdvance
|
||||
// EViewType::VolumetricFlowRate
|
||||
// EViewType::ActualVolumetricFlowRate
|
||||
// EViewType::LayerTimeLinear
|
||||
|
||||
@@ -1493,6 +1493,11 @@ Color ViewerImpl::get_vertex_color(const PathVertex& v) const
|
||||
{
|
||||
return v.is_travel() ? get_option_color(move_type_to_option(v.type)) : m_temperature_range.get_color_at(v.temperature);
|
||||
}
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
case EViewType::PressureAdvance:
|
||||
{
|
||||
return v.is_travel() ? get_option_color(move_type_to_option(v.type)) : m_pressure_advance_range.get_color_at(v.pressure_advance);
|
||||
}
|
||||
case EViewType::VolumetricFlowRate:
|
||||
{
|
||||
return v.is_travel() ? get_option_color(move_type_to_option(v.type)) : m_volumetric_rate_range.get_color_at(v.volumetric_rate());
|
||||
@@ -1582,6 +1587,8 @@ const ColorRange& ViewerImpl::get_color_range(EViewType type) const
|
||||
case EViewType::ActualSpeed: { return m_actual_speed_range; }
|
||||
case EViewType::FanSpeed: { return m_fan_speed_range; }
|
||||
case EViewType::Temperature: { return m_temperature_range; }
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
case EViewType::PressureAdvance: { return m_pressure_advance_range; }
|
||||
case EViewType::VolumetricFlowRate: { return m_volumetric_rate_range; }
|
||||
case EViewType::ActualVolumetricFlowRate: { return m_actual_volumetric_rate_range; }
|
||||
case EViewType::LayerTimeLinear: { return m_layer_time_range[0]; }
|
||||
@@ -1600,6 +1607,8 @@ void ViewerImpl::set_color_range_palette(EViewType type, const Palette& palette)
|
||||
case EViewType::ActualSpeed: { m_actual_speed_range.set_palette(palette); break; }
|
||||
case EViewType::FanSpeed: { m_fan_speed_range.set_palette(palette); break; }
|
||||
case EViewType::Temperature: { m_temperature_range.set_palette(palette); break; }
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
case EViewType::PressureAdvance: { m_pressure_advance_range.set_palette(palette); break; }
|
||||
case EViewType::VolumetricFlowRate: { m_volumetric_rate_range.set_palette(palette); break; }
|
||||
case EViewType::ActualVolumetricFlowRate: { m_actual_volumetric_rate_range.set_palette(palette); break; }
|
||||
case EViewType::LayerTimeLinear: { m_layer_time_range[0].set_palette(palette); break; }
|
||||
@@ -1637,6 +1646,8 @@ size_t ViewerImpl::get_used_cpu_memory() const
|
||||
ret += m_actual_speed_range.size_in_bytes_cpu();
|
||||
ret += m_fan_speed_range.size_in_bytes_cpu();
|
||||
ret += m_temperature_range.size_in_bytes_cpu();
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
ret += m_pressure_advance_range.size_in_bytes_cpu();
|
||||
ret += m_volumetric_rate_range.size_in_bytes_cpu();
|
||||
ret += m_actual_volumetric_rate_range.size_in_bytes_cpu();
|
||||
for (size_t i = 0; i < COLOR_RANGE_TYPES_COUNT; ++i) {
|
||||
@@ -1787,6 +1798,8 @@ void ViewerImpl::update_color_ranges()
|
||||
m_actual_speed_range.reset();
|
||||
m_fan_speed_range.reset();
|
||||
m_temperature_range.reset();
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
m_pressure_advance_range.reset();
|
||||
m_volumetric_rate_range.reset();
|
||||
m_actual_volumetric_rate_range.reset();
|
||||
m_layer_time_range[0].reset(); // ColorRange::EType::Linear
|
||||
@@ -1803,6 +1816,9 @@ void ViewerImpl::update_color_ranges()
|
||||
}
|
||||
m_fan_speed_range.update(round_to_bin(v.fan_speed));
|
||||
m_temperature_range.update(round_to_bin(v.temperature));
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
if (v.pressure_advance >= 0.0f)
|
||||
m_pressure_advance_range.update(v.pressure_advance);
|
||||
}
|
||||
if ((v.is_travel() && m_settings.options_visibility[size_t(EOptionType::Travels)]) ||
|
||||
(v.is_wipe() && m_settings.options_visibility[size_t(EOptionType::Wipes)]) ||
|
||||
|
||||
@@ -289,6 +289,8 @@ private:
|
||||
ColorRange m_actual_speed_range;
|
||||
ColorRange m_fan_speed_range;
|
||||
ColorRange m_temperature_range;
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
ColorRange m_pressure_advance_range;
|
||||
ColorRange m_volumetric_rate_range;
|
||||
ColorRange m_actual_volumetric_rate_range;
|
||||
std::array<ColorRange, COLOR_RANGE_TYPES_COUNT> m_layer_time_range{
|
||||
|
||||
@@ -736,7 +736,7 @@ else()
|
||||
set(_opengl_link_lib OpenGL::GL)
|
||||
endif()
|
||||
|
||||
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo libvgcode GLEW::GLEW OpenGL::GL hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise)
|
||||
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo libvgcode md4c-html GLEW::GLEW OpenGL::GL hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise)
|
||||
|
||||
|
||||
if (MSVC)
|
||||
|
||||
@@ -222,7 +222,7 @@ void Bed_2D::repaint(const std::vector<Vec2d>& shape)
|
||||
dc.DrawText(origin_label, origin_label_x, origin_label_y);
|
||||
|
||||
// ORCA add grid size value as information for large scale beds
|
||||
auto grid_label = wxString("1x1 Grid: " + std::to_string(step) + " mm");
|
||||
auto grid_label = wxString::Format(_L("1x1 Grid: %d mm"), step);
|
||||
Point draw_bb = to_pixels(Vec2d(
|
||||
std::min(m_pos(0),bb.min(0)),
|
||||
std::min(m_pos(1),bb.min(1))
|
||||
|
||||
@@ -188,6 +188,58 @@ void GLVolume::load_render_colors()
|
||||
RenderColor::colors[RenderCol_Model_Unprintable] = GUI::ImGuiWrapper::to_ImVec4(GLVolume::UNPRINTABLE_COLOR);
|
||||
}
|
||||
|
||||
ColorRGBA GLVolume::brighten_color(const ColorRGBA& color, float multiplier)
|
||||
{
|
||||
// Convert RGB to HSL, increase lightness, convert back
|
||||
|
||||
float r = color.r(), g = color.g(), b = color.b();
|
||||
|
||||
// RGB to HSL conversion
|
||||
float max_val = std::max({r, g, b});
|
||||
float min_val = std::min({r, g, b});
|
||||
float l = (max_val + min_val) / 2.0f;
|
||||
float h = 0.0f, s = 0.0f;
|
||||
|
||||
if (max_val != min_val) {
|
||||
float delta = max_val - min_val;
|
||||
s = l > 0.5f ? delta / (2.0f - max_val - min_val) : delta / (max_val + min_val);
|
||||
|
||||
if (max_val == r)
|
||||
h = (g - b) / delta + (g < b ? 6.0f : 0.0f);
|
||||
else if (max_val == g)
|
||||
h = (b - r) / delta + 2.0f;
|
||||
else
|
||||
h = (r - g) / delta + 4.0f;
|
||||
h /= 6.0f;
|
||||
}
|
||||
|
||||
// Increase lightness by a fixed amount (0.25)
|
||||
// Ensures even saturated colors become visibly brighter
|
||||
l = std::min(l + 0.25f, 1.0f);
|
||||
|
||||
// HSL to RGB conversion
|
||||
auto hue_to_rgb = [](float p, float q, float t) {
|
||||
if (t < 0.0f) t += 1.0f;
|
||||
if (t > 1.0f) t -= 1.0f;
|
||||
if (t < 1.0f / 6.0f) return p + (q - p) * 6.0f * t;
|
||||
if (t < 1.0f / 2.0f) return q;
|
||||
if (t < 2.0f / 3.0f) return p + (q - p) * (2.0f / 3.0f - t) * 6.0f;
|
||||
return p;
|
||||
};
|
||||
|
||||
if (s == 0.0f) {
|
||||
r = g = b = l; // achromatic (gray)
|
||||
} else {
|
||||
float q = l < 0.5f ? l * (1.0f + s) : l + s - l * s;
|
||||
float p = 2.0f * l - q;
|
||||
r = hue_to_rgb(p, q, h + 1.0f / 3.0f);
|
||||
g = hue_to_rgb(p, q, h);
|
||||
b = hue_to_rgb(p, q, h - 1.0f / 3.0f);
|
||||
}
|
||||
|
||||
return ColorRGBA(r, g, b, color.a());
|
||||
}
|
||||
|
||||
GLVolume::GLVolume(float r, float g, float b, float a)
|
||||
: m_sla_shift_z(0.0)
|
||||
, m_sinking_contours(*this)
|
||||
@@ -253,16 +305,28 @@ void GLVolume::set_render_color()
|
||||
set_render_color(outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR);
|
||||
else if (disabled)
|
||||
*/
|
||||
if (disabled)
|
||||
set_render_color(DISABLED_COLOR);
|
||||
// Determine base color first
|
||||
ColorRGBA base_color;
|
||||
|
||||
if (disabled) {
|
||||
base_color = DISABLED_COLOR;
|
||||
}
|
||||
#ifdef ENABLE_OUTSIDE_COLOR
|
||||
else if (is_outside && shader_outside_printer_detection_enabled)
|
||||
set_render_color(OUTSIDE_COLOR);
|
||||
else if (is_outside && shader_outside_printer_detection_enabled) {
|
||||
base_color = OUTSIDE_COLOR;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
//to make black not too hard too see
|
||||
ColorRGBA new_color = adjust_color_for_rendering(color);
|
||||
set_render_color(new_color);
|
||||
// to make black not too hard too see
|
||||
base_color = adjust_color_for_rendering(color);
|
||||
}
|
||||
|
||||
// Apply selection brightening AFTER determining base color
|
||||
if (selected && !disabled) {
|
||||
set_render_color(brighten_color(base_color, 1.25f));
|
||||
}
|
||||
else {
|
||||
set_render_color(base_color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +340,11 @@ void GLVolume::set_render_color()
|
||||
|
||||
//BBS set unprintable color
|
||||
if (!printable) {
|
||||
render_color = UNPRINTABLE_COLOR;
|
||||
if (selected) {
|
||||
render_color = brighten_color(UNPRINTABLE_COLOR, 1.25f);
|
||||
} else {
|
||||
render_color = UNPRINTABLE_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
//BBS set invisible color
|
||||
|
||||
@@ -96,6 +96,7 @@ public:
|
||||
|
||||
static void update_render_colors();
|
||||
static void load_render_colors();
|
||||
static ColorRGBA brighten_color(const ColorRGBA& color, float multiplier = 1.25f);
|
||||
|
||||
static float explosion_ratio;
|
||||
static float last_explosion_ratio;
|
||||
|
||||
@@ -721,7 +721,7 @@ void AMSSettingTypePanel::OnAmsTypeChanged(wxCommandEvent& event)
|
||||
return;
|
||||
}
|
||||
|
||||
MessageDialog dlg(this, _L("AMS type switching needs firmware update, taking about 30s. Switch now ?"), SLIC3R_APP_NAME + _L("Info"), wxOK | wxCANCEL | wxICON_INFORMATION);
|
||||
MessageDialog dlg(this, _L("AMS type switching needs firmware update, taking about 30s. Switch now?"), SLIC3R_APP_NAME + _L("Info"), wxOK | wxCANCEL | wxICON_INFORMATION);
|
||||
dlg.SetButtonLabel(wxID_OK, _L("Confirm"));
|
||||
int rtn = dlg.ShowModal();
|
||||
if (rtn != wxID_OK) {
|
||||
|
||||
@@ -2202,7 +2202,7 @@ void AmsReplaceMaterialDialog::create()
|
||||
label_txt->SetMaxSize(wxSize(FromDIP(380), -1));
|
||||
label_txt->Wrap(FromDIP(380));
|
||||
|
||||
identical_filament = new Label(this, _L("Identical filament: same brand, type and color"));
|
||||
identical_filament = new Label(this, _L("Identical filament: same brand, type and color."));
|
||||
identical_filament->SetFont(Label::Body_13);
|
||||
identical_filament->SetForegroundColour(StateColor::darkModeColorFor(wxColour("#009688")));
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#ifdef __WXGTK__
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
#define TOPBAR_ICON_SIZE 18
|
||||
#define TOPBAR_TITLE_WIDTH 300
|
||||
|
||||
@@ -532,6 +536,18 @@ void BBLTopbar::OnIconize(wxAuiToolBarEvent& event)
|
||||
|
||||
void BBLTopbar::OnFullScreen(wxAuiToolBarEvent& event)
|
||||
{
|
||||
#ifdef __WXGTK__
|
||||
GtkWindow* gtk_window = GTK_WINDOW(m_frame->m_widget);
|
||||
if (gtk_window_is_maximized(gtk_window)) {
|
||||
gtk_window_unmaximize(gtk_window);
|
||||
}
|
||||
else {
|
||||
m_normalRect = m_frame->GetRect();
|
||||
gtk_window_maximize(gtk_window);
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (m_frame->IsMaximized()) {
|
||||
m_frame->Restore();
|
||||
}
|
||||
@@ -621,17 +637,27 @@ void BBLTopbar::OnMouseLeftDown(wxMouseEvent& event)
|
||||
wxPoint frame_pos = m_frame->GetScreenPosition();
|
||||
m_delta = mouse_pos - frame_pos;
|
||||
|
||||
if (FindToolByCurrentPosition() == NULL
|
||||
if (FindToolByCurrentPosition() == NULL
|
||||
|| this->FindToolByCurrentPosition() == m_title_item)
|
||||
{
|
||||
CaptureMouse();
|
||||
#ifdef __WXMSW__
|
||||
CaptureMouse();
|
||||
ReleaseMouse();
|
||||
::PostMessage((HWND) m_frame->GetHandle(), WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(mouse_pos.x, mouse_pos.y));
|
||||
return;
|
||||
#endif // __WXMSW__
|
||||
#elif defined(__WXGTK__)
|
||||
// Use WM-integrated drag for smoother window movement on Linux.
|
||||
gtk_window_begin_move_drag(
|
||||
GTK_WINDOW(m_frame->m_widget),
|
||||
1, // left mouse button
|
||||
mouse_pos.x, mouse_pos.y,
|
||||
gtk_get_current_event_time());
|
||||
return;
|
||||
#else
|
||||
CaptureMouse();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
@@ -303,7 +303,7 @@ bool CalibrationWizard::save_preset_with_index(const std::string &old_preset_nam
|
||||
PresetCollection *filament_presets = &wxGetApp().preset_bundle->filaments;
|
||||
Preset *preset = filament_presets->find_preset(old_preset_name);
|
||||
if (!preset) {
|
||||
message = wxString::Format(_L("The selected preset: %s is not found."), old_preset_name);
|
||||
message = wxString::Format(_L("The selected preset: %s was not found."), old_preset_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -764,7 +764,7 @@ void CalibrationPresetPage::create_selection_panel(wxWindow* parent)
|
||||
m_filament_from_panel = new wxPanel(parent);
|
||||
m_filament_from_panel->Hide();
|
||||
auto filament_from_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
auto filament_from_text = new Label(m_filament_from_panel, _L("filament position"));
|
||||
auto filament_from_text = new Label(m_filament_from_panel, _L("Filament position"));
|
||||
filament_from_text->SetFont(Label::Head_14);
|
||||
filament_from_sizer->Add(filament_from_text, 0);
|
||||
|
||||
|
||||
@@ -816,9 +816,12 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
|
||||
toggle_line("preheat_steps", have_ooze_prevention && (preheat_steps > 0));
|
||||
|
||||
bool have_prime_tower = config->opt_bool("enable_prime_tower");
|
||||
for (auto el : {"prime_tower_width", "prime_tower_brim_width", "prime_tower_skip_points", "wipe_tower_wall_type", "prime_tower_infill_gap","prime_tower_enable_framework"})
|
||||
for (auto el : {"prime_tower_width", "prime_tower_brim_width", "prime_tower_skip_points", "wipe_tower_wall_type", "prime_tower_infill_gap","prime_tower_enable_framework", "enable_tower_interface_features"})
|
||||
toggle_line(el, have_prime_tower);
|
||||
|
||||
toggle_line("enable_tower_interface_cooldown_during_tower",
|
||||
have_prime_tower && config->opt_bool("enable_tower_interface_features"));
|
||||
|
||||
for (auto el : {"wall_filament", "sparse_infill_filament", "solid_infill_filament", "wipe_tower_filament"})
|
||||
toggle_line(el, !bSEMM);
|
||||
|
||||
|
||||
@@ -3724,7 +3724,7 @@ wxBoxSizer *ExportConfigsDialog::create_export_config_item(wxWindow *parent)
|
||||
|
||||
radioBoxSizer->Add(create_radio_item(m_exprot_type.preset_bundle, parent, wxEmptyString, m_export_type_btns), 0, wxEXPAND | wxALL, 0);
|
||||
radioBoxSizer->Add(0, 0, 0, wxTOP, FromDIP(6));
|
||||
wxStaticText *static_export_printer_preset_bundle_text = new wxStaticText(parent, wxID_ANY, _L("Printer and all the filament&&process presets that belongs to the printer.\n"
|
||||
wxStaticText *static_export_printer_preset_bundle_text = new wxStaticText(parent, wxID_ANY, _L("Printer and all the filament and process presets that belongs to the printer.\n"
|
||||
"Can be shared with others."), wxDefaultPosition, wxDefaultSize);
|
||||
static_export_printer_preset_bundle_text->SetFont(Label::Body_12);
|
||||
static_export_printer_preset_bundle_text->SetForegroundColour(wxColour("#6B6B6B"));
|
||||
|
||||
@@ -150,7 +150,7 @@ wxString Slic3r::get_stage_string(int stage)
|
||||
case 39:
|
||||
return _L("Nozzle offset calibration");
|
||||
case 40:
|
||||
return _L("high temperature auto bed leveling");
|
||||
return _L("High temperature auto bed leveling");
|
||||
case 41:
|
||||
return _L("Auto Check: Quick Release Lever");
|
||||
case 42:
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# GUI/DeviceTab
|
||||
# usage -- GUI about device tab for BambuStudio
|
||||
# date -- 2025.01.01
|
||||
# status -- Building
|
||||
|
||||
list(APPEND SLIC3R_GUI_SOURCES
|
||||
GUI/DeviceTab/uiAmsHumidityPopup.h
|
||||
|
||||
@@ -31,16 +31,14 @@
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
||||
|
||||
DownloadProgressDialog::DownloadProgressDialog(wxString title)
|
||||
: DPIDialog(static_cast<wxWindow *>(wxGetApp().mainframe), wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
|
||||
{
|
||||
wxString download_failed_url = wxT("https://wiki.bambulab.com/en/software/bambu-studio/failed-to-get-network-plugin");
|
||||
wxString install_failed_url = wxT("https://wiki.bambulab.com/en/software/bambu-studio/failed-to-get-network-plugin");
|
||||
|
||||
wxString download_failed_msg = _L("Failed to download the plug-in. Please check your firewall settings and vpn software, check and retry.");
|
||||
wxString install_failed_msg = _L("Failed to install the plug-in. Please check whether it is blocked or deleted by anti-virus software.");
|
||||
wxString download_failed_msg = _L("Failed to download the plug-in. Please check your firewall settings and VPN software and retry.");
|
||||
wxString install_failed_msg = _L("Failed to install the plug-in. The plug-in file may be in use. Please restart OrcaSlicer and try again. Also check whether it is blocked or deleted by anti-virus software.");
|
||||
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
wxBoxSizer *m_sizer_main = new wxBoxSizer(wxVERTICAL);
|
||||
@@ -76,7 +74,7 @@ DownloadProgressDialog::DownloadProgressDialog(wxString title)
|
||||
sizer_download_failed->Add(m_statictext_download_failed, 0, wxALIGN_CENTER | wxALL, 5);
|
||||
|
||||
// ORCA standardized HyperLink
|
||||
auto m_download_hyperlink = new HyperLink(m_panel_download_failed, _L("click here to see more info"), download_failed_url);
|
||||
auto m_download_hyperlink = new HyperLink(m_panel_download_failed, _L("Click here to see more info"), download_failed_url);
|
||||
sizer_download_failed->Add(m_download_hyperlink, 0, wxALIGN_CENTER | wxALL, 5);
|
||||
|
||||
|
||||
@@ -98,7 +96,7 @@ DownloadProgressDialog::DownloadProgressDialog(wxString title)
|
||||
sizer_install_failed->Add(m_statictext_install_failed, 0, wxALIGN_CENTER | wxALL, 5);
|
||||
|
||||
// ORCA standardized HyperLink
|
||||
auto m_install_hyperlink = new HyperLink(m_panel_install_failed, _L("click here to see more info"), install_failed_url);
|
||||
auto m_install_hyperlink = new HyperLink(m_panel_install_failed, _L("Click here to see more info"), install_failed_url);
|
||||
sizer_install_failed->Add(m_install_hyperlink, 0, wxALIGN_CENTER | wxALL, 5);
|
||||
|
||||
|
||||
@@ -215,7 +213,7 @@ void DownloadProgressDialog::on_finish()
|
||||
}
|
||||
|
||||
MessageDialog dlg(nullptr,
|
||||
_L("The network plugin was installed but could not be loaded. Please restart the application."),
|
||||
_L("The network plug-in was installed but could not be loaded. Please restart the application."),
|
||||
_L("Restart Required"), wxOK | wxICON_INFORMATION);
|
||||
dlg.ShowModal();
|
||||
}
|
||||
|
||||
+87
-29
@@ -101,6 +101,45 @@ ThumbnailErrors validate_thumbnails_string(wxString& str, const wxString& def_ex
|
||||
return errors;
|
||||
}
|
||||
|
||||
wxString get_formatted_tooltip_text(const ConfigOptionDef& opt, const t_config_option_key& id)
|
||||
{
|
||||
wxString tooltip = _(opt.tooltip);
|
||||
|
||||
if (tooltip.length() > 0) {
|
||||
edit_tooltip(tooltip);
|
||||
|
||||
std::string opt_id = id;
|
||||
auto hash_pos = opt_id.find("#");
|
||||
if (hash_pos != std::string::npos) {
|
||||
opt_id.replace(hash_pos, 1,"[");
|
||||
opt_id += "]";
|
||||
}
|
||||
|
||||
tooltip += "\n\n" + _(L("parameter name")) + ": " + opt_id;
|
||||
|
||||
if (opt.type == coFloat || opt.type == coInt) {
|
||||
double default_value = 0.;
|
||||
|
||||
if (opt.type == coFloat)
|
||||
default_value = opt.get_default_value<ConfigOptionFloat>()->value;
|
||||
else if (opt.type == coInt)
|
||||
default_value = opt.get_default_value<ConfigOptionInt>()->value;
|
||||
|
||||
tooltip += "\n\n" + _(L("Default")) + ": " + _(double_to_string(default_value));
|
||||
|
||||
if (opt.min > -FLT_MAX && opt.max < FLT_MAX) {
|
||||
tooltip += "\n" + _(L("Range")) + ": [" +
|
||||
_(double_to_string(opt.min)) + ", " +
|
||||
_(double_to_string(opt.max)) + "]";
|
||||
}
|
||||
}
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
Field::~Field()
|
||||
{
|
||||
if (m_on_kill_focus)
|
||||
@@ -223,23 +262,9 @@ void Field::toggle(bool en) { en && !m_opt.readonly ? enable() : disable(); }
|
||||
|
||||
wxString Field::get_tooltip_text(const wxString &default_string)
|
||||
{
|
||||
wxString tooltip_text("");
|
||||
#ifdef NDEBUG
|
||||
wxString tooltip = _(m_opt.tooltip);
|
||||
::edit_tooltip(tooltip);
|
||||
wxString tooltip_text = get_formatted_tooltip_text(m_opt, m_opt_id);
|
||||
|
||||
std::string opt_id = m_opt_id;
|
||||
auto hash_pos = opt_id.find("#");
|
||||
if (hash_pos != std::string::npos) {
|
||||
opt_id.replace(hash_pos, 1,"[");
|
||||
opt_id += "]";
|
||||
}
|
||||
|
||||
if (tooltip.length() > 0)
|
||||
tooltip_text = tooltip + "\n" +
|
||||
_(L("parameter name")) + "\t: " + opt_id;
|
||||
#endif
|
||||
return tooltip_text;
|
||||
return tooltip_text.length() > 0 ? tooltip_text : default_string;
|
||||
}
|
||||
|
||||
bool Field::is_matched(const std::string& string, const std::string& pattern)
|
||||
@@ -251,9 +276,15 @@ bool Field::is_matched(const std::string& string, const std::string& pattern)
|
||||
void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true*/)
|
||||
{
|
||||
switch (m_opt.type) {
|
||||
case coInts:
|
||||
case coInt: {
|
||||
long val = 0;
|
||||
if (!str.ToLong(&val)) {
|
||||
|
||||
bool is_na_value = m_opt.nullable && str == m_na_value;
|
||||
|
||||
if (is_na_value)
|
||||
val = ConfigOptionIntsNullable::nil_value();
|
||||
else if (!str.ToLong(&val)) {
|
||||
if (!check_value) {
|
||||
m_value.clear();
|
||||
break;
|
||||
@@ -261,6 +292,27 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
||||
show_error(m_parent, _(L("Invalid numeric.")));
|
||||
set_value(int(val), true);
|
||||
}
|
||||
|
||||
if (!m_opt.is_value_valid(double(val))) {
|
||||
if (!check_value) {
|
||||
m_value.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_na_value) {
|
||||
// Orca: no need to check ranges for the nil value
|
||||
show_error(m_parent, _L("Value is out of range."));
|
||||
|
||||
int min = static_cast<int>(m_opt.min);
|
||||
int max = static_cast<int>(m_opt.max);
|
||||
|
||||
if (min > val) val = min;
|
||||
if (val > max) val = max;
|
||||
|
||||
set_value(int(val), true);
|
||||
}
|
||||
}
|
||||
|
||||
m_value = int(val);
|
||||
break;
|
||||
}
|
||||
@@ -309,7 +361,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
||||
show_error(m_parent, _(L("Invalid numeric.")));
|
||||
set_value(double_to_string(val), true);
|
||||
}
|
||||
if (m_opt.min > val || val > m_opt.max)
|
||||
if (!m_opt.is_value_valid(val))
|
||||
{
|
||||
if (!check_value) {
|
||||
m_value.clear();
|
||||
@@ -347,7 +399,8 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (!is_na_value) {
|
||||
// Orca: no need to check ranges for the nil value
|
||||
show_error(m_parent, _L("Value is out of range."));
|
||||
if (m_opt.min > val) val = m_opt.min;
|
||||
if (val > m_opt.max) val = m_opt.max;
|
||||
@@ -830,13 +883,18 @@ bool TextCtrl::value_was_changed()
|
||||
case coInt:
|
||||
return boost::any_cast<int>(m_value) != boost::any_cast<int>(val);
|
||||
case coPercent:
|
||||
case coPercents:
|
||||
case coPercents: {
|
||||
if (m_opt.nullable && std::isnan(boost::any_cast<double>(m_value)) &&
|
||||
std::isnan(boost::any_cast<double>(val)))
|
||||
return false;
|
||||
return boost::any_cast<double>(m_value) != boost::any_cast<double>(val);
|
||||
}
|
||||
case coFloats:
|
||||
case coFloat: {
|
||||
if (m_opt.nullable && std::isnan(boost::any_cast<double>(m_value)) &&
|
||||
std::isnan(boost::any_cast<double>(val)))
|
||||
return false;
|
||||
return boost::any_cast<double>(m_value) != boost::any_cast<double>(val);
|
||||
return !is_approx(boost::any_cast<double>(m_value), boost::any_cast<double>(val));
|
||||
}
|
||||
case coString:
|
||||
case coStrings:
|
||||
@@ -1088,8 +1146,8 @@ void SpinCtrl::BUILD() {
|
||||
break;
|
||||
}
|
||||
|
||||
const int min_val = m_opt.min == INT_MIN ? 0 : m_opt.min;
|
||||
const int max_val = m_opt.max < 2147483647 ? m_opt.max : 2147483647;
|
||||
const int min_val = m_opt.min == -FLT_MAX ? 0 : (int)m_opt.min;
|
||||
const int max_val = m_opt.max < FLT_MAX ? (int)m_opt.max : INT_MAX;
|
||||
|
||||
static Builder<SpinInput> builder;
|
||||
auto temp = builder.build(m_parent, "", "", wxDefaultPosition, size,
|
||||
@@ -1145,7 +1203,7 @@ void SpinCtrl::BUILD() {
|
||||
if (!parsed || value < INT_MIN || value > INT_MAX)
|
||||
tmp_value = UNDEF_VALUE;
|
||||
else {
|
||||
tmp_value = std::min(std::max((int)value, m_opt.min), m_opt.max);
|
||||
tmp_value = std::min(std::max((int)value, temp->GetMin()), temp->GetMax());
|
||||
#ifdef __WXOSX__
|
||||
#ifdef UNDEFINED__WXOSX__ // BBS
|
||||
// Forcibly set the input value for SpinControl, since the value
|
||||
@@ -1198,7 +1256,7 @@ void SpinCtrl::set_value(const boost::any& value, bool change_event) {
|
||||
m_disable_change_event = !change_event;
|
||||
m_value = value;
|
||||
if (value.empty()) { // BBS: null value
|
||||
dynamic_cast<SpinInput*>(window)->SetValue(m_opt.min);
|
||||
dynamic_cast<SpinInput*>(window)->SetValue(dynamic_cast<SpinInput*>(window)->GetMin());
|
||||
dynamic_cast<SpinInput*>(window)->GetTextCtrl()->SetValue("");
|
||||
}
|
||||
else {
|
||||
@@ -2139,8 +2197,8 @@ boost::any& PointCtrl::get_value()
|
||||
show_error(m_parent, _L("Invalid numeric."));
|
||||
}
|
||||
else
|
||||
if (m_opt.min > x || x > m_opt.max ||
|
||||
m_opt.min > y || y > m_opt.max)
|
||||
if (!m_opt.is_value_valid(x) ||
|
||||
!m_opt.is_value_valid(y))
|
||||
{
|
||||
if (m_opt.min > x) x = m_opt.min;
|
||||
if (x > m_opt.max) x = m_opt.max;
|
||||
@@ -2199,8 +2257,8 @@ void SliderCtrl::BUILD()
|
||||
auto temp = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
auto def_val = m_opt.get_default_value<ConfigOptionInt>()->value;
|
||||
auto min = m_opt.min == INT_MIN ? 0 : m_opt.min;
|
||||
auto max = m_opt.max == INT_MAX ? 100 : m_opt.max;
|
||||
auto min = m_opt.min == -FLT_MAX ? 0 : (int)m_opt.min;
|
||||
auto max = m_opt.max == FLT_MAX ? 100 : INT_MAX;
|
||||
|
||||
m_slider = new wxSlider(m_parent, wxID_ANY, def_val * m_scale,
|
||||
min * m_scale, max * m_scale,
|
||||
|
||||
@@ -43,6 +43,7 @@ using t_back_to_init = std::function<void(const std::string&)>;
|
||||
wxString double_to_string(double const value, const int max_precision = 4);
|
||||
wxString get_thumbnail_string(const Vec2d& value);
|
||||
wxString get_thumbnails_string(const std::vector<Vec2d>& values);
|
||||
wxString get_formatted_tooltip_text(const ConfigOptionDef& opt, const t_config_option_key& id);
|
||||
|
||||
class UndoValueUIManager
|
||||
{
|
||||
|
||||
@@ -207,6 +207,17 @@ FilamentMapDialog::FilamentMapDialog(wxWindow *parent,
|
||||
|
||||
m_ok_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_ok, this);
|
||||
m_cancel_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_cancle, this);
|
||||
SetEscapeId(wxID_CANCEL);
|
||||
Bind(wxEVT_CHAR_HOOK, [this](wxKeyEvent& e) {
|
||||
if (e.GetKeyCode() == WXK_ESCAPE) {
|
||||
if (IsModal())
|
||||
EndModal(wxID_CANCEL);
|
||||
else
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
e.Skip();
|
||||
});
|
||||
|
||||
m_auto_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_switch_mode, this);
|
||||
m_manual_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_switch_mode, this);
|
||||
|
||||
@@ -91,6 +91,9 @@ static std::string get_view_type_string(libvgcode::EViewType view_type)
|
||||
return _u8L("Layer Time");
|
||||
else if (view_type == libvgcode::EViewType::LayerTimeLogarithmic)
|
||||
return _u8L("Layer Time (log)");
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
else if (view_type == libvgcode::EViewType::PressureAdvance)
|
||||
return _u8L("Pressure Advance");
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -397,6 +400,11 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode
|
||||
sprintf(buff, ("%.0f " + _u8L("°C")).c_str(), vertex.temperature);
|
||||
ImGuiWrapper::text(std::string(buff));
|
||||
});
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
append_table_row(_u8L("Pressure Advance"), [&vertex, &buff]() {
|
||||
sprintf(buff, "%.4f", vertex.pressure_advance);
|
||||
ImGuiWrapper::text(std::string(buff));
|
||||
});
|
||||
append_table_row(_u8L("Time"), [viewer, &vertex, &buff, vertex_id]() {
|
||||
const float estimated_time = viewer->get_estimated_time_at(vertex_id);
|
||||
sprintf(buff, "%s (%.3fs)", get_time_dhms(estimated_time).c_str(), vertex.times[static_cast<size_t>(viewer->get_time_mode())]);
|
||||
@@ -607,6 +615,11 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode
|
||||
sprintf(buf, "%s %s%.1f", buf, _u8L("Actual Speed: ").c_str(), vertex.actual_feedrate);
|
||||
break;
|
||||
}
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
case libvgcode::EViewType::PressureAdvance: {
|
||||
sprintf(buf, "%s %s%.4f", buf, _u8L("PA: ").c_str(), vertex.pressure_advance);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
@@ -1024,6 +1037,8 @@ void GCodeViewer::update_by_mode(ConfigOptionMode mode)
|
||||
view_type_items.push_back(libvgcode::EViewType::LayerTimeLogarithmic);
|
||||
view_type_items.push_back(libvgcode::EViewType::FanSpeed);
|
||||
view_type_items.push_back(libvgcode::EViewType::Temperature);
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
view_type_items.push_back(libvgcode::EViewType::PressureAdvance);
|
||||
//if (mode == ConfigOptionMode::comDevelop) {
|
||||
// view_type_items.push_back(EViewType::Tool);
|
||||
//}
|
||||
@@ -2250,6 +2265,8 @@ void GCodeViewer::render_toolpaths()
|
||||
add_range_property_row("speed range", m_viewer.get_color_range(libvgcode::EViewType::Speed).get_range());
|
||||
add_range_property_row("fan speed range", m_viewer.get_color_range(libvgcode::EViewType::FanSpeed).get_range());
|
||||
add_range_property_row("temperature range", m_viewer.get_color_range(libvgcode::EViewType::Temperature).get_range());
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
add_range_property_row("pressure advance range", m_viewer.get_color_range(libvgcode::EViewType::PressureAdvance).get_range());
|
||||
add_range_property_row("volumetric rate range", m_viewer.get_color_range(libvgcode::EViewType::VolumetricFlowRate).get_range());
|
||||
add_range_property_row("layer time linear range", m_viewer.get_color_range(libvgcode::EViewType::LayerTimeLinear).get_range());
|
||||
add_range_property_row("layer time logarithmic range", m_viewer.get_color_range(libvgcode::EViewType::LayerTimeLogarithmic).get_range());
|
||||
@@ -3498,6 +3515,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
}
|
||||
case libvgcode::EViewType::FanSpeed: { imgui.title(_u8L("Fan Speed (%)")); break; }
|
||||
case libvgcode::EViewType::Temperature: { imgui.title(_u8L("Temperature (°C)")); break; }
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
case libvgcode::EViewType::PressureAdvance:{ imgui.title(_u8L("Pressure Advance")); break; }
|
||||
case libvgcode::EViewType::VolumetricFlowRate:
|
||||
{ imgui.title(_u8L("Volumetric flow rate (mm³/s)")); break; }
|
||||
case libvgcode::EViewType::ActualVolumetricFlowRate:
|
||||
@@ -3647,7 +3666,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
|
||||
const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
|
||||
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() {
|
||||
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() {
|
||||
m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels);
|
||||
// refresh(*m_gcode_result, wxGetApp().plater()->get_extruder_colors_from_plater_config(m_gcode_result));
|
||||
update_moves_slider();
|
||||
@@ -3664,7 +3683,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} });
|
||||
const bool travel_visible = m_viewer.is_option_visible(libvgcode::EOptionType::Travels);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
|
||||
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() {
|
||||
append_item(EItemType::None, libvgcode::convert(m_viewer.get_option_color(libvgcode::EOptionType::Travels)), { {_u8L("Travel"), offsets[0] }}, true, predictable_icon_pos/*ORCA checkbox_pos*/, travel_visible, [this, travel_visible]() {
|
||||
m_viewer.toggle_option_visibility(libvgcode::EOptionType::Travels);
|
||||
// refresh(*m_gcode_result, wxGetApp().plater()->get_extruder_colors_from_plater_config(m_gcode_result));
|
||||
update_moves_slider();
|
||||
@@ -3674,6 +3693,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
|
||||
}
|
||||
case libvgcode::EViewType::FanSpeed: { append_range(m_viewer.get_color_range(libvgcode::EViewType::FanSpeed), 0); break; }
|
||||
case libvgcode::EViewType::Temperature: { append_range(m_viewer.get_color_range(libvgcode::EViewType::Temperature), 0); break; }
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
case libvgcode::EViewType::PressureAdvance: { append_range(m_viewer.get_color_range(libvgcode::EViewType::PressureAdvance), 3); break; }
|
||||
case libvgcode::EViewType::LayerTimeLinear: { append_range(m_viewer.get_color_range(libvgcode::EViewType::LayerTimeLinear), true); break; }
|
||||
case libvgcode::EViewType::LayerTimeLogarithmic: { append_range(m_viewer.get_color_range(libvgcode::EViewType::LayerTimeLogarithmic), true); break; }
|
||||
case libvgcode::EViewType::VolumetricFlowRate: { append_range(m_viewer.get_color_range(libvgcode::EViewType::VolumetricFlowRate), 2); break; }
|
||||
|
||||
@@ -1216,12 +1216,12 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
|
||||
m_selection.set_volumes(&m_volumes.volumes);
|
||||
|
||||
m_assembly_view_desc["object_selection_caption"] = _L("Left mouse button");
|
||||
m_assembly_view_desc["object_selection"] = _L("object selection");
|
||||
m_assembly_view_desc["object_selection"] = _L("Object selection");
|
||||
// FIXME: maybe should be using GUI::shortkey_alt_prefix() or equivalent?
|
||||
m_assembly_view_desc["part_selection_caption"] = _L("Alt+") + _L("Left mouse button");
|
||||
m_assembly_view_desc["part_selection"] = _L("part selection");
|
||||
m_assembly_view_desc["part_selection"] = _L("Part selection");
|
||||
m_assembly_view_desc["number_key_caption"] = "1~16 " + _L("number keys");
|
||||
m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects");
|
||||
m_assembly_view_desc["number_key"] = _L("Number keys can quickly change the color of objects");
|
||||
}
|
||||
|
||||
GLCanvas3D::~GLCanvas3D()
|
||||
@@ -1254,7 +1254,7 @@ bool GLCanvas3D::init()
|
||||
// Controls the display of object names directly over the object
|
||||
m_labels.show(wxGetApp().app_config->get_bool("show_labels"));
|
||||
// Controls the color coding of overhang surfaces
|
||||
m_slope.globalUse(wxGetApp().app_config->get_bool("show_labels"));
|
||||
m_slope.globalUse(wxGetApp().app_config->get_bool("show_overhang"));
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) <<__FUNCTION__<< " enter";
|
||||
glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
@@ -3272,8 +3272,12 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
||||
#else /* __APPLE__ */
|
||||
case WXK_CONTROL_A:
|
||||
#endif /* __APPLE__ */
|
||||
if (!is_in_painting_mode && !m_layers_editing.is_enabled())
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_SELECT_ALL));
|
||||
if (!is_in_painting_mode && !m_layers_editing.is_enabled()) {
|
||||
if (evt.ShiftDown())
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_SELECT_ALL));
|
||||
else
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_SELECT_CURR_PLATE_ALL));
|
||||
}
|
||||
break;
|
||||
#ifdef __APPLE__
|
||||
case 'c':
|
||||
@@ -8541,9 +8545,11 @@ void GLCanvas3D::_render_canvas_toolbar()
|
||||
zoom_to_selection();
|
||||
}
|
||||
} else if (ImGui::IsItemHovered()) {
|
||||
auto tooltip = _L("Fit camera to scene or selected object.");
|
||||
auto width = ImGui::CalcTextSize(tooltip.c_str()).x + imgui.scaled(2.0f);
|
||||
imgui.tooltip(tooltip, width);
|
||||
auto tooltip_str_wx = _L("Fit camera to scene or selected object.");
|
||||
std::string tooltip_str = tooltip_str_wx.ToUTF8().data();
|
||||
|
||||
float width = ImGui::CalcTextSize(tooltip_str.c_str()).x + imgui.scaled(2.0f);
|
||||
imgui.tooltip(tooltip_str, width);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8582,7 +8588,7 @@ void GLCanvas3D::_render_canvas_toolbar()
|
||||
ImGui::TextColored(enable ? ImVec4(1,1,1,1) : ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled), "%s", into_u8(condition ? ImGui::VisibleIcon : ImGui::HiddenIcon).c_str());
|
||||
};
|
||||
|
||||
create_menu_item( "3D Navigator",
|
||||
create_menu_item( _utf8(L("3D Navigator")),
|
||||
m_canvas_type != ECanvasType::CanvasAssembleView, // not work on assembly
|
||||
wxGetApp().show_3d_navigator(),
|
||||
[this]{
|
||||
@@ -8591,7 +8597,7 @@ void GLCanvas3D::_render_canvas_toolbar()
|
||||
}
|
||||
);
|
||||
|
||||
create_menu_item( "Zoom button",
|
||||
create_menu_item( _utf8(L("Zoom button")),
|
||||
true, // work on all
|
||||
wxGetApp().show_canvas_zoom_button(),
|
||||
[this]{
|
||||
@@ -8602,13 +8608,13 @@ void GLCanvas3D::_render_canvas_toolbar()
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
create_menu_item( "Overhangs",
|
||||
create_menu_item( _utf8(L("Overhangs")),
|
||||
m_canvas_type == ECanvasType::CanvasView3D, // work only on prepare
|
||||
p->is_view3D_overhang_shown(),
|
||||
[this, p]{p->show_view3D_overhang(!p->is_view3D_overhang_shown());}
|
||||
);
|
||||
|
||||
create_menu_item( "Outline",
|
||||
create_menu_item( _utf8(L("Outline")),
|
||||
m_canvas_type != ECanvasType::CanvasPreview, // not work on preview
|
||||
wxGetApp().show_outline(),
|
||||
[this]{wxGetApp().toggle_show_outline();}
|
||||
@@ -8616,7 +8622,7 @@ void GLCanvas3D::_render_canvas_toolbar()
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
create_menu_item( "Perspective",
|
||||
create_menu_item( _utf8(L("Perspective")),
|
||||
true, // work on all
|
||||
cfg->get_bool("use_perspective_camera"),
|
||||
[this, &cfg]{
|
||||
@@ -8627,15 +8633,21 @@ void GLCanvas3D::_render_canvas_toolbar()
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
create_menu_item( "Axes",
|
||||
create_menu_item( _utf8(L("Axes")),
|
||||
m_canvas_type != ECanvasType::CanvasAssembleView, // not work on assembly
|
||||
m_show_world_axes,
|
||||
[this]{toggle_world_axes_visibility(false);}
|
||||
);
|
||||
|
||||
// will add an option for gridlines in here
|
||||
create_menu_item( _utf8(L("Gridlines")),
|
||||
m_canvas_type != ECanvasType::CanvasAssembleView, // not work on assembly
|
||||
wxGetApp().show_plate_gridlines(),
|
||||
[this]{wxGetApp().toggle_show_plate_gridlines();}
|
||||
);
|
||||
|
||||
create_menu_item( "Labels",
|
||||
ImGui::Separator();
|
||||
|
||||
create_menu_item( _utf8(L("Labels")),
|
||||
m_canvas_type == ECanvasType::CanvasView3D, // work only on prepare
|
||||
p->are_view3D_labels_shown(),
|
||||
[this, p]{p->show_view3D_labels(!p->are_view3D_labels_shown());}
|
||||
@@ -8922,7 +8934,7 @@ void GLCanvas3D::_render_assemble_control()
|
||||
caption_max = std::max(caption_max, imgui->calc_text_size(m_assembly_view_desc.at(t + "_caption")).x);
|
||||
}
|
||||
const ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
const float text_y =imgui->calc_text_size(_L("part selection")).y;
|
||||
const float text_y = imgui->calc_text_size(_L("Part selection")).y;
|
||||
float get_cur_x = pos.x;
|
||||
float get_cur_y = pos.y - ImGui::GetFrameHeight() - 4 * text_y;
|
||||
tip_icon_size =_show_assembly_tooltip_information(caption_max, get_cur_x, get_cur_y);
|
||||
@@ -9643,7 +9655,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
||||
warning += std::to_string(filament + 1);
|
||||
warning += " ";
|
||||
}
|
||||
text = (boost::format(_u8L("filaments %s cannot be printed directly on the surface of this plate.")) % warning).str();
|
||||
text = (boost::format(_u8L("Filaments %s cannot be printed directly on the surface of this plate.")) % warning).str();
|
||||
error = ErrorType::SLICING_ERROR;
|
||||
break;
|
||||
}
|
||||
@@ -9665,7 +9677,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
||||
break;
|
||||
}
|
||||
case EWarning::FlushingVolumeZero:
|
||||
text = _u8L("Partial flushing volume set to 0. Multi-color printing may cause color mixing in models. Please redjust flushing settings.");
|
||||
text = _u8L("Partial flushing volume set to 0. Multi-color printing may cause color mixing in models. Please readjust flushing settings.");
|
||||
error = ErrorType::SLICING_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
+49
-28
@@ -523,34 +523,34 @@ bool static check_old_linux_datadir(const wxString& app_name) {
|
||||
#endif
|
||||
|
||||
struct FileWildcards {
|
||||
std::string_view title;
|
||||
const char* title_id;
|
||||
std::vector<std::string_view> file_extensions;
|
||||
};
|
||||
|
||||
static const FileWildcards file_wildcards_by_type[FT_SIZE] = {
|
||||
/* FT_STEP */ { "STEP files"sv, { ".stp"sv, ".step"sv } },
|
||||
/* FT_STL */ { "STL files"sv, { ".stl"sv } },
|
||||
/* FT_OBJ */ { "OBJ files"sv, { ".obj"sv } },
|
||||
/* FT_AMF */ { "AMF files"sv, { ".amf"sv, ".zip.amf"sv, ".xml"sv } },
|
||||
/* FT_3MF */ { "3MF files"sv, { ".3mf"sv } },
|
||||
/* FT_GCODE_3MF */ {"Gcode 3MF files"sv, {".gcode.3mf"sv}},
|
||||
/* FT_GCODE */ { "G-code files"sv, { ".gcode"sv} },
|
||||
/* FT_STEP */ { L("STEP files"), { ".stp"sv, ".step"sv } },
|
||||
/* FT_STL */ { L("STL files"), { ".stl"sv } },
|
||||
/* FT_OBJ */ { L("OBJ files"), { ".obj"sv } },
|
||||
/* FT_AMF */ { L("AMF files"), { ".amf"sv, ".zip.amf"sv, ".xml"sv } },
|
||||
/* FT_3MF */ { L("3MF files"), { ".3mf"sv } },
|
||||
/* FT_GCODE_3MF */ {L("Gcode 3MF files"), {".gcode.3mf"sv}},
|
||||
/* FT_GCODE */ { L("G-code files"), { ".gcode"sv} },
|
||||
#ifdef __APPLE__
|
||||
/* FT_MODEL */
|
||||
{"Supported files"sv, {".3mf"sv, ".stl"sv, ".oltp"sv, ".stp"sv, ".step"sv, ".svg"sv, ".amf"sv, ".obj"sv, ".usd"sv, ".usda"sv, ".usdc"sv, ".usdz"sv, ".abc"sv, ".ply"sv, ".drc"sv}},
|
||||
{L("Supported files"), {".3mf"sv, ".stl"sv, ".oltp"sv, ".stp"sv, ".step"sv, ".svg"sv, ".amf"sv, ".obj"sv, ".usd"sv, ".usda"sv, ".usdc"sv, ".usdz"sv, ".abc"sv, ".ply"sv, ".drc"sv}},
|
||||
#else
|
||||
/* FT_MODEL */
|
||||
{"Supported files"sv, {".3mf"sv, ".stl"sv, ".oltp"sv, ".stp"sv, ".step"sv, ".svg"sv, ".amf"sv, ".obj"sv, ".drc"sv}},
|
||||
{L("Supported files"), {".3mf"sv, ".stl"sv, ".oltp"sv, ".stp"sv, ".step"sv, ".svg"sv, ".amf"sv, ".obj"sv, ".drc"sv}},
|
||||
#endif
|
||||
/* FT_ZIP */ { "ZIP files"sv, { ".zip"sv } },
|
||||
/* FT_PROJECT */ { "Project files"sv, { ".3mf"sv} },
|
||||
/* FT_GALLERY */ { "Known files"sv, { ".stl"sv, ".obj"sv } },
|
||||
/* FT_ZIP */ { L("ZIP files"), { ".zip"sv } },
|
||||
/* FT_PROJECT */ { L("Project files"), { ".3mf"sv} },
|
||||
/* FT_GALLERY */ { L("Known files"), { ".stl"sv, ".obj"sv } },
|
||||
|
||||
/* FT_INI */ { "INI files"sv, { ".ini"sv } },
|
||||
/* FT_SVG */ { "SVG files"sv, { ".svg"sv } },
|
||||
/* FT_TEX */ { "Texture"sv, { ".png"sv, ".svg"sv } },
|
||||
/* FT_SL1 */ { "Masked SLA files"sv, { ".sl1"sv, ".sl1s"sv } },
|
||||
/* FT_DRC */ { "Draco files"sv, { ".drc"sv } },
|
||||
/* FT_INI */ { L("INI files"), { ".ini"sv } },
|
||||
/* FT_SVG */ { L("SVG files"), { ".svg"sv } },
|
||||
/* FT_TEX */ { L("Texture"), { ".png"sv, ".svg"sv } },
|
||||
/* FT_SL1 */ { L("Masked SLA files"), { ".sl1"sv, ".sl1s"sv } },
|
||||
/* FT_DRC */ { L("Draco files"), { ".drc"sv } },
|
||||
};
|
||||
|
||||
// This function produces a Win32 file dialog file template mask to be consumed by wxWidgets on all platforms.
|
||||
@@ -605,7 +605,8 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension)
|
||||
mask += ";*";
|
||||
mask += boost::to_upper_copy(std::string(ext));
|
||||
}
|
||||
return GUI::format_wxstr("%s (%s)|%s", data.title, title, mask);
|
||||
const wxString translated_title = Slic3r::GUI::I18N::translate(data.title_id);
|
||||
return GUI::format_wxstr("%s (%s)|%s", translated_title, title, mask);
|
||||
}
|
||||
|
||||
static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); }
|
||||
@@ -872,7 +873,9 @@ void GUI_App::post_init()
|
||||
}
|
||||
if (!switch_to_3d) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", begin load_gl_resources";
|
||||
#ifndef __linux__
|
||||
mainframe->Freeze();
|
||||
#endif
|
||||
plater_->canvas3D()->enable_render(false);
|
||||
mainframe->select_tab(size_t(MainFrame::tp3DEditor));
|
||||
plater_->select_view_3D("3D");
|
||||
@@ -909,7 +912,9 @@ void GUI_App::post_init()
|
||||
mainframe->select_tab(size_t(0));
|
||||
if (app_config->get("default_page") == "1")
|
||||
mainframe->select_tab(size_t(1));
|
||||
#ifndef __linux__
|
||||
mainframe->Thaw();
|
||||
#endif
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", end load_gl_resources";
|
||||
}
|
||||
|
||||
@@ -1717,7 +1722,7 @@ bool GUI_App::hot_reload_network_plugin()
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": starting hot reload";
|
||||
|
||||
wxBusyCursor busy;
|
||||
wxBusyInfo info(_L("Reloading network plugin..."), mainframe);
|
||||
wxBusyInfo info(_L("Reloading network plug-in..."), mainframe);
|
||||
wxYield();
|
||||
wxWindowDisabler disabler;
|
||||
|
||||
@@ -1860,7 +1865,7 @@ void GUI_App::show_network_plugin_download_dialog(bool is_update)
|
||||
app_config->set_network_plugin_version(selected);
|
||||
app_config->save();
|
||||
|
||||
DownloadProgressDialog download_dlg(_L("Downloading Network Plugin"));
|
||||
DownloadProgressDialog download_dlg(_L("Downloading Network Plug-in"));
|
||||
download_dlg.ShowModal();
|
||||
}
|
||||
break;
|
||||
@@ -2716,6 +2721,18 @@ bool GUI_App::on_init_inner()
|
||||
g_object_set (gtk_settings_get_default (), "gtk-menu-images", TRUE, NULL);
|
||||
#endif
|
||||
|
||||
#if defined(__WXGTK20__) || defined(__WXGTK3__)
|
||||
// Suppress harmless GTK critical warnings from the GTK3/wxWidgets interaction.
|
||||
// These include widget allocation on hidden widgets and events on unrealized widgets.
|
||||
g_log_set_handler("Gtk", G_LOG_LEVEL_CRITICAL,
|
||||
[](const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) {
|
||||
if (message && (strstr(message, "gtk_widget_set_allocation") ||
|
||||
strstr(message, "WIDGET_REALIZED_FOR_EVENT")))
|
||||
return;
|
||||
g_log_default_handler(log_domain, log_level, message, user_data);
|
||||
}, nullptr);
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
//BBS set crash log folder
|
||||
CBaseException::set_log_folder(data_dir());
|
||||
@@ -4416,7 +4433,7 @@ wxString GUI_App::transition_tridid(int trid_id) const
|
||||
if (trid_id == VIRTUAL_TRAY_MAIN_ID || trid_id == VIRTUAL_TRAY_DEPUTY_ID)
|
||||
{
|
||||
assert(0);
|
||||
return wxString("Ext");
|
||||
return _L("Ext");
|
||||
}
|
||||
|
||||
wxString maping_dict[] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
|
||||
@@ -5450,7 +5467,7 @@ void GUI_App::check_new_version_sf(bool show_tips, int by_user)
|
||||
}
|
||||
|
||||
version_info.url = prefer_release ? best_release_url : best_pre_url;
|
||||
version_info.version_str = prefer_release ? best_release.to_string_sf() : best_pre.to_string();
|
||||
version_info.version_str = prefer_release ? best_release.to_string_sf() : best_pre.to_string_sf();
|
||||
version_info.description = prefer_release ? best_release_content : best_pre_content;
|
||||
version_info.force_upgrade = false;
|
||||
|
||||
@@ -5535,11 +5552,15 @@ bool GUI_App::process_network_msg(std::string dev_id, std::string msg)
|
||||
}
|
||||
else if (msg == "unsigned_studio") {
|
||||
BOOST_LOG_TRIVIAL(info) << "process_network_msg, unsigned_studio";
|
||||
MessageDialog msg_dlg(nullptr,
|
||||
_L("Bambu Lab has implemented a signature verification check in their network plugin that restricts "
|
||||
"third-party software from communicating with your printer.\n\n"
|
||||
"As a result, some printing functions are unavailable in OrcaSlicer."),
|
||||
_L("Network Plugin Restriction"), wxAPPLY | wxOK);
|
||||
MessageDialog
|
||||
msg_dlg(nullptr,
|
||||
_L("To use OrcaSlicer with Bambu Lab printers, you need to enable LAN mode and Developer mode on your printer.\n\n"
|
||||
"Please go to your printer's settings and:\n"
|
||||
"1. Turn on LAN mode\n"
|
||||
"2. Enable Developer mode\n\n"
|
||||
"Developer mode allows the printer to work exclusively through local network access, "
|
||||
"enabling full functionality with OrcaSlicer."),
|
||||
_L("Network Plug-in Restriction"), wxAPPLY | wxOK);
|
||||
m_show_error_msgdlg = true;
|
||||
msg_dlg.ShowModal();
|
||||
m_show_error_msgdlg = false;
|
||||
|
||||
@@ -363,6 +363,9 @@ public:
|
||||
bool show_3d_navigator() const { return app_config->get_bool("show_3d_navigator"); }
|
||||
void toggle_show_3d_navigator() const { app_config->set_bool("show_3d_navigator", !show_3d_navigator()); }
|
||||
|
||||
bool show_plate_gridlines() const { return app_config->get_bool("show_plate_gridlines"); }
|
||||
void toggle_show_plate_gridlines() const { app_config->set_bool("show_plate_gridlines", !show_plate_gridlines()); }
|
||||
|
||||
bool show_canvas_zoom_button() const { return app_config->get_bool("show_canvas_zoom_button"); }
|
||||
void toggle_canvas_zoom_button() const { app_config->set_bool("show_canvas_zoom_button", !show_canvas_zoom_button()); }
|
||||
|
||||
|
||||
@@ -580,7 +580,7 @@ wxMenu* MenuFactory::append_submenu_add_handy_model(wxMenu* menu, ModelVolumeTyp
|
||||
"Yes - Change these settings automatically\n"
|
||||
"No - Do not change these settings for me");
|
||||
|
||||
MessageDialog dialog(wxGetApp().plater(), msg_text, "Suggestion", wxICON_WARNING | wxYES | wxNO);
|
||||
MessageDialog dialog(wxGetApp().plater(), msg_text, _L("Suggestion"), wxICON_WARNING | wxYES | wxNO);
|
||||
if (dialog.ShowModal() == wxID_YES) {
|
||||
m_config->set_key_value("min_width_top_surface", new ConfigOptionFloatOrPercent(0, false));
|
||||
wxGetApp().get_tab(Preset::TYPE_PRINT)->update_dirty();
|
||||
@@ -1351,6 +1351,8 @@ void MenuFactory::create_extra_object_menu()
|
||||
append_menu_item_fix_through_netfabb(&m_object_menu);
|
||||
// Object Simplify
|
||||
append_menu_item_simplify(&m_object_menu);
|
||||
// Object Mesh Subdivision
|
||||
append_menu_item_smooth_mesh(&m_object_menu);
|
||||
// merge to single part
|
||||
append_menu_item_merge_parts_to_single_part(&m_object_menu);
|
||||
// Object Center
|
||||
@@ -1402,6 +1404,8 @@ void MenuFactory::create_bbl_assemble_object_menu()
|
||||
append_menu_item_fix_through_netfabb(&m_assemble_object_menu);
|
||||
// Object Simplify
|
||||
append_menu_item_simplify(&m_assemble_object_menu);
|
||||
// Object Mesh Subdivision
|
||||
append_menu_item_smooth_mesh(&m_assemble_object_menu);
|
||||
m_assemble_object_menu.AppendSeparator();
|
||||
}
|
||||
|
||||
@@ -1485,6 +1489,7 @@ void MenuFactory::create_bbl_part_menu()
|
||||
append_menu_item_edit_text(menu);
|
||||
append_menu_item_fix_through_netfabb(menu);
|
||||
append_menu_item_simplify(menu);
|
||||
append_menu_item_smooth_mesh(menu);
|
||||
append_menu_item_center(menu);
|
||||
append_menu_item_drop(menu);
|
||||
append_menu_items_mirror(menu);
|
||||
@@ -1516,6 +1521,7 @@ void MenuFactory::create_bbl_assemble_part_menu()
|
||||
|
||||
append_menu_item_delete(menu);
|
||||
append_menu_item_simplify(menu);
|
||||
append_menu_item_smooth_mesh(menu);
|
||||
menu->AppendSeparator();
|
||||
}
|
||||
|
||||
@@ -1568,7 +1574,7 @@ void MenuFactory::create_plate_menu()
|
||||
{
|
||||
wxMenu* menu = &m_plate_menu;
|
||||
// select objects on current plate
|
||||
append_menu_item(menu, wxID_ANY, _L("Select All"), _L("select all objects on current plate"),
|
||||
append_menu_item(menu, wxID_ANY, _L("Select All"), _L("Select all objects on the current plate"),
|
||||
[](wxCommandEvent&) {
|
||||
plater()->select_curr_plate_all();
|
||||
}, "", nullptr, []() {
|
||||
@@ -1577,8 +1583,16 @@ void MenuFactory::create_plate_menu()
|
||||
return !plate->get_objects().empty();
|
||||
}, m_parent);
|
||||
|
||||
// select objects on all plates
|
||||
append_menu_item(menu, wxID_ANY, _L("Select All Plates"), _L("Select all objects on all plates"),
|
||||
[](wxCommandEvent&) {
|
||||
plater()->select_all();
|
||||
}, "", nullptr, []() {
|
||||
return !plater()->model().objects.empty();
|
||||
}, m_parent);
|
||||
|
||||
// delete objects on current plate
|
||||
append_menu_item(menu, wxID_ANY, _L("Delete All"), _L("delete all objects on current plate"),
|
||||
append_menu_item(menu, wxID_ANY, _L("Delete All"), _L("Delete all objects on the current plate"),
|
||||
[](wxCommandEvent&) {
|
||||
plater()->remove_curr_plate_all();
|
||||
}, "", nullptr, []() {
|
||||
@@ -1588,7 +1602,7 @@ void MenuFactory::create_plate_menu()
|
||||
}, m_parent);
|
||||
|
||||
// arrange objects on current plate
|
||||
append_menu_item(menu, wxID_ANY, _L("Arrange"), _L("arrange current plate"),
|
||||
append_menu_item(menu, wxID_ANY, _L("Arrange"), _L("Arrange current plate"),
|
||||
[](wxCommandEvent&) {
|
||||
PartPlate* plate = plater()->get_partplate_list().get_selected_plate();
|
||||
assert(plate);
|
||||
@@ -1602,7 +1616,7 @@ void MenuFactory::create_plate_menu()
|
||||
|
||||
// reload all objects on current plate
|
||||
append_menu_item(
|
||||
menu, wxID_ANY, _L("Reload All"), _L("reload all from disk"),
|
||||
menu, wxID_ANY, _L("Reload All"), _L("Reload all from disk"),
|
||||
[](wxCommandEvent&) {
|
||||
PartPlate* plate = plater()->get_partplate_list().get_selected_plate();
|
||||
assert(plate);
|
||||
@@ -1612,7 +1626,7 @@ void MenuFactory::create_plate_menu()
|
||||
"", nullptr, []() { return !plater()->get_partplate_list().get_selected_plate()->get_objects().empty(); }, m_parent);
|
||||
|
||||
// orient objects on current plate
|
||||
append_menu_item(menu, wxID_ANY, _L("Auto Rotate"), _L("auto rotate current plate"),
|
||||
append_menu_item(menu, wxID_ANY, _L("Auto Rotate"), _L("Auto rotate current plate"),
|
||||
[](wxCommandEvent&) {
|
||||
PartPlate* plate = plater()->get_partplate_list().get_selected_plate();
|
||||
assert(plate);
|
||||
@@ -1951,6 +1965,13 @@ void MenuFactory::append_menu_item_simplify(wxMenu* menu)
|
||||
[]() {return plater()->can_simplify(); }, m_parent);
|
||||
}
|
||||
|
||||
void MenuFactory::append_menu_item_smooth_mesh(wxMenu *menu)
|
||||
{
|
||||
wxMenuItem *menu_item = append_menu_item(
|
||||
menu, wxID_ANY, _L("Subdivision mesh") + _L("(Lost color)"), "", [](wxCommandEvent &) { obj_list()->smooth_mesh(); }, "", menu, []() { return plater()->can_smooth_mesh(); },
|
||||
m_parent);
|
||||
}
|
||||
|
||||
void MenuFactory::append_menu_item_center(wxMenu* menu)
|
||||
{
|
||||
append_menu_item(menu, wxID_ANY, _L("Center") , "",
|
||||
|
||||
@@ -164,6 +164,7 @@ private:
|
||||
//BBS add bbl menu item
|
||||
void append_menu_item_clone(wxMenu* menu);
|
||||
void append_menu_item_simplify(wxMenu* menu);
|
||||
void append_menu_item_smooth_mesh(wxMenu *menu);
|
||||
void append_menu_item_center(wxMenu* menu);
|
||||
void append_menu_item_drop(wxMenu* menu);
|
||||
void append_menu_item_per_object_process(wxMenu* menu);
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#endif /* __WXMSW__ */
|
||||
#include "Gizmos/GLGizmoScale.hpp"
|
||||
|
||||
#include "libslic3r/TriangleMeshDeal.hpp"
|
||||
namespace Slic3r
|
||||
{
|
||||
namespace GUI
|
||||
@@ -5931,6 +5932,92 @@ void ObjectList::simplify()
|
||||
gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify);
|
||||
}
|
||||
|
||||
void GUI::ObjectList::smooth_mesh()
|
||||
{
|
||||
wxBusyCursor cursor;
|
||||
auto plater = wxGetApp().plater();
|
||||
if (!plater) { return; }
|
||||
plater->take_snapshot("smooth_mesh");
|
||||
std::vector<int> obj_idxs, vol_idxs;
|
||||
get_selection_indexes(obj_idxs, vol_idxs);
|
||||
auto object_idx = obj_idxs.front();
|
||||
ModelObject *obj{nullptr};
|
||||
auto show_warning_dlg = [this](int cur_face_count,std::string name,bool is_part) {
|
||||
int limit_face_count = 1000000;
|
||||
if (cur_face_count > limit_face_count) {
|
||||
auto name_str = wxString::FromUTF8(name);
|
||||
auto content = wxString::Format(_L("\"%s\" will exceed 1 million faces after this subdivision, which may increase slicing time. Do you want to continue?"), name_str);
|
||||
WarningDialog dlg(static_cast<wxWindow *>(wxGetApp().mainframe), (is_part ? _L("Part") : _L("Object")) + " " + content, wxEmptyString, wxYES_NO);
|
||||
if (dlg.ShowModal() == wxID_NO) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
auto show_smooth_mesh_error_dlg = [this](std::string name) {
|
||||
auto name_str = wxString::FromUTF8(name);
|
||||
auto content = wxString::Format(_L("\"%s\" part's mesh contains errors. Please repair it first."), name_str);
|
||||
WarningDialog dlg(static_cast<wxWindow *>(wxGetApp().mainframe), content, wxEmptyString, wxOK);
|
||||
dlg.ShowModal();
|
||||
};
|
||||
bool has_show_smooth_mesh_error_dlg = false;
|
||||
if (vol_idxs.empty()) {
|
||||
obj = object(object_idx);
|
||||
auto future_face_count = static_cast<int>(obj->facets_count()) * 4;
|
||||
if (show_warning_dlg(future_face_count, obj->name,false)) {
|
||||
return;
|
||||
}
|
||||
for (auto mv : obj->volumes) {
|
||||
bool ok;
|
||||
auto result_mesh = TriangleMeshDeal::smooth_triangle_mesh(mv->mesh(), ok);
|
||||
if (ok) {
|
||||
mv->set_mesh(result_mesh);
|
||||
mv->reset_extra_facets(); // reset paint color
|
||||
mv->calculate_convex_hull();
|
||||
mv->invalidate_convex_hull_2d();
|
||||
mv->set_new_unique_id();
|
||||
} else {
|
||||
if (!has_show_smooth_mesh_error_dlg) {
|
||||
show_smooth_mesh_error_dlg(mv->name);
|
||||
has_show_smooth_mesh_error_dlg = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
obj->invalidate_bounding_box();
|
||||
obj->ensure_on_bed();
|
||||
plater->changed_mesh(object_idx);
|
||||
} else {
|
||||
obj = object(obj_idxs.front());
|
||||
for (int vol_idx : vol_idxs) {
|
||||
auto mv = obj->volumes[vol_idx];
|
||||
auto future_face_count = static_cast<int>(mv->mesh().facets_count()) * 4;
|
||||
if (show_warning_dlg(future_face_count, mv->name,true)) {
|
||||
return;
|
||||
}
|
||||
bool ok;
|
||||
auto result_mesh = TriangleMeshDeal::smooth_triangle_mesh(mv->mesh(),ok);
|
||||
if (ok) {
|
||||
mv->set_mesh(result_mesh);
|
||||
mv->reset_extra_facets(); // reset paint color
|
||||
mv->calculate_convex_hull();
|
||||
mv->invalidate_convex_hull_2d();
|
||||
mv->set_new_unique_id();
|
||||
} else {
|
||||
if (!has_show_smooth_mesh_error_dlg) {
|
||||
show_smooth_mesh_error_dlg(mv->name);
|
||||
has_show_smooth_mesh_error_dlg = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (obj) {
|
||||
obj->invalidate_bounding_box();
|
||||
obj->ensure_on_bed();
|
||||
plater->changed_mesh(object_idx);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectList::update_item_error_icon(const int obj_idx, const int vol_idx) const
|
||||
{
|
||||
auto obj = object(obj_idx);
|
||||
|
||||
@@ -428,6 +428,7 @@ public:
|
||||
void rename_item();
|
||||
void fix_through_netfabb();
|
||||
void simplify();
|
||||
void smooth_mesh();
|
||||
void update_item_error_icon(const int obj_idx, int vol_idx) const ;
|
||||
|
||||
void copy_layers_to_clipboard();
|
||||
|
||||
@@ -1070,7 +1070,7 @@ void ObjectGrid::paste_data( wxTextDataObject& text_data )
|
||||
if ((src_row_cnt == 1) && (src_col_cnt == 1))
|
||||
{
|
||||
if ((dst_col_cnt != 1) || (dst_left_col != src_left_col)) {
|
||||
wxLogWarning(_L("one cell can only be copied to one or multiple cells in the same column"));
|
||||
wxLogWarning(_L("One cell can only be copied to one or more cells in the same column."));
|
||||
}
|
||||
else {
|
||||
split(buf, string_array);
|
||||
|
||||
@@ -668,7 +668,7 @@ void GLGizmoAdvancedCut::perform_cut(const Selection& selection)
|
||||
if (its_num_open_edges(new_objects[i]->volumes[j]->mesh().its) > 0) {
|
||||
if (!is_showed_dialog) {
|
||||
is_showed_dialog = true;
|
||||
MessageDialog dlg(nullptr, _L("non-manifold edges be caused by cut tool, do you want to fix it now?"), "", wxYES | wxNO);
|
||||
MessageDialog dlg(nullptr, _L("Non-manifold edges be caused by cut tool, do you want to fix it now?"), "", wxYES | wxNO);
|
||||
int ret = dlg.ShowModal();
|
||||
if (ret == wxID_YES) {
|
||||
user_fix_model = true;
|
||||
|
||||
@@ -3376,7 +3376,7 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
|
||||
if (its_num_open_edges(new_objects[i]->volumes[j]->mesh().its) > 0) {
|
||||
if (!is_showed_dialog) {
|
||||
is_showed_dialog = true;
|
||||
MessageDialog dlg(nullptr, _L("non-manifold edges be caused by cut tool, do you want to fix it now?"), "", wxYES | wxCANCEL);
|
||||
MessageDialog dlg(nullptr, _L("Non-manifold edges be caused by cut tool, do you want to fix it now?"), "", wxYES | wxCANCEL);
|
||||
int ret = dlg.ShowModal();
|
||||
if (ret == wxID_YES) {
|
||||
user_fix_model = true;
|
||||
|
||||
@@ -3401,8 +3401,11 @@ bool load(Facenames &facenames) {
|
||||
|
||||
facenames.hash = data.hash;
|
||||
facenames.faces.reserve(data.good.size());
|
||||
for (const wxString &face : data.good)
|
||||
facenames.faces_names.reserve(data.good.size());
|
||||
for (const wxString &face : data.good) {
|
||||
facenames.faces.push_back({face});
|
||||
facenames.faces_names.push_back(face.utf8_string());
|
||||
}
|
||||
facenames.bad = data.bad;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1286,9 +1286,6 @@ void GLGizmoMmuSegmentation::remap_filament_assignments()
|
||||
size_t dst = m_extruder_remap[src];
|
||||
if (dst != src) {
|
||||
state_map[src+start_extruder] = static_cast<EnforcerBlockerType>(dst+start_extruder);
|
||||
if (src == 0)
|
||||
state_map[0] = static_cast<EnforcerBlockerType>(dst + start_extruder);
|
||||
|
||||
any_change = true;
|
||||
}
|
||||
}
|
||||
@@ -1319,11 +1316,19 @@ void GLGizmoMmuSegmentation::remap_filament_assignments()
|
||||
// ORCA: Remap base volume extruder as well if selected
|
||||
int current_ext_id = mv->extruder_id();
|
||||
int current_idx = (current_ext_id > 0) ? current_ext_id - 1 : 0;
|
||||
|
||||
|
||||
if (current_idx >= 0 && current_idx < m_extruder_remap.size()) {
|
||||
size_t dest_idx = m_extruder_remap[current_idx];
|
||||
if (dest_idx != current_idx) {
|
||||
mv->config.set("extruder", (int)dest_idx + 1);
|
||||
// Check if volume has its own extruder config or uses object's fallback
|
||||
const ConfigOption *vol_opt = mv->config.option("extruder");
|
||||
if (vol_opt != nullptr && vol_opt->getInt() != 0) {
|
||||
// Volume has its own extruder setting, update it
|
||||
mv->config.set("extruder", (int)dest_idx + 1);
|
||||
} else {
|
||||
// Volume uses object's extruder setting, update the object
|
||||
mo->config.set("extruder", (int)dest_idx + 1);
|
||||
}
|
||||
if (idx < m_volumes_extruder_idxs.size())
|
||||
m_volumes_extruder_idxs[idx] = (int)dest_idx + 1;
|
||||
volume_extruder_changed = true;
|
||||
@@ -1335,8 +1340,11 @@ void GLGizmoMmuSegmentation::remap_filament_assignments()
|
||||
|
||||
if (updated) {
|
||||
// ORCA: Update renderer colors if base volume extruder changed
|
||||
if (volume_extruder_changed)
|
||||
if (volume_extruder_changed) {
|
||||
this->update_triangle_selectors_colors();
|
||||
// ORCA: Update GUI_ObjectList extruder column to reflect the new extruder value
|
||||
wxGetApp().obj_list()->update_objects_list_filament_column(wxGetApp().filaments_cnt());
|
||||
}
|
||||
|
||||
// ORCA: Removed "Filament remapping finished" notification to reduce UI noise.
|
||||
update_model_object();
|
||||
|
||||
@@ -709,7 +709,7 @@ GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper * imgui,
|
||||
wxGetApp().app_config->set("sla_auto_rotate",
|
||||
"method_id",
|
||||
std::to_string(state.method_id));
|
||||
#endif SUPPORT_SLA_AUTO_ROTATE
|
||||
#endif // SUPPORT_SLA_AUTO_ROTATE
|
||||
}
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
|
||||
@@ -1332,7 +1332,7 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
|
||||
is_avoid_one_update = true;
|
||||
}
|
||||
|
||||
auto uniform_scale_size =imgui_wrapper->calc_text_size(_L("uniform scale")).x;
|
||||
auto uniform_scale_size =imgui_wrapper->calc_text_size(_L("Uniform scale")).x;
|
||||
ImGui::PushItemWidth(uniform_scale_size);
|
||||
int size_sel{-1};
|
||||
if (!is_avoid_one_update) {
|
||||
@@ -1348,10 +1348,10 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w
|
||||
|
||||
//if (uniform_scale_only) {
|
||||
// imgui_wrapper->disabled_begin(true);
|
||||
// imgui_wrapper->bbl_checkbox(_L("uniform scale"), uniform_scale_only);
|
||||
// imgui_wrapper->bbl_checkbox(_L("Uniform scale"), uniform_scale_only);
|
||||
// imgui_wrapper->disabled_end();
|
||||
//} else {
|
||||
imgui_wrapper->bbl_checkbox(_L("uniform scale"), uniform_scale);
|
||||
imgui_wrapper->bbl_checkbox(_L("Uniform scale"), uniform_scale);
|
||||
//}
|
||||
if (uniform_scale != this->m_uniform_scale) { this->set_uniform_scaling(uniform_scale); }
|
||||
|
||||
|
||||
@@ -1470,10 +1470,11 @@ void IMSlider::on_mouse_wheel(wxMouseEvent& evt) {
|
||||
|
||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
|
||||
float wheel = 0.0f;
|
||||
wheel = evt.GetWheelRotation() > 0 ? 1.0f : -1.0f;
|
||||
float wheel = evt.GetWheelRotation();
|
||||
// mac trackpads trigger this event with value 0 when right-clicking with two fingers
|
||||
if (wheel == 0.0f)
|
||||
return;
|
||||
wheel = wheel > 0 ? 1.0f : -1.0f;
|
||||
|
||||
#ifdef __WXOSX__
|
||||
if (wxGetKeyState(WXK_SHIFT)) {
|
||||
|
||||
@@ -299,7 +299,7 @@ CreateObjectJob::CreateObjectJob(DataCreateObject &&input): m_input(std::move(in
|
||||
void CreateObjectJob::process(Ctl &ctl)
|
||||
{
|
||||
if (!check(m_input))
|
||||
throw JobException("Bad input data for EmbossCreateObjectJob.");
|
||||
throw JobException(_u8L("Bad input data for EmbossCreateObjectJob."));
|
||||
|
||||
// can't create new object with using surface
|
||||
if (m_input.base->shape.projection.use_surface)
|
||||
@@ -398,13 +398,13 @@ UpdateJob::UpdateJob(DataUpdate&& input): m_input(std::move(input)){ assert(chec
|
||||
void UpdateJob::process(Ctl &ctl)
|
||||
{
|
||||
if (!check(m_input))
|
||||
throw JobException("Bad input data for EmbossUpdateJob.");
|
||||
throw JobException(_u8L("Bad input data for EmbossUpdateJob."));
|
||||
|
||||
auto was_canceled = ::was_canceled(ctl, *m_input.base);
|
||||
m_result = ::try_create_mesh(*m_input.base, was_canceled);
|
||||
if (was_canceled()) return;
|
||||
if (m_result.its.empty())
|
||||
throw JobException("Created text volume is empty. Change text or font.");
|
||||
throw JobException(_u8L("Created text volume is empty. Change text or font."));
|
||||
}
|
||||
|
||||
void UpdateJob::finalize(bool canceled, std::exception_ptr &eptr)
|
||||
@@ -462,7 +462,7 @@ CreateSurfaceVolumeJob::CreateSurfaceVolumeJob(CreateSurfaceVolumeData &&input)
|
||||
|
||||
void CreateSurfaceVolumeJob::process(Ctl &ctl) {
|
||||
if (!check(m_input))
|
||||
throw JobException("Bad input data for CreateSurfaceVolumeJob.");
|
||||
throw JobException(_u8L("Bad input data for CreateSurfaceVolumeJob."));
|
||||
m_result = cut_surface(*m_input.base, m_input, was_canceled(ctl, *m_input.base));
|
||||
}
|
||||
|
||||
@@ -484,7 +484,7 @@ UpdateSurfaceVolumeJob::UpdateSurfaceVolumeJob(UpdateSurfaceVolumeData &&input)
|
||||
void UpdateSurfaceVolumeJob::process(Ctl &ctl)
|
||||
{
|
||||
if (!check(m_input))
|
||||
throw JobException("Bad input data for UseSurfaceJob.");
|
||||
throw JobException(_u8L("Bad input data for UseSurfaceJob."));
|
||||
m_result = cut_surface(*m_input.base, m_input, was_canceled(ctl, *m_input.base));
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "slic3r/GUI/DeviceCore/DevUtil.h"
|
||||
|
||||
#include "slic3r/Utils/FileTransferUtils.hpp"
|
||||
#include "slic3r/Utils/BBLNetworkPlugin.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
@@ -228,7 +229,15 @@ void PrintJob::process(Ctl &ctl)
|
||||
ftp_ok = result == 0;
|
||||
}
|
||||
if (!emmc_ok && !ftp_ok) {
|
||||
BOOST_LOG_TRIVIAL(error) << "access code is invalid";
|
||||
bool legacy_mode = BBLNetworkPlugin::instance().use_legacy_network();
|
||||
BOOST_LOG_TRIVIAL(error) << "LAN connection verification failed:"
|
||||
<< " emmc_ok=" << emmc_ok
|
||||
<< ", ftp_ok=" << ftp_ok
|
||||
<< ", ftp_result=" << result
|
||||
<< ", dev_ip=" << m_dev_ip
|
||||
<< ", dev_id=" << m_dev_id
|
||||
<< ", password_length=" << m_access_code.size()
|
||||
<< ", legacy_mode=" << (legacy_mode ? "true" : "false");
|
||||
m_enter_ip_address_fun_fail();
|
||||
m_job_finished = true;
|
||||
return;
|
||||
|
||||
@@ -211,9 +211,9 @@ void KBShortcutsDialog::fill_shortcuts()
|
||||
bool swap_mouse_buttons = wxGetApp().app_config->get_bool("swap_mouse_buttons");
|
||||
|
||||
Shortcuts plater_shortcuts = {
|
||||
{ L("Left mouse button"), swap_mouse_buttons ? L("Pan View") : L("Rotate View") },
|
||||
{ L("Right mouse button"), swap_mouse_buttons ? L("Rotate View") : L("Pan View") },
|
||||
{ L("Mouse wheel"), L("Zoom View") },
|
||||
{ L("Left mouse button"), swap_mouse_buttons ? L("Pan view") : L("Rotate view") },
|
||||
{ L("Right mouse button"), swap_mouse_buttons ? L("Rotate view") : L("Pan view") },
|
||||
{ L("Mouse wheel"), L("Zoom view") },
|
||||
{ "A", L("Arrange all objects") },
|
||||
{ shift + "A", L("Arrange objects on selected plates") },
|
||||
|
||||
@@ -231,7 +231,7 @@ void KBShortcutsDialog::fill_shortcuts()
|
||||
{L("Arrow Right"), L("Move selection 10 mm in positive X direction")},
|
||||
{shift + L("Any arrow"), L("Movement step set to 1 mm")},
|
||||
{L("Esc"), L("Deselect all")},
|
||||
{"1-9", L("keyboard 1-9: set filament for object/part")},
|
||||
{"1-9", L("Keyboard 1-9: set filament for object/part")},
|
||||
{ctrl + "0", L("Camera view - Default")},
|
||||
{ctrl + "1", L("Camera view - Top")},
|
||||
{ctrl + "2", L("Camera view - Bottom")},
|
||||
|
||||
@@ -224,12 +224,14 @@ GCodeInputData convert(const Slic3r::GCodeProcessorResult& result, const std::ve
|
||||
const libvgcode::PathVertex vertex = { convert(prev.position), curr.height, curr.width, curr.feedrate, prev.actual_feedrate,
|
||||
curr.mm3_per_mm, curr.fan_speed, curr.temperature, 0.0f, convert(curr.extrusion_role), curr_type,
|
||||
static_cast<uint32_t>(curr.gcode_id), static_cast<uint32_t>(curr.layer_id),
|
||||
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), { 0.0f, 0.0f } };
|
||||
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), { 0.0f, 0.0f },
|
||||
/* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance };
|
||||
#else
|
||||
const libvgcode::PathVertex vertex = { convert(prev.position), curr.height, curr.width, curr.feedrate, prev.actual_feedrate,
|
||||
curr.mm3_per_mm, curr.fan_speed, curr.temperature, convert(curr.extrusion_role), curr_type,
|
||||
static_cast<uint32_t>(curr.gcode_id), static_cast<uint32_t>(curr.layer_id),
|
||||
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), { 0.0f, 0.0f } };
|
||||
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), { 0.0f, 0.0f },
|
||||
/* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance };
|
||||
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
|
||||
ret.vertices.emplace_back(vertex);
|
||||
}
|
||||
@@ -240,12 +242,14 @@ GCodeInputData convert(const Slic3r::GCodeProcessorResult& result, const std::ve
|
||||
curr.mm3_per_mm, curr.fan_speed, curr.temperature,
|
||||
result.filament_densities[curr.extruder_id] * curr.mm3_per_mm * (curr.position - prev.position).norm(),
|
||||
convert(curr.extrusion_role), curr_type, static_cast<uint32_t>(curr.gcode_id), static_cast<uint32_t>(curr.layer_id),
|
||||
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), curr.time };
|
||||
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), curr.time,
|
||||
/* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance };
|
||||
#else
|
||||
const libvgcode::PathVertex vertex = { convert(curr.position), curr.height, curr.width, curr.feedrate, curr.actual_feedrate,
|
||||
curr.mm3_per_mm, curr.fan_speed, curr.temperature, convert(curr.extrusion_role), curr_type,
|
||||
static_cast<uint32_t>(curr.gcode_id), static_cast<uint32_t>(curr.layer_id),
|
||||
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), curr.time };
|
||||
static_cast<uint8_t>(curr.extruder_id), static_cast<uint8_t>(curr.cp_color_id), curr.time,
|
||||
/* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance };
|
||||
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
|
||||
ret.vertices.emplace_back(vertex);
|
||||
}
|
||||
|
||||
@@ -74,6 +74,10 @@
|
||||
#include <shlobj.h>
|
||||
#include <shellapi.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#ifdef __WXGTK__
|
||||
#include <gtk/gtk.h>
|
||||
#endif // __WXGTK__
|
||||
#include <slic3r/GUI/CreatePresetsDialog.hpp>
|
||||
|
||||
|
||||
@@ -103,6 +107,113 @@ enum class ERescaleTarget
|
||||
SettingsDialog
|
||||
};
|
||||
|
||||
#ifdef __WXGTK__
|
||||
// A thin transparent panel placed at a window edge to handle resize.
|
||||
// Works regardless of underlying content (GLCanvas3D, wxWebView, etc.)
|
||||
// because these panels are Raise()'d above all siblings, so their GDK
|
||||
// windows receive pointer events even over WebKit2GTK or GL surfaces.
|
||||
class ResizeEdgePanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
enum Edge { Bottom, Left, Right };
|
||||
|
||||
static constexpr int BORDER_PX = 5;
|
||||
|
||||
ResizeEdgePanel(MainFrame* frame, Edge edge)
|
||||
: wxPanel(frame, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
||||
wxBORDER_NONE | wxTRANSPARENT_WINDOW)
|
||||
, m_frame(frame)
|
||||
, m_edge(edge)
|
||||
{
|
||||
SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
|
||||
Bind(wxEVT_MOTION, &ResizeEdgePanel::OnCursorUpdate, this);
|
||||
Bind(wxEVT_ENTER_WINDOW, &ResizeEdgePanel::OnCursorUpdate, this);
|
||||
Bind(wxEVT_LEFT_DOWN, &ResizeEdgePanel::OnLeftDown, this);
|
||||
Bind(wxEVT_LEAVE_WINDOW, &ResizeEdgePanel::OnLeave, this);
|
||||
Bind(wxEVT_PAINT, &ResizeEdgePanel::OnPaint, this);
|
||||
}
|
||||
|
||||
private:
|
||||
void OnPaint(wxPaintEvent&)
|
||||
{
|
||||
wxPaintDC dc(this);
|
||||
// Transparent — draw nothing
|
||||
}
|
||||
|
||||
GdkWindowEdge get_gdk_edge(const wxPoint& pos) const
|
||||
{
|
||||
wxSize size = GetSize();
|
||||
switch (m_edge) {
|
||||
case Bottom:
|
||||
if (pos.x < BORDER_PX) return GDK_WINDOW_EDGE_SOUTH_WEST;
|
||||
if (pos.x > size.x - BORDER_PX) return GDK_WINDOW_EDGE_SOUTH_EAST;
|
||||
return GDK_WINDOW_EDGE_SOUTH;
|
||||
case Left:
|
||||
if (pos.y < BORDER_PX) return GDK_WINDOW_EDGE_NORTH_WEST;
|
||||
if (pos.y > size.y - BORDER_PX) return GDK_WINDOW_EDGE_SOUTH_WEST;
|
||||
return GDK_WINDOW_EDGE_WEST;
|
||||
case Right:
|
||||
if (pos.y < BORDER_PX) return GDK_WINDOW_EDGE_NORTH_EAST;
|
||||
if (pos.y > size.y - BORDER_PX) return GDK_WINDOW_EDGE_SOUTH_EAST;
|
||||
return GDK_WINDOW_EDGE_EAST;
|
||||
}
|
||||
return GDK_WINDOW_EDGE_SOUTH;
|
||||
}
|
||||
|
||||
void OnCursorUpdate(wxMouseEvent& evt)
|
||||
{
|
||||
GdkWindowEdge edge = get_gdk_edge(evt.GetPosition());
|
||||
const char* name;
|
||||
switch (edge) {
|
||||
case GDK_WINDOW_EDGE_NORTH: name = "n-resize"; break;
|
||||
case GDK_WINDOW_EDGE_SOUTH: name = "s-resize"; break;
|
||||
case GDK_WINDOW_EDGE_WEST: name = "w-resize"; break;
|
||||
case GDK_WINDOW_EDGE_EAST: name = "e-resize"; break;
|
||||
case GDK_WINDOW_EDGE_NORTH_WEST: name = "nw-resize"; break;
|
||||
case GDK_WINDOW_EDGE_NORTH_EAST: name = "ne-resize"; break;
|
||||
case GDK_WINDOW_EDGE_SOUTH_WEST: name = "sw-resize"; break;
|
||||
case GDK_WINDOW_EDGE_SOUTH_EAST: name = "se-resize"; break;
|
||||
default: name = "s-resize"; break;
|
||||
}
|
||||
if (name == m_last_cursor_name) return;
|
||||
m_last_cursor_name = name;
|
||||
|
||||
GdkDisplay* display = gtk_widget_get_display(m_widget);
|
||||
GdkCursor* cursor = gdk_cursor_new_from_name(display, name);
|
||||
if (cursor) {
|
||||
gdk_window_set_cursor(gtk_widget_get_window(m_widget), cursor);
|
||||
g_object_unref(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
void OnLeave(wxMouseEvent&)
|
||||
{
|
||||
m_last_cursor_name = nullptr;
|
||||
gdk_window_set_cursor(gtk_widget_get_window(m_widget), nullptr);
|
||||
}
|
||||
|
||||
void OnLeftDown(wxMouseEvent& evt)
|
||||
{
|
||||
if (m_frame->IsMaximized() || m_frame->IsFullScreen())
|
||||
return;
|
||||
|
||||
GdkWindowEdge edge = get_gdk_edge(evt.GetPosition());
|
||||
wxPoint mouse = ClientToScreen(evt.GetPosition());
|
||||
|
||||
gtk_window_begin_resize_drag(
|
||||
GTK_WINDOW(m_frame->m_widget),
|
||||
edge,
|
||||
1, // left button
|
||||
mouse.x, mouse.y,
|
||||
gtk_get_current_event_time());
|
||||
}
|
||||
|
||||
MainFrame* m_frame;
|
||||
Edge m_edge;
|
||||
const char* m_last_cursor_name{nullptr};
|
||||
};
|
||||
#endif // __WXGTK__
|
||||
|
||||
#ifdef __APPLE__
|
||||
class OrcaSlicerTaskBarIcon : public wxTaskBarIcon
|
||||
{
|
||||
@@ -194,6 +305,14 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
|
||||
set_miniaturizable(GetHandle());
|
||||
#endif
|
||||
|
||||
#ifdef __WXGTK__
|
||||
m_gdkDecor = 0;
|
||||
|
||||
m_edge_bottom = new ResizeEdgePanel(this, ResizeEdgePanel::Bottom);
|
||||
m_edge_left = new ResizeEdgePanel(this, ResizeEdgePanel::Left);
|
||||
m_edge_right = new ResizeEdgePanel(this, ResizeEdgePanel::Right);
|
||||
#endif
|
||||
|
||||
if (!wxGetApp().app_config->has("user_mode")) {
|
||||
wxGetApp().app_config->set("user_mode", "simple");
|
||||
wxGetApp().app_config->set_bool("developer_mode", false);
|
||||
@@ -355,6 +474,9 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
|
||||
#endif
|
||||
Refresh();
|
||||
Layout();
|
||||
#ifdef __WXGTK__
|
||||
update_edge_panels();
|
||||
#endif
|
||||
wxQueueEvent(wxGetApp().plater(), new SimpleEvent(EVT_NOTICE_CHILDE_SIZE_CHANGED));
|
||||
});
|
||||
|
||||
@@ -936,10 +1058,39 @@ void MainFrame::update_layout()
|
||||
Thaw();
|
||||
}
|
||||
|
||||
#ifdef __WXGTK__
|
||||
void MainFrame::update_edge_panels()
|
||||
{
|
||||
if (!m_edge_bottom) return;
|
||||
|
||||
bool hide = IsMaximized() || IsFullScreen();
|
||||
m_edge_bottom->Show(!hide);
|
||||
m_edge_left->Show(!hide);
|
||||
m_edge_right->Show(!hide);
|
||||
if (hide) return;
|
||||
|
||||
constexpr int B = ResizeEdgePanel::BORDER_PX;
|
||||
wxSize cs = GetClientSize();
|
||||
m_edge_bottom->SetSize(0, cs.y - B, cs.x, B);
|
||||
m_edge_left->SetSize(0, 0, B, cs.y);
|
||||
m_edge_right->SetSize(cs.x - B, 0, B, cs.y);
|
||||
|
||||
m_edge_bottom->Raise();
|
||||
m_edge_left->Raise();
|
||||
m_edge_right->Raise();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Called when closing the application and when switching the application language.
|
||||
void MainFrame::shutdown()
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "MainFrame::shutdown enter";
|
||||
#ifdef __WXGTK__
|
||||
// Edge panels are child windows — wxWidgets destroys them automatically.
|
||||
m_edge_bottom = nullptr;
|
||||
m_edge_left = nullptr;
|
||||
m_edge_right = nullptr;
|
||||
#endif
|
||||
// BBS: backup
|
||||
Slic3r::set_backup_callback(nullptr);
|
||||
#ifdef _WIN32
|
||||
@@ -1699,7 +1850,9 @@ wxBoxSizer* MainFrame::create_side_tools()
|
||||
|
||||
auto curr_plate = m_plater->get_partplate_list().get_curr_plate();
|
||||
#ifdef __linux__
|
||||
slice = try_pop_up_before_slice(m_slice_select == eSliceAll, m_plater, curr_plate, true);
|
||||
PresetBundle* preset = wxGetApp().preset_bundle;
|
||||
bool force_show_fila_group_dlg = (preset && preset->is_bbl_vendor() && preset->get_printer_extruder_count() == 2);
|
||||
slice = try_pop_up_before_slice(m_slice_select == eSliceAll, m_plater, curr_plate, force_show_fila_group_dlg);
|
||||
#else
|
||||
slice = try_pop_up_before_slice(m_slice_select == eSliceAll, m_plater, curr_plate, false);
|
||||
#endif
|
||||
@@ -2828,6 +2981,14 @@ void MainFrame::init_menubar_as_editor()
|
||||
this, [this]() { return m_tabpanel->GetSelection() == TabPosition::tp3DEditor || m_tabpanel->GetSelection() == TabPosition::tpPreview; },
|
||||
[this]() { return wxGetApp().show_3d_navigator(); }, this);
|
||||
|
||||
append_menu_check_item(viewMenu, wxID_ANY, _L("Show Gridlines"), _L("Show Gridlines on plate"),
|
||||
[this](wxCommandEvent&) {
|
||||
wxGetApp().toggle_show_plate_gridlines();
|
||||
m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT));
|
||||
}, this,
|
||||
[this]() { return m_tabpanel->GetSelection() == TabPosition::tp3DEditor || m_tabpanel->GetSelection() == TabPosition::tpPreview; },
|
||||
[this]() { return wxGetApp().show_plate_gridlines(); }, this);
|
||||
|
||||
append_menu_item(
|
||||
viewMenu, wxID_ANY, _L("Reset Window Layout"), _L("Reset to default window layout"),
|
||||
[this](wxCommandEvent&) { m_plater->reset_window_layout(); }, "", this,
|
||||
|
||||
@@ -52,6 +52,9 @@ class PrintHostQueueDialog;
|
||||
class Plater;
|
||||
class MainFrame;
|
||||
class ParamsDialog;
|
||||
#ifdef __WXGTK__
|
||||
class ResizeEdgePanel;
|
||||
#endif
|
||||
|
||||
enum QuickSlice
|
||||
{
|
||||
@@ -422,6 +425,14 @@ public:
|
||||
uint32_t m_ulSHChangeNotifyRegister { 0 };
|
||||
static constexpr int WM_USER_MEDIACHANGED { 0x7FFF }; // WM_USER from 0x0400 to 0x7FFF, picking the last one to not interfere with wxWidgets allocation
|
||||
#endif // _WIN32
|
||||
|
||||
#ifdef __WXGTK__
|
||||
friend class ResizeEdgePanel;
|
||||
ResizeEdgePanel* m_edge_bottom{nullptr};
|
||||
ResizeEdgePanel* m_edge_left{nullptr};
|
||||
ResizeEdgePanel* m_edge_right{nullptr};
|
||||
void update_edge_panels();
|
||||
#endif // __WXGTK__
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(EVT_HTTP_ERROR, wxCommandEvent);
|
||||
|
||||
@@ -68,7 +68,7 @@ AddMachinePanel::AddMachinePanel(wxWindow* parent, wxWindowID id, const wxPoint&
|
||||
m_button_add_machine->SetBorderColor(0x909090);
|
||||
m_button_add_machine->SetMinSize(wxSize(96, 39));
|
||||
btn_sizer->Add(m_button_add_machine, 0, wxALL | wxALIGN_CENTER_HORIZONTAL, 5);
|
||||
m_staticText_add_machine = new wxStaticText(this, wxID_ANY, wxT("click to add machine"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_staticText_add_machine = new wxStaticText(this, wxID_ANY, _L("click to add machine"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_staticText_add_machine->Wrap(-1);
|
||||
m_staticText_add_machine->SetForegroundColour(0x909090);
|
||||
btn_sizer->Add(m_staticText_add_machine, 0, wxALL | wxALIGN_CENTER_HORIZONTAL, 5);
|
||||
@@ -200,7 +200,7 @@ void MonitorPanel::init_tabpanel()
|
||||
|
||||
std::string network_ver = Slic3r::NetworkAgent::get_version();
|
||||
if (!network_ver.empty()) {
|
||||
m_tabpanel->SetFooterText(wxString::Format("Network plugin v%s", network_ver));
|
||||
m_tabpanel->SetFooterText(wxString::Format(_L("Network plug-in v%s"), network_ver));
|
||||
}
|
||||
|
||||
m_initialized = true;
|
||||
@@ -543,9 +543,9 @@ void MonitorPanel::update_network_version_footer()
|
||||
|
||||
wxString footer_text;
|
||||
if (!suffix.empty() && configured_base == binary_version) {
|
||||
footer_text = wxString::Format("Network plugin v%s (%s)", binary_version, suffix);
|
||||
footer_text = wxString::Format(_L("Network plug-in v%s (%s)"), binary_version, suffix);
|
||||
} else {
|
||||
footer_text = wxString::Format("Network plugin v%s", binary_version);
|
||||
footer_text = wxString::Format(_L("Network plug-in v%s"), binary_version);
|
||||
}
|
||||
|
||||
m_tabpanel->SetFooterText(footer_text);
|
||||
|
||||
@@ -147,7 +147,7 @@ wxString DeviceItem::get_state_printable()
|
||||
str_state_printable.push_back(_L("Printing"));
|
||||
str_state_printable.push_back(_L("Upgrading"));
|
||||
str_state_printable.push_back(_L("Incompatible"));
|
||||
str_state_printable.push_back(_L("syncing"));
|
||||
str_state_printable.push_back(_L("Syncing"));
|
||||
|
||||
return str_state_printable[state_printable];
|
||||
}
|
||||
@@ -163,7 +163,7 @@ wxString DeviceItem::get_state_device()
|
||||
str_state_device.push_back(_L("Printing Pause"));
|
||||
str_state_device.push_back(_L("Prepare"));
|
||||
str_state_device.push_back(_L("Slicing"));
|
||||
str_state_device.push_back(_L("syncing"));
|
||||
str_state_device.push_back(_L("Syncing"));
|
||||
|
||||
return str_state_device[state_device];
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ NetworkPluginDownloadDialog::NetworkPluginDownloadDialog(wxWindow* parent, Mode
|
||||
const std::string& error_message,
|
||||
const std::string& error_details)
|
||||
: DPIDialog(parent, wxID_ANY, mode == Mode::UpdateAvailable ?
|
||||
_L("Network Plugin Update Available") : _L("Bambu Network Plugin Required"),
|
||||
_L("Network Plug-in Update Available") : _L("Bambu Network Plug-in Required"),
|
||||
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
|
||||
, m_mode(mode)
|
||||
, m_error_message(error_message)
|
||||
@@ -54,8 +54,8 @@ void NetworkPluginDownloadDialog::create_missing_plugin_ui()
|
||||
|
||||
auto* desc = new wxStaticText(this, wxID_ANY,
|
||||
m_mode == Mode::CorruptedPlugin ?
|
||||
_L("The Bambu Network Plugin is corrupted or incompatible. Please reinstall it.") :
|
||||
_L("The Bambu Network Plugin is required for cloud features, printer discovery, and remote printing."));
|
||||
_L("The Bambu Network Plug-in is corrupted or incompatible. Please reinstall it.") :
|
||||
_L("The Bambu Network Plug-in is required for cloud features, printer discovery, and remote printing."));
|
||||
desc->SetFont(::Label::Body_13);
|
||||
desc->Wrap(FromDIP(400));
|
||||
main_sizer->Add(desc, 0, wxLEFT | wxRIGHT, FromDIP(25));
|
||||
@@ -134,7 +134,7 @@ void NetworkPluginDownloadDialog::create_update_available_ui(const std::string&
|
||||
wxBoxSizer* main_sizer = static_cast<wxBoxSizer*>(GetSizer());
|
||||
|
||||
auto* desc = new wxStaticText(this, wxID_ANY,
|
||||
_L("A new version of the Bambu Network Plugin is available."));
|
||||
_L("A new version of the Bambu Network Plug-in is available."));
|
||||
desc->SetFont(::Label::Body_13);
|
||||
desc->Wrap(FromDIP(400));
|
||||
main_sizer->Add(desc, 0, wxLEFT | wxRIGHT, FromDIP(25));
|
||||
@@ -305,14 +305,14 @@ NetworkPluginRestartDialog::NetworkPluginRestartDialog(wxWindow* parent)
|
||||
auto* text_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
auto* desc = new wxStaticText(this, wxID_ANY,
|
||||
_L("The Bambu Network Plugin has been installed successfully."));
|
||||
_L("The Bambu Network Plug-in has been installed successfully."));
|
||||
desc->SetFont(::Label::Body_14);
|
||||
desc->Wrap(FromDIP(350));
|
||||
text_sizer->Add(desc, 0, wxTOP, FromDIP(10));
|
||||
text_sizer->Add(0, 0, 0, wxTOP, FromDIP(10));
|
||||
|
||||
auto* restart_msg = new wxStaticText(this, wxID_ANY,
|
||||
_L("A restart is required to load the new plugin. Would you like to restart now?"));
|
||||
_L("A restart is required to load the new plug-in. Would you like to restart now?"));
|
||||
restart_msg->SetFont(::Label::Body_13);
|
||||
restart_msg->Wrap(FromDIP(350));
|
||||
text_sizer->Add(restart_msg, 0, wxBOTTOM, FromDIP(10));
|
||||
|
||||
@@ -322,6 +322,13 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
|
||||
render_minimize_button(imgui, win_pos.x, win_pos.y);
|
||||
render_close_button(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y); // ORCA draw it after minimize button since its position related to minimize button
|
||||
}
|
||||
|
||||
const bool gcode_window_visible = canvas.get_canvas_type() == GLCanvas3D::ECanvasType::CanvasPreview && wxGetApp().show_gcode_window();
|
||||
if (!gcode_window_visible)
|
||||
{
|
||||
ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow());
|
||||
}
|
||||
|
||||
imgui.end();
|
||||
|
||||
restore_default_theme();
|
||||
|
||||
@@ -48,14 +48,7 @@ wxBoxSizer* ObjColorDialog::create_btn_sizer(long flags,bool exist_error)
|
||||
if (!exist_error) {
|
||||
btn_sizer->AddSpacer(FromDIP(25));
|
||||
auto *tips = new HyperLink(this, _L("Wiki Guide")); // ORCA
|
||||
tips->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) {
|
||||
bool is_zh = wxGetApp().app_config->get("language") == "zh_CN";
|
||||
if (is_zh) {
|
||||
wxLaunchDefaultBrowser("https://wiki.bambulab.com/zh/software/bambu-studio/import_obj");
|
||||
} else {
|
||||
wxLaunchDefaultBrowser("https://wiki.bambulab.com/en/software/bambu-studio/import_obj");
|
||||
}
|
||||
});
|
||||
tips->SetURL("https://www.orcaslicer.com/wiki/general-settings/import_export.html#obj");
|
||||
btn_sizer->Add(tips, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
|
||||
}
|
||||
btn_sizer->AddStretchSpacer();
|
||||
@@ -924,7 +917,7 @@ wxBoxSizer *ObjColorPanel::create_color_icon_map_rgba_sizer(wxWindow *parent, in
|
||||
icon_sizer->Add(icon, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0); // wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM
|
||||
icon_sizer->AddSpacer(FromDIP(10));
|
||||
|
||||
wxStaticText *map_text = new wxStaticText(parent, wxID_ANY, u8"—> ");
|
||||
wxStaticText *map_text = new wxStaticText(parent, wxID_ANY, _L(u8"—> "));
|
||||
map_text->SetFont(Label::Head_12);
|
||||
icon_sizer->Add(map_text, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0);
|
||||
|
||||
|
||||
@@ -25,6 +25,18 @@
|
||||
#include "../Utils/MacDarkMode.hpp"
|
||||
#endif // __APPLE__
|
||||
|
||||
// Verify GLEW and wxWidgets use the same OpenGL backend (EGL vs GLX).
|
||||
// A mismatch causes rendering failures: GLEW's function loading must match
|
||||
// the context type created by wxWidgets.
|
||||
#if defined(__linux__)
|
||||
#if defined(GLEW_EGL) && (!defined(wxUSE_GLCANVAS_EGL) || !wxUSE_GLCANVAS_EGL)
|
||||
#error "OpenGL backend mismatch: GLEW has EGL support enabled but wxWidgets does not. Ensure GLEW_USE_EGL and wxUSE_GLCANVAS_EGL are both ON or both OFF."
|
||||
#endif
|
||||
#if !defined(GLEW_EGL) && defined(wxUSE_GLCANVAS_EGL) && wxUSE_GLCANVAS_EGL
|
||||
#error "OpenGL backend mismatch: wxWidgets has EGL support enabled but GLEW does not. Ensure GLEW_USE_EGL and wxUSE_GLCANVAS_EGL are both ON or both OFF."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
||||
@@ -594,11 +594,12 @@ void OptionsGroup::clear(bool destroy_custom_ctrl)
|
||||
|
||||
Line OptionsGroup::create_single_option_line(const Option& option, const std::string& path/* = std::string()*/) const
|
||||
{
|
||||
wxString tooltip = _(option.opt.tooltip);
|
||||
edit_tooltip(tooltip);
|
||||
wxString tooltip = _(get_formatted_tooltip_text(option.opt, option.opt_id));
|
||||
|
||||
Line retval{ _(option.opt.label), tooltip };
|
||||
retval.label_path = path;
|
||||
retval.append_option(option);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@@ -1485,7 +1485,12 @@ void PartPlate::register_raycasters_for_picking(GLCanvas3D &canvas)
|
||||
canvas.remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id_component(6));
|
||||
register_model_for_picking(canvas, m_plate_name_edit_icon, picking_id_component(6));
|
||||
register_model_for_picking(canvas, m_move_front_icon, picking_id_component(7));
|
||||
register_model_for_picking(canvas, m_plate_filament_map_icon, picking_id_component(PLATE_FILAMENT_MAP_ID));
|
||||
|
||||
// Only register filament map button for H2D (dual-extruder Bambu Lab) printers
|
||||
PresetBundle* preset = wxGetApp().preset_bundle;
|
||||
bool dual_bbl = (preset && preset->is_bbl_vendor() && preset->get_printer_extruder_count() == 2);
|
||||
if (dual_bbl)
|
||||
register_model_for_picking(canvas, m_plate_filament_map_icon, picking_id_component(PLATE_FILAMENT_MAP_ID));
|
||||
}
|
||||
|
||||
int PartPlate::picking_id_component(int idx) const
|
||||
@@ -3241,7 +3246,7 @@ void PartPlate::render(const Transform3d& view_matrix, const Transform3d& projec
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
if (show_grid)
|
||||
if (wxGetApp().show_plate_gridlines() && show_grid)
|
||||
render_grid(bottom);
|
||||
|
||||
if (!bottom && m_selected && !force_background_color) {
|
||||
|
||||
+59
-20
@@ -469,6 +469,7 @@ struct Sidebar::priv
|
||||
ScalableButton * m_bpButton_ams_filament;
|
||||
ScalableButton * m_bpButton_set_filament;
|
||||
int m_menu_filament_id = -1;
|
||||
int filament_area_height;
|
||||
wxScrolledWindow* m_panel_filament_content;
|
||||
wxScrolledWindow* m_scrolledWindow_filament_content;
|
||||
wxStaticLine* m_staticline2;
|
||||
@@ -1236,6 +1237,18 @@ bool Sidebar::priv::switch_diameter(bool single)
|
||||
diameter = diameter_left;
|
||||
}
|
||||
}
|
||||
|
||||
// ORCA: Check if the selected diameter matches the current nozzle diameter in the config
|
||||
Preset& printer_preset = wxGetApp().preset_bundle->printers.get_edited_preset();
|
||||
auto* nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(printer_preset.config.option("nozzle_diameter"));
|
||||
if (nozzle_diameter && nozzle_diameter->size() > 0) {
|
||||
auto current_nozzle_dia = get_diameter_string(nozzle_diameter->values[0]);
|
||||
// If the selected diameter is the same as current nozzle, don't switch profiles
|
||||
if (current_nozzle_dia == diameter.ToStdString()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
auto preset = wxGetApp().preset_bundle->get_similar_printer_preset({}, diameter.ToStdString());
|
||||
if (preset == nullptr) {
|
||||
// ORCA add a text. this appears when user tries to change nozzle value but config doesnt have a inherited or compatible preset
|
||||
@@ -2093,10 +2106,14 @@ Sidebar::Sidebar(Plater *parent)
|
||||
bSizer39->AddSpacer(FromDIP(SidebarProps::TitlebarMargin()));
|
||||
|
||||
// add filament content
|
||||
// ORCA use a height with user preference
|
||||
int filament_count_user = std::stoi(wxGetApp().app_config->get("filaments_area_preferred_count"));
|
||||
p->filament_area_height = std::ceil(filament_count_user * 0.5) * (30 + SidebarProps::ElementSpacing()) - SidebarProps::ElementSpacing();
|
||||
|
||||
p->m_panel_filament_content = new wxScrolledWindow( p->scrolled, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
|
||||
p->m_panel_filament_content->SetScrollbars(0, 100, 1, 2);
|
||||
p->m_panel_filament_content->SetScrollRate(0, 5);
|
||||
p->m_panel_filament_content->SetMaxSize(wxSize{-1, FromDIP(174)});
|
||||
p->m_panel_filament_content->SetMaxSize(wxSize{-1, FromDIP(p->filament_area_height)}); // ORCA
|
||||
p->m_panel_filament_content->SetBackgroundColour(wxColour(255, 255, 255));
|
||||
|
||||
//wxBoxSizer* bSizer_filament_content;
|
||||
@@ -2563,22 +2580,23 @@ void Sidebar::update_presets(Preset::Type preset_type)
|
||||
auto update_extruder_diameter = [&diameters, &diameter, &nozzle_diameter](int extruder_index,ExtruderGroup & extruder) {
|
||||
extruder.combo_diameter->Clear();
|
||||
int select = -1;
|
||||
// ORCA if user defined a custom nozzle in printer config select it instead inherited one. this will show correct nozzle diameter in combobox if its exist in nozzle diameters list
|
||||
// ORCA get the actual nozzle diameter from printer config
|
||||
auto nozzle_dia = get_diameter_string(nozzle_diameter->values[extruder_index]);
|
||||
if(nozzle_dia != diameter && std::find(diameters.begin(), diameters.end(), nozzle_dia) != diameters.end())
|
||||
diameter = nozzle_dia;
|
||||
// ORCA try to add nozzle diameter from config if list is empty. fixes blank nozzle combo box when preset has no alias
|
||||
if(diameters[0].empty() && !nozzle_dia.empty()){
|
||||
diameters[0] = nozzle_dia;
|
||||
diameter = nozzle_dia;
|
||||
}
|
||||
// Orca: Check if the actual nozzle diameter exists in the list, if not add it as a custom option
|
||||
if (std::find(diameters.begin(), diameters.end(), nozzle_dia) == diameters.end() && !nozzle_dia.empty()) {
|
||||
diameters.push_back(nozzle_dia);
|
||||
}
|
||||
for (size_t i = 0; i < diameters.size(); ++i) {
|
||||
if (diameters[i] == diameter)
|
||||
if (diameters[i] == nozzle_dia)
|
||||
select = extruder.combo_diameter->GetCount();
|
||||
extruder.combo_diameter->Append(diameters[i], {});
|
||||
}
|
||||
extruder.combo_diameter->SetSelection(select);
|
||||
extruder.diameter = diameter;
|
||||
extruder.diameter = nozzle_dia;
|
||||
};
|
||||
auto image_path = get_cur_select_bed_image();
|
||||
if (is_dual_extruder) {
|
||||
@@ -3506,7 +3524,7 @@ void Sidebar::sync_ams_list(bool is_from_big_sync_btn)
|
||||
for (auto& c : p->combos_filament)
|
||||
c->update();
|
||||
// Expand filament list
|
||||
p->m_panel_filament_content->SetMaxSize({-1, FromDIP(174)});
|
||||
p->m_panel_filament_content->SetMaxSize({-1, FromDIP(p->filament_area_height)}); // ORCA
|
||||
auto min_size = p->m_panel_filament_content->GetSizer()->GetMinSize();
|
||||
if (min_size.y > p->m_panel_filament_content->GetMaxHeight())
|
||||
min_size.y = p->m_panel_filament_content->GetMaxHeight();
|
||||
@@ -4642,6 +4660,7 @@ struct Plater::priv
|
||||
bool can_layers_editing() const;
|
||||
bool can_fix_through_netfabb() const;
|
||||
bool can_simplify() const;
|
||||
bool can_smooth_mesh() const;
|
||||
bool can_set_instance_to_object() const;
|
||||
bool can_mirror() const;
|
||||
bool can_reload_from_disk() const;
|
||||
@@ -10081,7 +10100,7 @@ void Plater::priv::update_plugin_when_launch(wxCommandEvent &event)
|
||||
|
||||
void Plater::priv::show_install_plugin_hint(wxCommandEvent &event)
|
||||
{
|
||||
notification_manager->bbl_show_plugin_install_notification(into_u8(_L("Network Plug-in is not detected. Network related features are unavailable.")));
|
||||
notification_manager->bbl_show_plugin_install_notification(into_u8(_L("The network plug-in was not detected. Network related features are unavailable.")));
|
||||
}
|
||||
|
||||
void Plater::priv::show_preview_only_hint(wxCommandEvent &event)
|
||||
@@ -10400,13 +10419,13 @@ void Plater::priv::set_project_name(const wxString& project_name)
|
||||
m_project_name = project_name;
|
||||
wxString name = project_name + " - OrcaSlicer-ZAA";
|
||||
//update topbar title
|
||||
#ifdef __WINDOWS__
|
||||
wxGetApp().mainframe->SetTitle(name);
|
||||
wxGetApp().mainframe->topbar()->SetTitle(name);
|
||||
#else
|
||||
wxGetApp().mainframe->SetTitle(name);
|
||||
#ifdef __APPLE__
|
||||
wxGetApp().mainframe->SetTitle(m_project_name);
|
||||
if (!m_project_name.IsEmpty())
|
||||
wxGetApp().mainframe->update_title_colour_after_set_title();
|
||||
#else
|
||||
wxGetApp().mainframe->SetTitle(m_project_name + " - OrcaSlicer");
|
||||
wxGetApp().mainframe->topbar()->SetTitle(m_project_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -10421,11 +10440,12 @@ void Plater::priv::update_title_dirty_status()
|
||||
else
|
||||
title = m_project_name;
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
wxGetApp().mainframe->topbar()->SetTitle(title);
|
||||
#ifdef __APPLE__
|
||||
wxGetApp().mainframe->SetTitle(title);
|
||||
wxGetApp().mainframe->update_title_colour_after_set_title();
|
||||
#else
|
||||
wxGetApp().mainframe->SetTitle(title);
|
||||
wxGetApp().mainframe->update_title_colour_after_set_title();
|
||||
wxGetApp().mainframe->topbar()->SetTitle(title);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -10664,7 +10684,7 @@ bool Plater::priv::check_ams_status_impl(bool is_slice_all)
|
||||
: MessageDialog(parent,
|
||||
_L("The nozzle type and AMS quantity information has not been synced from the connected printer.\n"
|
||||
"After syncing, software can optimize printing time and filament usage when slicing.\n"
|
||||
"Would you like to sync now ?"),
|
||||
"Would you like to sync now?"),
|
||||
_L("Warning"), 0)
|
||||
{
|
||||
add_button(wxID_YES, true, _L("Sync now"));
|
||||
@@ -11038,6 +11058,24 @@ bool Plater::priv::can_simplify() const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Plater::priv::can_smooth_mesh() const
|
||||
{
|
||||
std::vector<int> obj_idxs, vol_idxs;
|
||||
sidebar->obj_list()->get_selection_indexes(obj_idxs, vol_idxs);
|
||||
if (vol_idxs.empty()) {
|
||||
for (auto obj_idx : obj_idxs)
|
||||
if (model.objects[obj_idx]->get_object_stl_stats().open_edges > 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int obj_idx = obj_idxs.front();
|
||||
for (auto vol_idx : vol_idxs)
|
||||
if (model.objects[obj_idx]->get_object_stl_stats().open_edges > 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Plater::priv::can_increase_instances() const
|
||||
{
|
||||
if (!m_worker.is_idle()
|
||||
@@ -11914,7 +11952,7 @@ void Plater::import_model_id(wxString download_info)
|
||||
int res = 0;
|
||||
std::string http_body;
|
||||
|
||||
msg = _L("prepare 3MF file...");
|
||||
msg = _L("Preparing 3MF file...");
|
||||
|
||||
//gets the number of files with the same name
|
||||
std::vector<wxString> vecFiles;
|
||||
@@ -11963,7 +12001,7 @@ void Plater::import_model_id(wxString download_info)
|
||||
}
|
||||
|
||||
|
||||
msg = _L("downloading project...");
|
||||
msg = _L("Downloading project...");
|
||||
|
||||
//target_path = wxStandardPaths::Get().GetTempDir().utf8_str().data();
|
||||
|
||||
@@ -17930,6 +17968,7 @@ bool Plater::can_decrease_instances() const { return p->can_decrease_instances()
|
||||
bool Plater::can_set_instance_to_object() const { return p->can_set_instance_to_object(); }
|
||||
bool Plater::can_fix_through_netfabb() const { return p->can_fix_through_netfabb(); }
|
||||
bool Plater::can_simplify() const { return p->can_simplify(); }
|
||||
bool Plater::can_smooth_mesh() const { return p->can_smooth_mesh(); }
|
||||
bool Plater::can_split_to_objects() const { return p->can_split_to_objects(); }
|
||||
bool Plater::can_split_to_volumes() const { return p->can_split_to_volumes(); }
|
||||
bool Plater::can_arrange() const { return p->can_arrange(); }
|
||||
|
||||
@@ -662,6 +662,7 @@ public:
|
||||
bool can_set_instance_to_object() const;
|
||||
bool can_fix_through_netfabb() const;
|
||||
bool can_simplify() const;
|
||||
bool can_smooth_mesh() const;
|
||||
bool can_split_to_objects() const;
|
||||
bool can_split_to_volumes() const;
|
||||
bool can_arrange() const;
|
||||
|
||||
@@ -558,6 +558,50 @@ wxBoxSizer *PreferencesDialog::create_item_input(wxString title, wxString title2
|
||||
return sizer_input;
|
||||
}
|
||||
|
||||
wxBoxSizer *PreferencesDialog::create_item_spinctrl(wxString title, wxString title2, wxString side_label, wxString tooltip, std::string param, int min, int max, std::function<void(int)> onchange)
|
||||
{
|
||||
wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
auto label = new wxStaticText(m_parent, wxID_ANY, title, wxDefaultPosition, DESIGN_TITLE_SIZE, wxST_NO_AUTORESIZE);
|
||||
label->SetForegroundColour(DESIGN_GRAY900_COLOR);
|
||||
label->SetFont(::Label::Body_14);
|
||||
label->SetToolTip(tooltip);
|
||||
label->Wrap(DESIGN_TITLE_SIZE.x);
|
||||
label->Wrap(DESIGN_TITLE_SIZE.x);
|
||||
|
||||
auto input = new SpinInput(m_parent, wxEmptyString, side_label, wxDefaultPosition, DESIGN_INPUT_SIZE, wxSP_ARROW_KEYS, min, max, stoi(app_config->get(param)));
|
||||
input->SetToolTip(tooltip);
|
||||
|
||||
sizer->AddSpacer(FromDIP(DESIGN_LEFT_MARGIN));
|
||||
sizer->Add(label, 0, wxALIGN_CENTER_VERTICAL);
|
||||
sizer->Add(input, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(5));
|
||||
|
||||
if(!title2.empty()){
|
||||
auto second_title = new wxStaticText(m_parent, wxID_ANY, title2, wxDefaultPosition, wxDefaultSize, 0);
|
||||
second_title->SetForegroundColour(DESIGN_GRAY900_COLOR);
|
||||
second_title->SetFont(::Label::Body_14);
|
||||
second_title->SetToolTip(tooltip);
|
||||
sizer->Add(second_title, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(5));
|
||||
}
|
||||
|
||||
input->Bind(wxEVT_TEXT_ENTER, [this, param, input, onchange](wxCommandEvent& e) {
|
||||
auto value = input->GetValue();
|
||||
app_config->set(param, std::to_string(value));
|
||||
app_config->save();
|
||||
if (onchange != nullptr) onchange(value);
|
||||
e.Skip();
|
||||
});
|
||||
|
||||
input->Bind(wxEVT_KILL_FOCUS, [this, param, input, onchange](wxFocusEvent &e) {
|
||||
auto value = input->GetValue();
|
||||
app_config->set(param, std::to_string(value));
|
||||
if (onchange != nullptr) onchange(value);
|
||||
e.Skip();
|
||||
});
|
||||
|
||||
return sizer;
|
||||
}
|
||||
|
||||
wxBoxSizer *PreferencesDialog::create_camera_orbit_mult_input(wxString title, wxString tooltip)
|
||||
{
|
||||
wxBoxSizer *sizer_input = new wxBoxSizer(wxHORIZONTAL);
|
||||
@@ -1354,6 +1398,9 @@ void PreferencesDialog::create_items()
|
||||
"group_filament_presets", {_L("All"), _L("None"), _L("By type"), _L("By vendor")}, [](wxString value) {wxGetApp().plater()->sidebar().update_presets(Preset::TYPE_FILAMENT);});
|
||||
g_sizer->Add(item_filament_preset_grouping);
|
||||
|
||||
auto item_filament_area_height = create_item_spinctrl(_L("Optimize filaments area height for..."), _L("(Requires restart)"), _L("filaments"), _L("Optimizes filament area maximum height by chosen filament count."), "filaments_area_preferred_count", 8, 99);
|
||||
g_sizer->Add(item_filament_area_height);
|
||||
|
||||
//// GENERAL > Features
|
||||
g_sizer->Add(create_item_title(_L("Features")), 1, wxEXPAND);
|
||||
|
||||
@@ -1503,18 +1550,18 @@ void PreferencesDialog::create_items()
|
||||
g_sizer->Add(item_filament_sync_mode);
|
||||
|
||||
//// ONLINE > Network plugin
|
||||
g_sizer->Add(create_item_title(_L("Network plugin")), 1, wxEXPAND);
|
||||
g_sizer->Add(create_item_title(_L("Network plug-in")), 1, wxEXPAND);
|
||||
|
||||
auto item_enable_plugin = create_item_checkbox(_L("Enable network plugin"), "", "installed_networking");
|
||||
auto item_enable_plugin = create_item_checkbox(_L("Enable network plug-in"), "", "installed_networking");
|
||||
g_sizer->Add(item_enable_plugin);
|
||||
|
||||
m_network_version_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_network_version_sizer->AddSpacer(FromDIP(DESIGN_LEFT_MARGIN));
|
||||
|
||||
auto version_title = new wxStaticText(m_parent, wxID_ANY, _L("Network plugin version"), wxDefaultPosition, DESIGN_TITLE_SIZE, wxST_NO_AUTORESIZE);
|
||||
auto version_title = new wxStaticText(m_parent, wxID_ANY, _L("Network plug-in version"), wxDefaultPosition, DESIGN_TITLE_SIZE, wxST_NO_AUTORESIZE);
|
||||
version_title->SetForegroundColour(DESIGN_GRAY900_COLOR);
|
||||
version_title->SetFont(::Label::Body_14);
|
||||
version_title->SetToolTip(_L("Select the network plugin version to use"));
|
||||
version_title->SetToolTip(_L("Select the network plug-in version to use"));
|
||||
version_title->Wrap(DESIGN_TITLE_SIZE.x);
|
||||
m_network_version_sizer->Add(version_title, 0, wxALIGN_CENTER);
|
||||
|
||||
@@ -1591,20 +1638,20 @@ void PreferencesDialog::create_items()
|
||||
if (Slic3r::NetworkAgent::versioned_library_exists(new_version)) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Version " << new_version << " already exists on disk, triggering hot reload";
|
||||
if (wxGetApp().hot_reload_network_plugin()) {
|
||||
MessageDialog dlg(this, _L("Network plugin switched successfully."), _L("Success"), wxOK | wxICON_INFORMATION);
|
||||
MessageDialog dlg(this, _L("Network plug-in switched successfully."), _L("Success"), wxOK | wxICON_INFORMATION);
|
||||
dlg.ShowModal();
|
||||
} else {
|
||||
MessageDialog dlg(this, _L("Failed to load network plugin. Please restart the application."), _L("Restart Required"), wxOK | wxICON_WARNING);
|
||||
MessageDialog dlg(this, _L("Failed to load network plug-in. Please restart the application."), _L("Restart Required"), wxOK | wxICON_WARNING);
|
||||
dlg.ShowModal();
|
||||
}
|
||||
} else {
|
||||
wxString msg = wxString::Format(
|
||||
_L("You've selected network plugin version %s.\n\nWould you like to download and install this version now?\n\nNote: The application may need to restart after installation."),
|
||||
_L("You've selected network plug-in version %s.\n\nWould you like to download and install this version now?\n\nNote: The application may need to restart after installation."),
|
||||
wxString::FromUTF8(new_version));
|
||||
|
||||
MessageDialog dlg(this, msg, _L("Download Network Plugin"), wxYES_NO | wxICON_QUESTION);
|
||||
MessageDialog dlg(this, msg, _L("Download Network Plug-in"), wxYES_NO | wxICON_QUESTION);
|
||||
if (dlg.ShowModal() == wxID_YES) {
|
||||
DownloadProgressDialog progress_dlg(_L("Downloading Network Plugin"));
|
||||
DownloadProgressDialog progress_dlg(_L("Downloading Network Plug-in"));
|
||||
progress_dlg.ShowModal();
|
||||
}
|
||||
}
|
||||
@@ -1684,13 +1731,13 @@ void PreferencesDialog::create_items()
|
||||
auto loglevel_combox = create_item_loglevel_combobox(_L("Log Level"), _L("Log Level"), log_level_list);
|
||||
g_sizer->Add(loglevel_combox);
|
||||
|
||||
g_sizer->Add(create_item_title(_L("Network Plugin")), 1, wxEXPAND);
|
||||
auto item_reload_plugin = create_item_button(_L("Network plugin"), _L("Reload"), _L("Reload the network plugin without restarting the application"), "", [this]() {
|
||||
g_sizer->Add(create_item_title(_L("Network plug-in")), 1, wxEXPAND);
|
||||
auto item_reload_plugin = create_item_button(_L("Network plug-in"), _L("Reload"), _L("Reload the network plug-in without restarting the application"), "", [this]() {
|
||||
if (wxGetApp().hot_reload_network_plugin()) {
|
||||
MessageDialog dlg(this, _L("Network plugin reloaded successfully."), _L("Reload"), wxOK | wxICON_INFORMATION);
|
||||
MessageDialog dlg(this, _L("Network plug-in reloaded successfully."), _L("Reload"), wxOK | wxICON_INFORMATION);
|
||||
dlg.ShowModal();
|
||||
} else {
|
||||
MessageDialog dlg(this, _L("Failed to reload network plugin. Please restart the application."), _L("Reload Failed"), wxOK | wxICON_ERROR);
|
||||
MessageDialog dlg(this, _L("Failed to reload network plug-in. Please restart the application."), _L("Reload Failed"), wxOK | wxICON_ERROR);
|
||||
dlg.ShowModal();
|
||||
}
|
||||
});
|
||||
@@ -1755,10 +1802,10 @@ void PreferencesDialog::create_shortcuts_page()
|
||||
std::vector<wxString> mouse_supported;
|
||||
Split(app_config->get("mouse_supported"), "/", mouse_supported);
|
||||
|
||||
auto item_rotate_view = create_item_multiple_combobox(_L("Rotate of view"), _L("Rotate of view"), "rotate_view", keyboard_supported,
|
||||
auto item_rotate_view = create_item_multiple_combobox(_L("Rotate view"), _L("Rotate view"), "rotate_view", keyboard_supported,
|
||||
mouse_supported);
|
||||
auto item_move_view = create_item_multiple_combobox(_L("Move of view"), _L("Move of view"), "move_view", keyboard_supported, mouse_supported);
|
||||
auto item_zoom_view = create_item_multiple_combobox(_L("Zoom of view"), _L("Zoom of view"), "rotate_view", keyboard_supported, mouse_supported);
|
||||
auto item_move_view = create_item_multiple_combobox(_L("Pan view"), _L("Pan view"), "move_view", keyboard_supported, mouse_supported);
|
||||
auto item_zoom_view = create_item_multiple_combobox(_L("Zoom view"), _L("Zoom view"), "rotate_view", keyboard_supported, mouse_supported);
|
||||
|
||||
auto title_other = create_item_title(_L("Other"));
|
||||
auto item_other = create_item_checkbox(_L("Mouse wheel reverses when zooming"), _L("Mouse wheel reverses when zooming"), "mouse_wheel");
|
||||
@@ -1812,12 +1859,12 @@ wxBoxSizer* PreferencesDialog::create_debug_page()
|
||||
radio_group->SetSelection(3);
|
||||
}
|
||||
|
||||
Button* debug_button = new Button(m_parent, _L("debug save button"));
|
||||
Button* debug_button = new Button(m_parent, _L("Debug save button"));
|
||||
debug_button->SetStyle(ButtonStyle::Confirm, ButtonType::Window);
|
||||
|
||||
debug_button->Bind(wxEVT_LEFT_DOWN, [this, radio_group](wxMouseEvent &e) {
|
||||
// success message box
|
||||
MessageDialog dialog(this, _L("save debug settings"), _L("DEBUG settings have been saved successfully!"), wxNO_DEFAULT | wxYES_NO | wxICON_INFORMATION);
|
||||
MessageDialog dialog(this, _L("Save debug settings"), _L("DEBUG settings have been saved successfully!"), wxNO_DEFAULT | wxYES_NO | wxICON_INFORMATION);
|
||||
dialog.SetSize(400,-1);
|
||||
switch (dialog.ShowModal()) {
|
||||
case wxID_NO: {
|
||||
|
||||
@@ -185,7 +185,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
|
||||
//FIXME handle gap_infill_speed
|
||||
if (! out.empty())
|
||||
out += "\n";
|
||||
out += (first_layer ? _utf8(L("Initial layer volumetric")) : (bridging ? _utf8(L("Bridge volumetric")) : _utf8(L("Volumetric"))));
|
||||
out += (first_layer ? _utf8(L("First layer volumetric")) : (bridging ? _utf8(L("Bridge volumetric")) : _utf8(L("Volumetric"))));
|
||||
out += " " + _utf8(L("flow rate is maximized")) + " ";
|
||||
bool limited_by_max_volumetric_speed = max_volumetric_speed > 0 && max_volumetric_speed < max_flow;
|
||||
out += (limited_by_max_volumetric_speed ?
|
||||
|
||||
@@ -181,13 +181,13 @@ void PublishDialog::SetPublishStep(PublishStep step, bool yield, int percent)
|
||||
else
|
||||
m_progress->SetValue(0);
|
||||
} else if (step == PublishStep::STEP_PACKING) {
|
||||
m_text_progress->SetLabelText(_L("Packing data to 3mf"));
|
||||
m_text_progress->SetLabelText(_L("Packing data to 3MF"));
|
||||
if (percent > 0)
|
||||
m_progress->SetValue(percent);
|
||||
else
|
||||
m_progress->SetValue(70);
|
||||
} else if (step == PublishStep::STEP_UPLOADING) {
|
||||
m_text_progress->SetLabelText(_L("Packing data to 3mf"));
|
||||
m_text_progress->SetLabelText(_L("Uploading data"));
|
||||
if (percent > 0)
|
||||
m_progress->SetValue(percent);
|
||||
else
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "DeviceCore/DevManager.h"
|
||||
#include "DeviceCore/DevStorage.h"
|
||||
#include "md4c/src/md4c-html.h"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
@@ -268,32 +269,33 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent)
|
||||
|
||||
//webview
|
||||
m_vebview_release_note = CreateTipView(m_simplebook_release_note);
|
||||
m_vebview_release_note->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8));
|
||||
m_vebview_release_note->SetSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
m_vebview_release_note->SetMinSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
//m_vebview_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
m_vebview_release_note->Bind(wxEVT_WEBVIEW_NAVIGATING,[=](wxWebViewEvent& event){
|
||||
static bool load_url_first = false;
|
||||
if(load_url_first){
|
||||
// Orca: not used in Orca Slicer
|
||||
// wxLaunchDefaultBrowser(url_line);
|
||||
if (wxGetApp().app_config->get_bool("developer_mode"))
|
||||
m_vebview_release_note->EnableAccessToDevTools();
|
||||
|
||||
m_vebview_release_note->Bind(wxEVT_WEBVIEW_NAVIGATING,[=, count = 0](wxWebViewEvent& event) mutable {
|
||||
count++;
|
||||
if (count == 1) {
|
||||
m_vebview_release_note->SetPage(wxString::FromUTF8(html_source), "");
|
||||
} else if (count >= 3) {
|
||||
// Launch the default browser for links clicked by the user
|
||||
wxLaunchDefaultBrowser(event.GetURL());
|
||||
event.Veto();
|
||||
}else{
|
||||
load_url_first = true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
fs::path ph(data_dir());
|
||||
ph /= "resources/tooltip/releasenote.html";
|
||||
if (!fs::exists(ph)) {
|
||||
ph = resources_dir();
|
||||
ph /= "tooltip/releasenote.html";
|
||||
}
|
||||
auto url = ph.string();
|
||||
std::replace(url.begin(), url.end(), '\\', '/');
|
||||
url = "file:///" + url;
|
||||
m_vebview_release_note->LoadURL(from_u8(url));
|
||||
// fs::path ph(data_dir());
|
||||
// ph /= "resources/tooltip/releasenote.html";
|
||||
// if (!fs::exists(ph)) {
|
||||
// ph = resources_dir();
|
||||
// ph /= "tooltip/releasenote.html";
|
||||
// }
|
||||
// auto url = ph.string();
|
||||
// std::replace(url.begin(), url.end(), '\\', '/');
|
||||
// url = "file:///" + url;
|
||||
// m_vebview_release_note->LoadURL(from_u8(url));
|
||||
|
||||
m_simplebook_release_note->AddPage(m_scrollwindows_release_note, wxEmptyString, false);
|
||||
m_simplebook_release_note->AddPage(m_vebview_release_note, wxEmptyString, false);
|
||||
@@ -470,27 +472,31 @@ void UpdateVersionDialog::update_version_info(wxString release_note, wxString ve
|
||||
// }
|
||||
// }
|
||||
|
||||
if (use_web_link) {
|
||||
m_brand->Hide();
|
||||
m_text_up_info->Hide();
|
||||
m_simplebook_release_note->SetSelection(1);
|
||||
m_vebview_release_note->LoadURL(from_u8(url_line));
|
||||
}
|
||||
else {
|
||||
m_simplebook_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
m_simplebook_release_note->SetSelection(0);
|
||||
m_text_up_info->SetLabel(wxString::Format(_L("Click to download new version in default browser: %s"), version));
|
||||
wxBoxSizer* sizer_text_release_note = new wxBoxSizer(wxVERTICAL);
|
||||
auto m_staticText_release_note = new ::Label(m_scrollwindows_release_note, release_note, LB_AUTO_WRAP);
|
||||
m_staticText_release_note->SetMinSize(wxSize(FromDIP(560), -1));
|
||||
m_staticText_release_note->SetMaxSize(wxSize(FromDIP(560), -1));
|
||||
sizer_text_release_note->Add(m_staticText_release_note, 0, wxALL, 5);
|
||||
m_scrollwindows_release_note->SetSizer(sizer_text_release_note);
|
||||
m_scrollwindows_release_note->Layout();
|
||||
m_scrollwindows_release_note->Fit();
|
||||
SetMinSize(GetSize());
|
||||
SetMaxSize(GetSize());
|
||||
}
|
||||
// if (use_web_link) {
|
||||
// m_brand->Hide();
|
||||
// m_text_up_info->Hide();
|
||||
// m_simplebook_release_note->SetSelection(1);
|
||||
// m_vebview_release_note->LoadURL(from_u8(url_line));
|
||||
// }
|
||||
// else {
|
||||
m_simplebook_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
m_simplebook_release_note->SetSelection(1);
|
||||
m_text_up_info->SetLabel(wxString::Format(_L("Click to download new version in default browser: %s"), version));
|
||||
auto data_buf_in = release_note.utf8_str();
|
||||
auto bg_color = StateColor::darkModeColorFor(*wxWHITE).GetAsString();
|
||||
auto fg_color = StateColor::darkModeColorFor(*wxBLACK).GetAsString();
|
||||
html_source = (boost::format("<html><head><style>body { color: %1%; background-color: %2%; font-family: sans-serif; } a { color: #1E90FF }</style></head><body>")
|
||||
% fg_color % bg_color).str();
|
||||
md_html(data_buf_in.data(), data_buf_in.length(), [](const MD_CHAR* text, MD_SIZE size, void* userdata) {
|
||||
std::string* out_buf = (std::string*)userdata;
|
||||
out_buf->append(text, size);
|
||||
}, (void*) &html_source, MD_DIALECT_GITHUB | MD_FLAG_STRIKETHROUGH | MD_FLAG_WIKILINKS, 0);
|
||||
html_source.append("</body></html>");
|
||||
m_vebview_release_note->LoadURL("file://" + (boost::filesystem::path (resources_dir()) / "web/guide/0/index.html").string());
|
||||
|
||||
SetMinSize(GetSize());
|
||||
SetMaxSize(GetSize());
|
||||
// }
|
||||
|
||||
wxGetApp().UpdateDlgDarkUI(this);
|
||||
Layout();
|
||||
|
||||
@@ -107,6 +107,7 @@ public:
|
||||
Button* m_button_download;
|
||||
Button* m_button_cancel;
|
||||
std::string url_line;
|
||||
std::string html_source;
|
||||
};
|
||||
|
||||
class SecondaryCheckDialog : public DPIFrame
|
||||
|
||||
@@ -203,14 +203,14 @@ wxBoxSizer* SafetyOptionsDialog::create_settings_group(wxWindow* parent)
|
||||
line_sizer->Add(FromDIP(10), 0, 0, 0);
|
||||
sizer->Add(0, 0, 0, wxTOP, FromDIP(15));
|
||||
|
||||
//Idel Heating Protect
|
||||
//Idle Heating Protect
|
||||
m_idel_heating_container = new wxPanel(parent, wxID_ANY);
|
||||
m_idel_heating_container->SetBackgroundColour(*wxWHITE);
|
||||
wxBoxSizer* idel_container_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
line_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_cb_idel_heating_protection = new CheckBox(m_idel_heating_container);
|
||||
m_text_idel_heating_protection = new Label(m_idel_heating_container, _L("Idel Heating Protection"));
|
||||
m_text_idel_heating_protection = new Label(m_idel_heating_container, _L("Idle Heating Protection"));
|
||||
m_text_idel_heating_protection->SetFont(Label::Body_14);
|
||||
line_sizer->AddSpacer(FromDIP(5));
|
||||
line_sizer->Add(m_cb_idel_heating_protection, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5));
|
||||
|
||||
@@ -607,7 +607,7 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater)
|
||||
auto completedimg = new wxStaticBitmap(m_panel_finish, wxID_ANY, create_scaled_bitmap("completed", m_panel_finish, 25), wxDefaultPosition, wxSize(imgsize, imgsize), 0);
|
||||
m_sizer_finish_h->Add(completedimg, 0, wxALIGN_CENTER | wxALL, FromDIP(5));
|
||||
|
||||
m_statictext_finish = new wxStaticText(m_panel_finish, wxID_ANY, L("send completed"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_statictext_finish = new wxStaticText(m_panel_finish, wxID_ANY, L("Send complete"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_statictext_finish->Wrap(-1);
|
||||
m_statictext_finish->SetForegroundColour(wxColour(0, 150, 136));
|
||||
m_sizer_finish_h->Add(m_statictext_finish, 0, wxALIGN_CENTER | wxALL, FromDIP(5));
|
||||
@@ -3555,7 +3555,7 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_)
|
||||
}
|
||||
|
||||
if (obj_->GetConfig()->HasChamber()) {
|
||||
const auto& msg = wxString::Format(_L("[ %s ] requires printing in a high-temperature environment.Please close the door."), filament_strs);
|
||||
const auto& msg = wxString::Format(_L("[ %s ] requires printing in a high-temperature environment. Please close the door."), filament_strs);
|
||||
show_status(PrintDialogStatus::PrintStatusFilamentWarningHighChamberTempCloseDoor, { msg });
|
||||
if (PrePrintChecker::is_error(PrintDialogStatus::PrintStatusFilamentWarningHighChamberTempCloseDoor)) { return; }
|
||||
} else {
|
||||
@@ -5129,8 +5129,8 @@ void PrinterInfoBox::UpdatePlate(const std::string& plate_name)
|
||||
name = _L("Textured PEI Plate");
|
||||
m_bed_image->SetBitmap(create_scaled_bitmap("bed_pei", this, 40));
|
||||
}
|
||||
else if (plate_name == "Supertack Plate") {
|
||||
name = _L("Cool Plate (Supertack)");
|
||||
else if (plate_name == "SuperTack Plate") {
|
||||
name = _L("Cool Plate (SuperTack)");
|
||||
m_bed_image->SetBitmap(create_scaled_bitmap("bed_cool_supertack", this, 40));
|
||||
}
|
||||
|
||||
|
||||
@@ -367,7 +367,7 @@ SendToPrinterDialog::SendToPrinterDialog(Plater *plater)
|
||||
auto completedimg = new wxStaticBitmap(m_panel_finish, wxID_ANY, create_scaled_bitmap("completed", m_panel_finish, 25), wxDefaultPosition, wxSize(imgsize, imgsize), 0);
|
||||
m_sizer_finish_h->Add(completedimg, 0, wxALIGN_CENTER | wxALL, FromDIP(5));
|
||||
|
||||
m_statictext_finish = new wxStaticText(m_panel_finish, wxID_ANY, L("send completed"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_statictext_finish = new wxStaticText(m_panel_finish, wxID_ANY, L("Send complete"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_statictext_finish->Wrap(-1);
|
||||
m_statictext_finish->SetForegroundColour(wxColour(0, 150, 136));
|
||||
m_sizer_finish_h->Add(m_statictext_finish, 0, wxALIGN_CENTER | wxALL, FromDIP(5));
|
||||
|
||||
@@ -3986,13 +3986,13 @@ void StatusPanel::axis_ctrl_e_hint(bool up_down)
|
||||
{
|
||||
if (ctrl_e_hint_dlg == nullptr) {
|
||||
/* ctrl_e_hint_dlg = new SecondaryCheckDialog(this->GetParent(), wxID_ANY, _L("Warning"), SecondaryCheckDialog::VisibleButtons::CONFIRM_AND_CANCEL, wxDefaultPosition,
|
||||
ctrl_e_hint_dlg->update_text(_L("Please heat the nozzle to above 170°C before loading or unloading filament."));
|
||||
ctrl_e_hint_dlg->update_text(_L("Please heat the nozzle to above 170\u2103 before loading or unloading filament."));
|
||||
ctrl_e_hint_dlg->m_show_again_checkbox->Hide();
|
||||
ctrl_e_hint_dlg->m_button_cancel->Hide();
|
||||
ctrl_e_hint_dlg->m_staticText_release_note->SetMaxSize(wxSize(FromDIP(360), -1));
|
||||
ctrl_e_hint_dlg->m_staticText_release_note->SetMinSize(wxSize(FromDIP(360), -1));
|
||||
ctrl_e_hint_dlg->Fit();*/
|
||||
ctrl_e_hint_dlg = new MessageDialog(this, _L("Please heat the nozzle to above 170°C before loading or unloading filament."), wxString(_L("Warning")), wxOK | wxCENTER);
|
||||
ctrl_e_hint_dlg = new MessageDialog(this, _L("Please heat the nozzle to above 170\u2103 before loading or unloading filament."), wxString(_L("Warning")), wxOK | wxCENTER);
|
||||
}
|
||||
ctrl_e_hint_dlg->ShowModal();
|
||||
// ctrl_e_hint_dlg->on_show();
|
||||
@@ -5891,7 +5891,7 @@ wxBoxSizer *ScoreDialog::get_button_sizer()
|
||||
if (ret == -1)
|
||||
error_info += _L("Upload failed\n").ToUTF8().data();
|
||||
else
|
||||
error_info += _L("obtaining instance_id failed\n").ToUTF8().data();
|
||||
error_info += _L("Obtaining instance_id failed\n").ToUTF8().data();
|
||||
if (!error_info.empty()) { BOOST_LOG_TRIVIAL(info) << error_info; }
|
||||
|
||||
dlg_info = new MessageDialog(this,
|
||||
|
||||
@@ -119,7 +119,7 @@ StepMeshDialog::StepMeshDialog(wxWindow* parent, Slic3r::Step& file, double line
|
||||
info->SetForegroundColour(StateColor::darkModeColorFor(FONT_COLOR));
|
||||
|
||||
// ORCA standardized HyperLink
|
||||
HyperLink *tips = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/prepare_stl_transformation");
|
||||
HyperLink *tips = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/import_export#step");
|
||||
tips->SetFont(::Label::Body_12);
|
||||
|
||||
info->Wrap(FromDIP(400));
|
||||
|
||||
+40
-13
@@ -903,9 +903,21 @@ void Tab::filter_diff_option(std::vector<std::string> &options)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) opt = opt.substr(0, hash_pos);
|
||||
if (found) continue;
|
||||
|
||||
// Keep key#index if that exact option is tracked.
|
||||
if (m_options_list.find(opt) != m_options_list.end())
|
||||
continue;
|
||||
|
||||
const std::string base = opt.substr(0, hash_pos);
|
||||
const std::string idx0 = base + "#0";
|
||||
if (m_options_list.find(idx0) != m_options_list.end()) {
|
||||
opt = idx0;
|
||||
continue;
|
||||
}
|
||||
if (m_options_list.find(base) != m_options_list.end())
|
||||
opt = base;
|
||||
}
|
||||
options.erase(std::remove(options.begin(), options.end(), ""), options.end());
|
||||
}
|
||||
|
||||
// Update UI according to changes
|
||||
@@ -974,7 +986,8 @@ void Tab::init_options_list()
|
||||
m_options_list.emplace(opt_key, m_opt_status_value);
|
||||
continue;
|
||||
}
|
||||
if (m_config->option(opt_key)->is_vector())
|
||||
const ConfigOptionDef* opt_def = m_config->def()->get(opt_key);
|
||||
if (m_config->option(opt_key)->is_vector() && !(opt_def && opt_def->gui_flags == "serialized"))
|
||||
m_options_list.emplace(opt_key + "#0", m_opt_status_value);
|
||||
else
|
||||
m_options_list.emplace(opt_key, m_opt_status_value);
|
||||
@@ -987,10 +1000,15 @@ void TabPrinter::init_options_list()
|
||||
if (m_printer_technology == ptFFF)
|
||||
m_options_list.emplace("extruders_count", m_opt_status_value);
|
||||
for (size_t i = 1; i < m_extruders_count; ++i) {
|
||||
auto extruder_page = m_pages[3 + i];
|
||||
for (auto group : extruder_page->m_optgroups) {
|
||||
for (auto & opt : group->opt_map())
|
||||
m_options_list.emplace(opt.first, m_opt_status_value);
|
||||
wxString target_title = wxString::Format("Extruder %d", int(i + 1));
|
||||
for (auto &page : m_pages) {
|
||||
if (page->title() == target_title) {
|
||||
for (auto group : page->m_optgroups) {
|
||||
for (auto &opt : group->opt_map())
|
||||
m_options_list.emplace(opt.first, m_opt_status_value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1597,7 +1615,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
bool wipe_tower_enabled = m_config->option<ConfigOptionBool>("enable_prime_tower")->value;
|
||||
if (boost::any_cast<bool>(value) && !wipe_tower_enabled) {
|
||||
MessageDialog dlg(wxGetApp().plater(),
|
||||
_L("Prime tower is required for clumping detection. There may be flaws on the model without prime tower. Do you still want to enable clumping detection?"),
|
||||
_L("A prime tower is required for clumping detection. There may be flaws on the model without prime tower. Do you still want to enable clumping detection?"),
|
||||
_L("Warning"), wxICON_WARNING | wxYES | wxNO);
|
||||
if (dlg.ShowModal() == wxID_NO) {
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
@@ -1706,7 +1724,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
"Yes - Change these settings automatically\n"
|
||||
"No - Do not change these settings for me");
|
||||
}
|
||||
MessageDialog dialog(wxGetApp().plater(), msg_text, "Suggestion", wxICON_WARNING | wxYES | wxNO);
|
||||
MessageDialog dialog(wxGetApp().plater(), msg_text, _L("Suggestion"), wxICON_WARNING | wxYES | wxNO);
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog.ShowModal() == wxID_YES) {
|
||||
auto &filament_presets = Slic3r::GUI::wxGetApp().preset_bundle->filament_presets;
|
||||
@@ -1758,7 +1776,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
wxString msg_text = _(
|
||||
L("Infill patterns are typically designed to handle rotation automatically to ensure proper printing and achieve their "
|
||||
"intended effects (e.g., Gyroid, Cubic). Rotating the current sparse infill pattern may lead to insufficient support. "
|
||||
"Please proceed with caution and thoroughly check for any potential printing issues."
|
||||
"Please proceed with caution and thoroughly check for any potential printing issues. "
|
||||
"Are you sure you want to enable this option?"));
|
||||
msg_text += "\n\n" + _(L("Are you sure you want to enable this option?"));
|
||||
MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxYES | wxNO);
|
||||
@@ -2448,7 +2466,7 @@ void TabPrint::build()
|
||||
optgroup->append_single_option_line("ensure_vertical_shell_thickness", "strength_settings_advanced#ensure-vertical-shell-thickness");
|
||||
|
||||
page = add_options_page(L("Speed"), "custom-gcode_speed"); // ORCA: icon only visible on placeholders
|
||||
optgroup = page->new_optgroup(L("Initial layer speed"), L"param_speed_first", 15);
|
||||
optgroup = page->new_optgroup(L("First layer speed"), L"param_speed_first", 15);
|
||||
optgroup->append_single_option_line("initial_layer_speed", "speed_settings_initial_layer_speed#initial-layer");
|
||||
optgroup->append_single_option_line("initial_layer_infill_speed", "speed_settings_initial_layer_speed#initial-layer-infill");
|
||||
optgroup->append_single_option_line("initial_layer_travel_speed", "speed_settings_initial_layer_speed#initial-layer-travel-speed");
|
||||
@@ -2584,6 +2602,8 @@ void TabPrint::build()
|
||||
optgroup = page->new_optgroup(L("Prime tower"), L"param_tower");
|
||||
optgroup->append_single_option_line("enable_prime_tower", "multimaterial_settings_prime_tower");
|
||||
optgroup->append_single_option_line("prime_tower_skip_points", "multimaterial_settings_prime_tower");
|
||||
optgroup->append_single_option_line("enable_tower_interface_features", "multimaterial_settings_prime_tower");
|
||||
optgroup->append_single_option_line("enable_tower_interface_cooldown_during_tower", "multimaterial_settings_prime_tower");
|
||||
optgroup->append_single_option_line("prime_tower_enable_framework", "multimaterial_settings_prime_tower");
|
||||
optgroup->append_single_option_line("prime_tower_width", "multimaterial_settings_prime_tower#width");
|
||||
optgroup->append_single_option_line("prime_volume", "multimaterial_settings_prime_tower");
|
||||
@@ -4048,6 +4068,11 @@ void TabFilament::build()
|
||||
page = add_options_page(L("Multimaterial"), "custom-gcode_multi_material"); // ORCA: icon only visible on placeholders
|
||||
optgroup = page->new_optgroup(L("Wipe tower parameters"), "param_tower");
|
||||
optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower", "material_multimaterial#multimaterial-wipe-tower-parameters");
|
||||
optgroup->append_single_option_line("filament_tower_interface_pre_extrusion_dist", "material_multimaterial#multimaterial-wipe-tower-parameters");
|
||||
optgroup->append_single_option_line("filament_tower_interface_pre_extrusion_length", "material_multimaterial#multimaterial-wipe-tower-parameters");
|
||||
optgroup->append_single_option_line("filament_tower_ironing_area", "material_multimaterial#multimaterial-wipe-tower-parameters");
|
||||
optgroup->append_single_option_line("filament_tower_interface_purge_volume", "material_multimaterial#multimaterial-wipe-tower-parameters");
|
||||
optgroup->append_single_option_line("filament_tower_interface_print_temp", "material_multimaterial#multimaterial-wipe-tower-parameters");
|
||||
|
||||
optgroup = page->new_optgroup(L("Multi Filament"));
|
||||
// optgroup->append_single_option_line("filament_flush_temp", "", 0);
|
||||
@@ -4407,7 +4432,6 @@ void TabPrinter::build_fff()
|
||||
|
||||
optgroup->append_single_option_line("use_relative_e_distances", "printer_basic_information_advanced#use-relative-e-distances");
|
||||
optgroup->append_single_option_line("use_firmware_retraction", "printer_basic_information_advanced#use-firmware-retraction");
|
||||
optgroup->append_single_option_line("bed_temperature_formula", "printer_basic_information_advanced#bed-temperature-type");
|
||||
// optgroup->append_single_option_line("spaghetti_detector");
|
||||
optgroup->append_single_option_line("time_cost", "printer_basic_information_advanced#time-cost");
|
||||
|
||||
@@ -4892,6 +4916,7 @@ if (is_marlin_flavor)
|
||||
});
|
||||
};
|
||||
optgroup->append_single_option_line("manual_filament_change", "printer_multimaterial_setup#manual-filament-change");
|
||||
optgroup->append_single_option_line("bed_temperature_formula", "printer_basic_information_advanced#bed-temperature-type");
|
||||
|
||||
optgroup = page->new_optgroup(L("Wipe tower"), "param_tower");
|
||||
optgroup->append_single_option_line("purge_in_prime_tower", "printer_multimaterial_wipe_tower#purge-in-prime-tower");
|
||||
@@ -5621,7 +5646,7 @@ void Tab::rebuild_page_tree()
|
||||
if (sel_item == m_last_select_item)
|
||||
m_last_select_item = item;
|
||||
else
|
||||
m_last_select_item = NULL;
|
||||
m_last_select_item = 0;
|
||||
|
||||
// allow activate page before selection of a page_tree item
|
||||
m_disable_tree_sel_changed_event = false;
|
||||
@@ -6969,6 +6994,8 @@ void Tab::switch_excluder(int extruder_id)
|
||||
{}, {"", "filament_extruder_variant"}, // Preset::TYPE_FILAMENT filament don't use id anymore
|
||||
{}, {"printer_extruder_id", "printer_extruder_variant"}, // Preset::TYPE_PRINTER
|
||||
};
|
||||
if (extruder_id >= nozzle_volumes->size() || extruder_id >= extruders->size())
|
||||
extruder_id = 0;
|
||||
if (m_extruder_switch && m_type != Preset::TYPE_PRINTER) {
|
||||
int current_extruder = m_extruder_switch->GetValue() ? 1 : 0;
|
||||
if (extruder_id == -1)
|
||||
|
||||
Loaded 100 of 838 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user