mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-11 15:09:02 +08:00
Merge branch 'master' into fs_svg
This commit is contained in:
commit
d9b0fad80c
@ -36,7 +36,7 @@ Each string resource in PrusaSlicer available for translation needs to be explic
|
||||
```C++
|
||||
auto msg = L("This message to be localized")
|
||||
```
|
||||
To get translated text use one of needed macro/function (`_(s)` or `_CHB(s)` ).
|
||||
To get translated text use needed macro/function (`_(s)`).
|
||||
If you add new file resource, add it to the list of files containing macro `L()`
|
||||
|
||||
### Scenario 4. How do I use GNUgettext to localize my own application taking PrusaSlicer as an example
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -165,6 +165,7 @@ struct indexed_triangle_set
|
||||
std::vector<stl_vertex> vertices;
|
||||
|
||||
bool empty() const { return indices.empty() || vertices.empty(); }
|
||||
bool operator==(const indexed_triangle_set& other) const { return this->indices == other.indices && this->vertices == other.vertices; }
|
||||
};
|
||||
|
||||
extern bool stl_open(stl_file *stl, const char *file);
|
||||
|
@ -86,7 +86,13 @@ inline IntPoint IntPoint2d(cInt x, cInt y)
|
||||
|
||||
inline cInt Round(double val)
|
||||
{
|
||||
return static_cast<cInt>((val < 0) ? (val - 0.5) : (val + 0.5));
|
||||
double v = val < 0 ? val - 0.5 : val + 0.5;
|
||||
#if defined(CLIPPERLIB_INT32) && ! defined(NDEBUG)
|
||||
static constexpr const double hi = 65536 * 16383;
|
||||
if (v > hi || -v > hi)
|
||||
throw clipperException("Coordinate outside allowed range");
|
||||
#endif
|
||||
return static_cast<cInt>(v);
|
||||
}
|
||||
|
||||
// Overriding the Eigen operators because we don't want to compare Z coordinate if IntPoint is 3 dimensional.
|
||||
|
@ -30,6 +30,9 @@ void EdgeCache::sample_contour(double accuracy, std::vector<ContourLocation> &sa
|
||||
const auto N = m_contour.distances.size();
|
||||
const auto S = stride(N, accuracy);
|
||||
|
||||
if (N == 0 || S == 0)
|
||||
return;
|
||||
|
||||
samples.reserve(N / S + 1);
|
||||
for(size_t i = 0; i < N; i += S) {
|
||||
samples.emplace_back(
|
||||
@ -41,6 +44,10 @@ void EdgeCache::sample_contour(double accuracy, std::vector<ContourLocation> &sa
|
||||
|
||||
const auto NH = hc.distances.size();
|
||||
const auto SH = stride(NH, accuracy);
|
||||
|
||||
if (NH == 0 || SH == 0)
|
||||
continue;
|
||||
|
||||
samples.reserve(samples.size() + NH / SH + 1);
|
||||
for (size_t i = 0; i < NH; i += SH) {
|
||||
samples.emplace_back(
|
||||
|
@ -48,8 +48,9 @@ public:
|
||||
// when fetching corners.
|
||||
static inline size_t stride(const size_t N, double accuracy)
|
||||
{
|
||||
size_t n = std::max(size_t{1}, N);
|
||||
return static_cast<coord_t>(
|
||||
std::round(N / std::pow(N, std::pow(accuracy, 1./3.)))
|
||||
std::round(N / std::pow(n, std::pow(accuracy, 1./3.)))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -155,10 +155,10 @@ It check_csgmesh_booleans(const Range<It> &csgrange, Visitor &&vfn)
|
||||
if (!m || MeshBoolean::cgal::empty(*m))
|
||||
return;
|
||||
|
||||
if (!MeshBoolean::cgal::does_bound_a_volume(*m))
|
||||
if (MeshBoolean::cgal::does_self_intersect(*m))
|
||||
return;
|
||||
|
||||
if (MeshBoolean::cgal::does_self_intersect(*m))
|
||||
if (!MeshBoolean::cgal::does_bound_a_volume(*m))
|
||||
return;
|
||||
}
|
||||
catch (...) { return; }
|
||||
|
@ -239,11 +239,12 @@ namespace Slic3r {
|
||||
|
||||
const bool needs_toolchange = gcodegen.writer().need_toolchange(new_extruder_id);
|
||||
const bool will_go_down = ! is_approx(z, current_z);
|
||||
const bool is_ramming = (gcodegen.config().single_extruder_multi_material && ! tcr.priming)
|
||||
const bool is_ramming = (gcodegen.config().single_extruder_multi_material)
|
||||
|| (! gcodegen.config().single_extruder_multi_material && gcodegen.config().filament_multitool_ramming.get_at(tcr.initial_tool));
|
||||
const bool should_travel_to_tower = tcr.force_travel // wipe tower says so
|
||||
|| ! needs_toolchange // this is just finishing the tower with no toolchange
|
||||
|| is_ramming;
|
||||
const bool should_travel_to_tower = ! tcr.priming
|
||||
&& (tcr.force_travel // wipe tower says so
|
||||
|| ! needs_toolchange // this is just finishing the tower with no toolchange
|
||||
|| is_ramming);
|
||||
if (should_travel_to_tower) {
|
||||
// FIXME: It would be better if the wipe tower set the force_travel flag for all toolchanges,
|
||||
// then we could simplify the condition and make it more readable.
|
||||
@ -3256,7 +3257,7 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
|
||||
|
||||
bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role)
|
||||
{
|
||||
if (travel.length() < scale_(EXTRUDER_CONFIG(retract_before_travel))) {
|
||||
if (! m_writer.extruder() || travel.length() < scale_(EXTRUDER_CONFIG(retract_before_travel))) {
|
||||
// skip retraction if the move is shorter than the configured threshold
|
||||
return false;
|
||||
}
|
||||
|
@ -450,6 +450,19 @@ MedialAxis::MedialAxis(double min_width, double max_width, const ExPolygon &expo
|
||||
|
||||
void MedialAxis::build(ThickPolylines* polylines)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// Verify the scaling of the coordinates of input line segments.
|
||||
for (const Line& l : m_lines) {
|
||||
auto test = [](int32_t v) {
|
||||
static constexpr const int32_t hi = 65536 * 16383;
|
||||
assert(v <= hi && -v < hi);
|
||||
};
|
||||
test(l.a.x());
|
||||
test(l.a.y());
|
||||
test(l.b.x());
|
||||
test(l.b.y());
|
||||
}
|
||||
#endif // NDEBUG
|
||||
construct_voronoi(m_lines.begin(), m_lines.end(), &m_vd);
|
||||
Slic3r::Voronoi::annotate_inside_outside(m_vd, m_lines);
|
||||
// static constexpr double threshold_alpha = M_PI / 12.; // 30 degrees
|
||||
|
@ -81,7 +81,8 @@ void Layer::make_slices()
|
||||
// Top / bottom surfaces must overlap more than 2um to be chained into a Z graph.
|
||||
// Also a larger offset will likely be more robust on non-manifold input polygons.
|
||||
static constexpr const float delta = scaled<float>(0.001);
|
||||
co.MiterLimit = scaled<double>(3.);
|
||||
// Don't scale the miter limit, it is a factor, not an absolute length!
|
||||
co.MiterLimit = 3.;
|
||||
// Use the default zero edge merging distance. For this kind of safety offset the accuracy of normal direction is not important.
|
||||
// co.ShortestEdgeLength = delta * ClipperOffsetShortestEdgeFactor;
|
||||
// static constexpr const double accept_area_threshold_ccw = sqr(scaled<double>(0.1 * delta));
|
||||
|
@ -1475,7 +1475,8 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
|
||||
if (std::vector<Polygons> &top = top_raw[color_idx]; ! top.empty() && ! top[layer_idx].empty())
|
||||
if (ExPolygons top_ex = union_ex(top[layer_idx]); ! top_ex.empty()) {
|
||||
// Clean up thin projections. They are not printable anyways.
|
||||
top_ex = opening_ex(top_ex, stat.small_region_threshold);
|
||||
if (stat.small_region_threshold > 0)
|
||||
top_ex = opening_ex(top_ex, stat.small_region_threshold);
|
||||
if (! top_ex.empty()) {
|
||||
append(triangles_by_color_top[color_idx][layer_idx + layer_idx_offset], top_ex);
|
||||
float offset = 0.f;
|
||||
@ -1483,7 +1484,9 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
|
||||
for (int last_idx = int(layer_idx) - 1; last_idx >= std::max(int(layer_idx - stat.top_solid_layers), int(0)); --last_idx) {
|
||||
offset -= stat.extrusion_width;
|
||||
layer_slices_trimmed = intersection_ex(layer_slices_trimmed, input_expolygons[last_idx]);
|
||||
ExPolygons last = opening_ex(intersection_ex(top_ex, offset_ex(layer_slices_trimmed, offset)), stat.small_region_threshold);
|
||||
ExPolygons last = intersection_ex(top_ex, offset_ex(layer_slices_trimmed, offset));
|
||||
if (stat.small_region_threshold > 0)
|
||||
last = opening_ex(last, stat.small_region_threshold);
|
||||
if (last.empty())
|
||||
break;
|
||||
append(triangles_by_color_top[color_idx][last_idx + layer_idx_offset], std::move(last));
|
||||
@ -1493,7 +1496,8 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
|
||||
if (std::vector<Polygons> &bottom = bottom_raw[color_idx]; ! bottom.empty() && ! bottom[layer_idx].empty())
|
||||
if (ExPolygons bottom_ex = union_ex(bottom[layer_idx]); ! bottom_ex.empty()) {
|
||||
// Clean up thin projections. They are not printable anyways.
|
||||
bottom_ex = opening_ex(bottom_ex, stat.small_region_threshold);
|
||||
if (stat.small_region_threshold > 0)
|
||||
bottom_ex = opening_ex(bottom_ex, stat.small_region_threshold);
|
||||
if (! bottom_ex.empty()) {
|
||||
append(triangles_by_color_bottom[color_idx][layer_idx + layer_idx_offset], bottom_ex);
|
||||
float offset = 0.f;
|
||||
@ -1501,7 +1505,9 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
|
||||
for (size_t last_idx = layer_idx + 1; last_idx < std::min(layer_idx + stat.bottom_solid_layers, num_layers); ++last_idx) {
|
||||
offset -= stat.extrusion_width;
|
||||
layer_slices_trimmed = intersection_ex(layer_slices_trimmed, input_expolygons[last_idx]);
|
||||
ExPolygons last = opening_ex(intersection_ex(bottom_ex, offset_ex(layer_slices_trimmed, offset)), stat.small_region_threshold);
|
||||
ExPolygons last = intersection_ex(bottom_ex, offset_ex(layer_slices_trimmed, offset));
|
||||
if (stat.small_region_threshold > 0)
|
||||
last = opening_ex(last, stat.small_region_threshold);
|
||||
if (last.empty())
|
||||
break;
|
||||
append(triangles_by_color_bottom[color_idx][last_idx + layer_idx_offset], std::move(last));
|
||||
|
@ -1376,6 +1376,10 @@ Preset& PresetCollection::select_preset(size_t idx)
|
||||
if (idx >= m_presets.size())
|
||||
idx = first_visible_idx();
|
||||
m_idx_selected = idx;
|
||||
if (!m_presets[idx].is_visible)
|
||||
// The newly selected preset can be activated -> make it visible.
|
||||
m_presets[idx].is_visible = true;
|
||||
|
||||
m_edited_preset = m_presets[idx];
|
||||
bool default_visible = ! m_default_suppressed || m_idx_selected < m_num_default_presets;
|
||||
for (size_t i = 0; i < m_num_default_presets; ++i)
|
||||
|
@ -1046,11 +1046,8 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
}
|
||||
// Load the configs into this->filaments and make them active.
|
||||
std::vector<std::string> extr_names = std::vector<std::string>(configs.size());
|
||||
// To avoid incorrect selection of the first filament preset (means a value of Preset->m_idx_selected)
|
||||
// in a case when next added preset take a place of previosly selected preset,
|
||||
// we should add presets from last to first
|
||||
bool any_modified = false;
|
||||
for (int i = (int)configs.size()-1; i >= 0; i--) {
|
||||
for (int i = 0; i < (int)configs.size(); i++) {
|
||||
DynamicPrintConfig &cfg = configs[i];
|
||||
// Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets.
|
||||
cfg.opt_string("compatible_printers_condition", true) = compatible_printers_condition_values[i + 1];
|
||||
@ -1059,15 +1056,18 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
// Load all filament presets, but only select the first one in the preset dialog.
|
||||
auto [loaded, modified] = this->filaments.load_external_preset(name_or_path, name,
|
||||
(i < int(old_filament_profile_names->values.size())) ? old_filament_profile_names->values[i] : "",
|
||||
std::move(cfg),
|
||||
i == 0 ?
|
||||
PresetCollection::LoadAndSelect::Always :
|
||||
any_modified ?
|
||||
PresetCollection::LoadAndSelect::Never :
|
||||
PresetCollection::LoadAndSelect::OnlyIfModified);
|
||||
std::move(cfg),
|
||||
any_modified ? PresetCollection::LoadAndSelect::Never :
|
||||
PresetCollection::LoadAndSelect::OnlyIfModified);
|
||||
any_modified |= modified;
|
||||
extr_names[i] = loaded->name;
|
||||
}
|
||||
|
||||
// Check if some preset was selected after loading from config file.
|
||||
// ! Selected preset name is always the same as name of edited preset, if selection was applied
|
||||
if (this->filaments.get_selected_preset_name() != this->filaments.get_edited_preset().name)
|
||||
this->filaments.select_preset_by_name(extr_names[0], true);
|
||||
|
||||
// create extruders_filaments only when all filaments are loaded
|
||||
for (size_t id = 0; id < extr_names.size(); ++id)
|
||||
this->extruders_filaments.emplace_back(ExtruderFilaments(&filaments, id, extr_names[id]));
|
||||
@ -1806,7 +1806,21 @@ void PresetBundle::update_filaments_compatible(PresetSelectCompatibleType select
|
||||
else
|
||||
update_filament_compatible(extruder_idx);
|
||||
|
||||
if (this->filaments.get_idx_selected() == size_t(-1))
|
||||
// validate selection in filaments
|
||||
bool invalid_selection = this->filaments.get_idx_selected() == size_t(-1);
|
||||
if (!invalid_selection) {
|
||||
invalid_selection = true;
|
||||
const std::string selected_filament_name = this->filaments.get_selected_preset_name();
|
||||
for (const auto& extruder : extruders_filaments)
|
||||
if (const std::string& selected_extr_filament_name = extruder.get_selected_preset_name();
|
||||
selected_extr_filament_name == selected_filament_name) {
|
||||
invalid_selection = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// select valid filament from first extruder
|
||||
if (invalid_selection)
|
||||
this->filaments.select_preset(extruders_filaments[0].get_selected_idx());
|
||||
}
|
||||
|
||||
|
@ -3457,7 +3457,9 @@ static void generate_support_areas(Print &print, const BuildVolume &build_volume
|
||||
|
||||
SupportParameters support_params(print_object);
|
||||
support_params.with_sheath = true;
|
||||
support_params.support_density = 0;
|
||||
// Don't override the support density of tree supports, as the support density is used for raft.
|
||||
// The trees will have the density zeroed in tree_supports_generate_paths()
|
||||
// support_params.support_density = 0;
|
||||
|
||||
SupportGeneratorLayerStorage layer_storage;
|
||||
SupportGeneratorLayersPtr top_contacts;
|
||||
|
@ -52,14 +52,4 @@
|
||||
// Enable OpenGL debug messages using debug context
|
||||
#define ENABLE_OPENGL_DEBUG_OPTION (1 && ENABLE_GL_CORE_PROFILE)
|
||||
|
||||
|
||||
//====================
|
||||
// 2.6.0.alpha1 techs
|
||||
//====================
|
||||
#define ENABLE_2_6_0_ALPHA1 1
|
||||
|
||||
// Enable alternative version of file_wildcards()
|
||||
#define ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR (1 && ENABLE_2_6_0_ALPHA1)
|
||||
|
||||
|
||||
#endif // _prusaslicer_technologies_h_
|
||||
|
@ -496,87 +496,44 @@ static const FileWildcards file_wildcards_by_type[FT_SIZE] = {
|
||||
/* FT_ZIP */ { "Zip files"sv, { ".zip"sv } },
|
||||
};
|
||||
|
||||
static wxString file_wildcards(const FileWildcards& data)
|
||||
{
|
||||
std::string title;
|
||||
std::string mask;
|
||||
|
||||
// Generate cumulative first item
|
||||
for (const std::string_view& ext : data.file_extensions) {
|
||||
if (title.empty()) {
|
||||
title = "*";
|
||||
title += ext;
|
||||
mask = title;
|
||||
}
|
||||
else {
|
||||
title += ", *";
|
||||
title += ext;
|
||||
mask += ";*";
|
||||
mask += ext;
|
||||
}
|
||||
mask += ";*";
|
||||
mask += boost::to_upper_copy(std::string(ext));
|
||||
}
|
||||
|
||||
wxString ret = GUI::format_wxstr("%s (%s)|%s", data.title, title, mask);
|
||||
|
||||
// Adds an item for each of the extensions
|
||||
if (data.file_extensions.size() > 1) {
|
||||
for (const std::string_view& ext : data.file_extensions) {
|
||||
title = "*";
|
||||
title += ext;
|
||||
ret += GUI::format_wxstr("|%s (%s)|%s", data.title, title, title);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR
|
||||
wxString file_wildcards(FileType file_type)
|
||||
{
|
||||
const FileWildcards& data = file_wildcards_by_type[file_type];
|
||||
|
||||
return file_wildcards(data);
|
||||
}
|
||||
#else
|
||||
// This function produces a Win32 file dialog file template mask to be consumed by wxWidgets on all platforms.
|
||||
// The function accepts a custom extension parameter. If the parameter is provided, the custom extension
|
||||
// will be added as a fist to the list. This is important for a "file save" dialog on OSX, which strips
|
||||
// an extension from the provided initial file name and substitutes it with the default extension (the first one in the template).
|
||||
wxString file_wildcards(FileType file_type, const std::string &custom_extension)
|
||||
static wxString file_wildcards(const FileWildcards &wildcards, const std::string &custom_extension)
|
||||
{
|
||||
const FileWildcards& data = file_wildcards_by_type[file_type];
|
||||
std::string title;
|
||||
std::string mask;
|
||||
std::string custom_ext_lower;
|
||||
|
||||
// Collects items for each of the extensions one by one.
|
||||
wxString out_one_by_one;
|
||||
auto add_single = [&out_one_by_one](const std::string_view title, const std::string_view ext) {
|
||||
out_one_by_one += GUI::format_wxstr("|%s (*%s)|*%s", title, ext, ext);
|
||||
};
|
||||
|
||||
if (! custom_extension.empty()) {
|
||||
// Generate an extension into the title mask and into the list of extensions.
|
||||
// Generate a custom extension into the title mask and into the list of extensions.
|
||||
// Add default version (upper, lower or mixed) first based on custom extension provided.
|
||||
title = std::string("*") + custom_extension;
|
||||
mask = title;
|
||||
add_single(wildcards.title, custom_extension);
|
||||
custom_ext_lower = boost::to_lower_copy(custom_extension);
|
||||
const std::string custom_ext_upper = boost::to_upper_copy(custom_extension);
|
||||
if (custom_ext_lower == custom_extension) {
|
||||
// Add a lower case version.
|
||||
title = std::string("*") + custom_ext_lower;
|
||||
mask = title;
|
||||
// Add an upper case version.
|
||||
mask += ";*";
|
||||
mask += custom_ext_upper;
|
||||
// Add one more variant - the upper case extension.
|
||||
mask += ";*";
|
||||
mask += custom_ext_upper;
|
||||
add_single(wildcards.title, custom_ext_upper);
|
||||
} else if (custom_ext_upper == custom_extension) {
|
||||
// Add an upper case version.
|
||||
title = std::string("*") + custom_ext_upper;
|
||||
mask = title;
|
||||
// Add a lower case version.
|
||||
// Add one more variant - the lower case extension.
|
||||
mask += ";*";
|
||||
mask += custom_ext_lower;
|
||||
} else {
|
||||
// Add the mixed case version only.
|
||||
title = std::string("*") + custom_extension;
|
||||
mask = title;
|
||||
add_single(wildcards.title, custom_ext_lower);
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::string_view &ext : data.file_extensions)
|
||||
for (const std::string_view &ext : wildcards.file_extensions)
|
||||
// Only add an extension if it was not added first as the custom extension.
|
||||
if (ext != custom_ext_lower) {
|
||||
if (title.empty()) {
|
||||
@ -591,11 +548,16 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension)
|
||||
}
|
||||
mask += ";*";
|
||||
mask += boost::to_upper_copy(std::string(ext));
|
||||
add_single(wildcards.title, ext);
|
||||
}
|
||||
|
||||
return GUI::format_wxstr("%s (%s)|%s", data.title, title, mask);
|
||||
return GUI::format_wxstr("%s (%s)|%s", wildcards.title, title, mask) + out_one_by_one;
|
||||
}
|
||||
|
||||
wxString file_wildcards(FileType file_type, const std::string &custom_extension)
|
||||
{
|
||||
return file_wildcards(file_wildcards_by_type[file_type], custom_extension);
|
||||
}
|
||||
#endif // ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR
|
||||
|
||||
wxString sla_wildcards(const char *formatid)
|
||||
{
|
||||
@ -617,7 +579,7 @@ wxString sla_wildcards(const char *formatid)
|
||||
wc.file_extensions.emplace_back(ext);
|
||||
}
|
||||
|
||||
ret = file_wildcards(wc);
|
||||
ret = file_wildcards(wc, {});
|
||||
}
|
||||
|
||||
if (ret.empty())
|
||||
@ -2864,6 +2826,9 @@ void GUI_App::load_current_presets(bool check_printer_presets_ /*= true*/)
|
||||
// Mark the plater to update print bed by tab->load_current_preset() from Plater::on_config_change().
|
||||
this->plater()->force_print_bed_update();
|
||||
}
|
||||
else if (tab->type() == Preset::TYPE_FILAMENT)
|
||||
// active extruder can be changed in a respect to the new loaded configurations, if some filament preset will be modified
|
||||
static_cast<TabFilament*>(tab)->invalidate_active_extruder();
|
||||
tab->load_current_preset();
|
||||
}
|
||||
}
|
||||
|
@ -78,11 +78,7 @@ enum FileType
|
||||
FT_SIZE,
|
||||
};
|
||||
|
||||
#if ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR
|
||||
extern wxString file_wildcards(FileType file_type);
|
||||
#else
|
||||
extern wxString file_wildcards(FileType file_type, const std::string &custom_extension = std::string{});
|
||||
#endif // ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR
|
||||
extern wxString file_wildcards(FileType file_type, const std::string &custom_extension = {});
|
||||
|
||||
wxString sla_wildcards(const char *formatid);
|
||||
|
||||
|
@ -2326,42 +2326,8 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors)
|
||||
});
|
||||
|
||||
if (m_connector_type == CutConnectorType::Snap) {
|
||||
|
||||
const std::string format = "%.0f %%";
|
||||
|
||||
bool is_changed = false;
|
||||
{
|
||||
const std::string label = _u8L("Bulge");
|
||||
ImGuiWrapper::text(label);
|
||||
|
||||
ImGui::SameLine(m_label_width);
|
||||
ImGui::PushItemWidth(m_control_width * 0.7f);
|
||||
|
||||
float val = m_snap_bulge_proportion *100.f;
|
||||
if (m_imgui->slider_float(("##snap_" + label).c_str(), &val, 5.f, 100.f * m_snap_space_proportion, format.c_str(), 1.f, true, _u8L("Bulge proportion related to radius"))) {
|
||||
m_snap_bulge_proportion = val * 0.01f;
|
||||
is_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const std::string label = _u8L("Space");
|
||||
ImGuiWrapper::text(label);
|
||||
|
||||
ImGui::SameLine(m_label_width);
|
||||
ImGui::PushItemWidth(m_control_width * 0.7f);
|
||||
|
||||
float val = m_snap_space_proportion *100.f;
|
||||
if (m_imgui->slider_float(("##snap_" + label).c_str(), &val, 10.f, 50.f, format.c_str(), 1.f, true, _u8L("Space proportion related to radius"))) {
|
||||
m_snap_space_proportion = val * 0.01f;
|
||||
is_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_changed) {
|
||||
update_connector_shape();
|
||||
update_raycasters_for_picking();
|
||||
}
|
||||
render_snap_specific_input(_u8L("Bulge"), _u8L("Bulge proportion related to radius"), m_snap_bulge_proportion, 0.15f, 5.f, 100.f * m_snap_space_proportion);
|
||||
render_snap_specific_input(_u8L("Space"), _u8L("Space proportion related to radius"), m_snap_space_proportion, 0.3f, 10.f, 50.f);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
@ -2616,6 +2582,37 @@ void GLGizmoCut3D::render_groove_angle_input(const std::string& label, float& in
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::render_snap_specific_input(const std::string& label, const std::string& tooltip, float& in_val, const float& init_val, const float min_val, const float max_val)
|
||||
{
|
||||
ImGuiWrapper::text(label);
|
||||
|
||||
ImGui::SameLine(m_label_width);
|
||||
ImGui::PushItemWidth(m_control_width * 0.7f);
|
||||
|
||||
bool is_changed = false;
|
||||
const std::string format = "%.0f %%";
|
||||
|
||||
float val = in_val * 100.f;
|
||||
if (m_imgui->slider_float(("##snap_" + label).c_str(), &val, min_val, max_val, format.c_str(), 1.f, true, tooltip)) {
|
||||
in_val = val * 0.01f;
|
||||
is_changed = true;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
m_imgui->disabled_begin(is_approx(in_val, init_val));
|
||||
const std::string act_name = _u8L("Reset");
|
||||
if (render_reset_button(("##snap_" + label + act_name).c_str(), act_name)) {
|
||||
in_val = init_val;
|
||||
is_changed = true;
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
|
||||
if (is_changed) {
|
||||
update_connector_shape();
|
||||
update_raycasters_for_picking();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors)
|
||||
{
|
||||
|
@ -302,6 +302,7 @@ protected:
|
||||
void render_color_marker(float size, const ImU32& color);
|
||||
void render_groove_float_input(const std::string &label, float &in_val, const float &init_val, float &in_tolerance);
|
||||
void render_groove_angle_input(const std::string &label, float &in_val, const float &init_val, float min_val, float max_val);
|
||||
void render_snap_specific_input(const std::string& label, const std::string& tooltip, float& in_val, const float& init_val, const float min_val, const float max_val);
|
||||
void render_cut_plane_input_window(CutConnectors &connectors);
|
||||
void init_input_window_data(CutConnectors &connectors);
|
||||
void render_input_window_warning() const;
|
||||
|
@ -22,12 +22,6 @@
|
||||
#define L_CONTEXT(s, context) s
|
||||
#endif /* L */
|
||||
|
||||
#ifndef _CHB
|
||||
//! macro used to localization, return wxScopedCharBuffer
|
||||
//! With wxConvUTF8 explicitly specify that the source string is already in UTF-8 encoding
|
||||
#define _CHB(s) wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str()
|
||||
#endif /* _CHB */
|
||||
|
||||
#ifndef slic3r_GUI_I18N_hpp_
|
||||
#define slic3r_GUI_I18N_hpp_
|
||||
|
||||
|
@ -1147,6 +1147,19 @@ static const wxString sep_space = "";
|
||||
static wxMenu* generate_help_menu()
|
||||
{
|
||||
wxMenu* helpMenu = new wxMenu();
|
||||
|
||||
append_menu_item(helpMenu, wxID_ANY, wxString::Format(_L("%s &Website"), SLIC3R_APP_NAME),
|
||||
wxString::Format(_L("Open the %s website in your browser"), SLIC3R_APP_NAME),
|
||||
[](wxCommandEvent&) { wxGetApp().open_web_page_localized("https://www.prusa3d.com/slicerweb"); });
|
||||
// TRN Item from "Help" menu
|
||||
append_menu_item(helpMenu, wxID_ANY, wxString::Format(_L("&Quick Start"), SLIC3R_APP_NAME),
|
||||
wxString::Format(_L("Open the %s website in your browser"), SLIC3R_APP_NAME),
|
||||
[](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("https://help.prusa3d.com/article/first-print-with-prusaslicer_1753", nullptr, false); });
|
||||
// TRN Item from "Help" menu
|
||||
append_menu_item(helpMenu, wxID_ANY, wxString::Format(_L("Sample &G-codes and Models"), SLIC3R_APP_NAME),
|
||||
wxString::Format(_L("Open the %s website in your browser"), SLIC3R_APP_NAME),
|
||||
[](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("https://help.prusa3d.com/article/sample-g-codes_529630", nullptr, false); });
|
||||
helpMenu->AppendSeparator();
|
||||
append_menu_item(helpMenu, wxID_ANY, _L("Prusa 3D &Drivers"), _L("Open the Prusa3D drivers download page in your browser"),
|
||||
[](wxCommandEvent&) { wxGetApp().open_web_page_localized("https://www.prusa3d.com/downloads"); });
|
||||
append_menu_item(helpMenu, wxID_ANY, _L("Software &Releases"), _L("Open the software releases page in your browser"),
|
||||
@ -1155,9 +1168,6 @@ static wxMenu* generate_help_menu()
|
||||
//# wxTheApp->check_version(1);
|
||||
//# });
|
||||
//# $versioncheck->Enable(wxTheApp->have_version_check);
|
||||
append_menu_item(helpMenu, wxID_ANY, wxString::Format(_L("%s &Website"), SLIC3R_APP_NAME),
|
||||
wxString::Format(_L("Open the %s website in your browser"), SLIC3R_APP_NAME),
|
||||
[](wxCommandEvent&) { wxGetApp().open_web_page_localized("https://www.prusa3d.com/slicerweb"); });
|
||||
// append_menu_item(helpMenu, wxID_ANY, wxString::Format(_L("%s &Manual"), SLIC3R_APP_NAME),
|
||||
// wxString::Format(_L("Open the %s manual in your browser"), SLIC3R_APP_NAME),
|
||||
// [this](wxCommandEvent&) { wxGetApp().open_browser_with_warning_dialog("http://manual.slic3r.org/"); });
|
||||
|
@ -2814,7 +2814,9 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
|
||||
#endif /* AUTOPLACEMENT_ON_LOAD */
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < object->instances.size(); ++i) {
|
||||
for (size_t i = 0; i < object->instances.size()
|
||||
&& !object->is_cut() // don't apply scaled_down functionality to cut objects
|
||||
; ++i) {
|
||||
ModelInstance* instance = object->instances[i];
|
||||
const Vec3d size = object->instance_bounding_box(i).size();
|
||||
const Vec3d ratio = size.cwiseQuotient(bed_size);
|
||||
@ -3602,9 +3604,14 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const
|
||||
new_volume->convert_from_imperial_units();
|
||||
else if (old_volume->source.is_converted_from_meters)
|
||||
new_volume->convert_from_meters();
|
||||
new_volume->supported_facets.assign(old_volume->supported_facets);
|
||||
new_volume->seam_facets.assign(old_volume->seam_facets);
|
||||
new_volume->mmu_segmentation_facets.assign(old_volume->mmu_segmentation_facets);
|
||||
|
||||
if (old_volume->mesh().its == new_volume->mesh().its) {
|
||||
// This function is called both from reload_from_disk and replace_with_stl.
|
||||
// We need to make sure that the painted data point to existing triangles.
|
||||
new_volume->supported_facets.assign(old_volume->supported_facets);
|
||||
new_volume->seam_facets.assign(old_volume->seam_facets);
|
||||
new_volume->mmu_segmentation_facets.assign(old_volume->mmu_segmentation_facets);
|
||||
}
|
||||
std::swap(old_model_object->volumes[volume_idx], old_model_object->volumes.back());
|
||||
old_model_object->delete_volume(old_model_object->volumes.size() - 1);
|
||||
if (!sinking)
|
||||
@ -4026,7 +4033,8 @@ void Plater::priv::set_current_panel(wxPanel* panel)
|
||||
bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() != ModelInstancePVS_Partly_Outside;
|
||||
if (!model.objects.empty() && !export_in_progress && model_fits) {
|
||||
preview->get_canvas3d()->init_gcode_viewer();
|
||||
preview->load_gcode_shells();
|
||||
if (! this->background_process.finished())
|
||||
preview->load_gcode_shells();
|
||||
q->reslice();
|
||||
}
|
||||
// keeps current gcode preview, if any
|
||||
@ -6467,19 +6475,12 @@ void Plater::export_gcode(bool prefer_removable)
|
||||
|
||||
fs::path output_path;
|
||||
{
|
||||
#if !ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR
|
||||
std::string ext = default_output_file.extension().string();
|
||||
#endif // !ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR
|
||||
wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _L("Save G-code file as:") : _L("Save SL1 / SL1S file as:"),
|
||||
start_dir,
|
||||
from_path(default_output_file.filename()),
|
||||
#if ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR
|
||||
printer_technology() == ptFFF ? GUI::file_wildcards(FT_GCODE) :
|
||||
GUI::sla_wildcards(p->sla_print.printer_config().sla_archive_format.value.c_str()),
|
||||
#else
|
||||
printer_technology() == ptFFF ? GUI::file_wildcards(FT_GCODE, ext) :
|
||||
GUI::sla_wildcards(p->sla_print.printer_config().sla_archive_format.value.c_str()),
|
||||
#endif // ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR
|
||||
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
|
||||
);
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
|
@ -1986,8 +1986,16 @@ void TabFilament::update_extruder_combobox()
|
||||
m_extruders_cb->Append(format_wxstr("%1% %2%", _L("Extruder"), id), *get_bmp_bundle("funnel"));
|
||||
}
|
||||
|
||||
if (m_active_extruder >= int(extruder_cnt))
|
||||
if (m_active_extruder >= int(extruder_cnt)) {
|
||||
m_active_extruder = 0;
|
||||
// update selected and, as a result, editing preset
|
||||
const std::string& preset_name = m_preset_bundle->extruders_filaments[0].get_selected_preset_name();
|
||||
m_presets->select_preset_by_name(preset_name, true);
|
||||
|
||||
// To avoid inconsistance between value of active_extruder in FilamentTab and TabPresetComboBox,
|
||||
// which can causes a crash on switch preset from MM printer to SM printer
|
||||
m_presets_choice->set_active_extruder(m_active_extruder);
|
||||
}
|
||||
|
||||
m_extruders_cb->SetSelection(m_active_extruder);
|
||||
}
|
||||
@ -2317,12 +2325,37 @@ void TabFilament::sys_color_changed()
|
||||
|
||||
void TabFilament::load_current_preset()
|
||||
{
|
||||
const std::string& selected_filament_name = m_presets->get_selected_preset_name();
|
||||
if (m_active_extruder < 0) {
|
||||
// active extruder was invalidated before load new project file or configuration,
|
||||
// so we have to update active extruder selection from selected filament
|
||||
const std::string& edited_filament_name = m_presets->get_edited_preset().name;
|
||||
assert(!selected_filament_name.empty() && selected_filament_name == edited_filament_name);
|
||||
|
||||
for (int i = 0; i < int(m_preset_bundle->extruders_filaments.size()); i++) {
|
||||
const std::string& selected_extr_filament_name = m_preset_bundle->extruders_filaments[i].get_selected_preset_name();
|
||||
if (selected_extr_filament_name == edited_filament_name) {
|
||||
m_active_extruder = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(m_active_extruder >= 0);
|
||||
|
||||
m_presets_choice->set_active_extruder(m_active_extruder);
|
||||
if (m_active_extruder != m_extruders_cb->GetSelection())
|
||||
m_extruders_cb->Select(m_active_extruder);
|
||||
}
|
||||
|
||||
assert(m_active_extruder >= 0 && m_active_extruder < m_preset_bundle->extruders_filaments.size());
|
||||
const std::string& selected_extr_filament_name = m_preset_bundle->extruders_filaments[m_active_extruder].get_selected_preset_name();
|
||||
const std::string& selected_filament_name = m_presets->get_selected_preset_name();
|
||||
if (selected_extr_filament_name != selected_filament_name)
|
||||
if (selected_extr_filament_name != selected_filament_name) {
|
||||
m_presets->select_preset_by_name(selected_extr_filament_name, false);
|
||||
|
||||
// To avoid inconsistance between value of active_extruder in FilamentTab and TabPresetComboBox,
|
||||
// which can causes a crash on switch preset from MM printer to SM printer
|
||||
m_presets_choice->set_active_extruder(m_active_extruder);
|
||||
}
|
||||
|
||||
Tab::load_current_preset();
|
||||
}
|
||||
|
||||
@ -3639,8 +3672,17 @@ bool Tab::select_preset(std::string preset_name, bool delete_current /*=false*/,
|
||||
for (PresetUpdate &pu : updates) {
|
||||
pu.old_preset_dirty = (old_printer_technology == pu.technology) && pu.presets->current_is_dirty();
|
||||
pu.new_preset_compatible = (new_printer_technology == pu.technology) && is_compatible_with_printer(pu.presets->get_edited_preset_with_vendor_profile(), new_printer_preset_with_vendor_profile);
|
||||
bool force_update_edited_preset = false;
|
||||
if (pu.tab_type == Preset::TYPE_FILAMENT && pu.new_preset_compatible) {
|
||||
// check if edited preset will be still correct after selection new printer
|
||||
const int active_extruder = dynamic_cast<const TabFilament*>(wxGetApp().get_tab(Preset::TYPE_FILAMENT))->get_active_extruder();
|
||||
const int extruder_count_new = int(dynamic_cast<const ConfigOptionFloats*>(new_printer_preset.config.option("nozzle_diameter"))->size());
|
||||
// if active_extruder is bigger than extruders_count,
|
||||
// then it means that edited filament preset will be changed and we have to check this changes
|
||||
force_update_edited_preset = active_extruder >= extruder_count_new;
|
||||
}
|
||||
if (!canceled)
|
||||
canceled = pu.old_preset_dirty && !pu.new_preset_compatible && !may_discard_current_dirty_preset(pu.presets, preset_name);
|
||||
canceled = pu.old_preset_dirty && (!pu.new_preset_compatible || force_update_edited_preset) && !may_discard_current_dirty_preset(pu.presets, preset_name);
|
||||
}
|
||||
if (!canceled) {
|
||||
for (PresetUpdate &pu : updates) {
|
||||
|
@ -469,6 +469,7 @@ public:
|
||||
// set actiev extruder and update preset combobox if needed
|
||||
// return false, if new preset wasn't selected
|
||||
bool set_active_extruder(int new_selected_extruder);
|
||||
void invalidate_active_extruder() { m_active_extruder = -1; }
|
||||
void update_extruder_combobox();
|
||||
int get_active_extruder() const { return m_active_extruder; }
|
||||
|
||||
|
@ -930,7 +930,7 @@ TEST_CASE("Optimal nfp position search with GravityKernel using RectangleItem an
|
||||
|
||||
Slic3r::Vec2crd D = bed.center - item.shape.center();
|
||||
REQUIRE(item.translation == D);
|
||||
REQUIRE(score == Approx(0.));
|
||||
REQUIRE(score == Approx(0.).margin(EPSILON));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user