Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorremi durand <remi-j.durand@thalesgroup.com>2022-04-01 01:00:48 +0300
committerremi durand <remi-j.durand@thalesgroup.com>2022-04-01 01:00:48 +0300
commit173e6c694c246dd6a322f96a393eb42d922843b9 (patch)
tree55ee8b25d7be48369f4445fd6c3f2dab9ef4ed7e
parenta0d7ae360b79823d861bccc7ed610538b87a0761 (diff)
parent14ce3ad01bed34f7f14b1f06fb19f8b5cdc7d754 (diff)
rc for 2.3.57.122.3.57.12
-rw-r--r--doc/How to build - Mac OS.md3
m---------resources/profiles0
-rw-r--r--src/libslic3r/AppConfig.cpp31
-rw-r--r--src/libslic3r/Config.cpp10
-rw-r--r--src/libslic3r/GCode.cpp6
-rw-r--r--src/libslic3r/GCode/SeamPlacer.cpp19
-rw-r--r--src/libslic3r/MedialAxis.cpp135
-rw-r--r--src/libslic3r/MedialAxis.hpp13
-rw-r--r--src/libslic3r/PerimeterGenerator.cpp15
-rw-r--r--src/libslic3r/Preset.cpp2
-rw-r--r--src/libslic3r/Print.cpp8
-rw-r--r--src/libslic3r/PrintBase.cpp5
-rw-r--r--src/libslic3r/PrintConfig.cpp18
-rw-r--r--src/slic3r/GUI/CalibrationBedDialog.cpp10
-rw-r--r--src/slic3r/GUI/CalibrationBridgeDialog.cpp6
-rw-r--r--src/slic3r/GUI/CalibrationFlowDialog.cpp14
-rw-r--r--src/slic3r/GUI/CalibrationOverBridgeDialog.cpp12
-rw-r--r--src/slic3r/GUI/CalibrationRetractionDialog.cpp4
-rw-r--r--src/slic3r/GUI/CalibrationTempDialog.cpp7
-rw-r--r--src/slic3r/GUI/Field.cpp105
-rw-r--r--src/slic3r/GUI/Field.hpp6
-rw-r--r--src/slic3r/GUI/FreeCADDialog.cpp50
-rw-r--r--src/slic3r/GUI/NotificationManager.cpp12
-rw-r--r--src/slic3r/GUI/Tab.cpp3
-rw-r--r--src/slic3r/GUI/WipeTowerDialog.cpp6
25 files changed, 373 insertions, 127 deletions
diff --git a/doc/How to build - Mac OS.md b/doc/How to build - Mac OS.md
index 25e14cf4b..964599fdb 100644
--- a/doc/How to build - Mac OS.md
+++ b/doc/How to build - Mac OS.md
@@ -14,6 +14,8 @@ XCode is available through Apple's App Store, the other three tools are availabl
### How to get the source code
You have to gitclone the repository
+
+Open 'terminal' and enter each line, one at a time.
```
git clone https://github.com/supermerill/SuperSlicer.git
```
@@ -21,6 +23,7 @@ git clone https://github.com/supermerill/SuperSlicer.git
and then you have to clone the profiles submodules
```
+cd SuperSlicer
cd resources/profiles
git submodule update
```
diff --git a/resources/profiles b/resources/profiles
-Subproject 0b8261ae8bbd7c31d736f371323476d6aff3ef3
+Subproject ab609331353a14890c8d65fcb55f07dd0ca5b1c
diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp
index 04afd9ea5..3c4064d8d 100644
--- a/src/libslic3r/AppConfig.cpp
+++ b/src/libslic3r/AppConfig.cpp
@@ -67,8 +67,37 @@ void AppConfig::set_defaults()
if (get("drop_project_action").empty())
set("drop_project_action", "1");
- if (get("freecad_path").empty())
+ if (get("freecad_path").empty() || get("freecad_path") == ".") {
set("freecad_path", ".");
+ //try to find it
+#ifdef _WIN32
+ //windows
+ boost::filesystem::path prg_files = "C:/Program Files";
+ boost::filesystem::path freecad_path;
+ if (boost::filesystem::exists(prg_files)) {
+ for (boost::filesystem::directory_entry& prg_dir : boost::filesystem::directory_iterator(prg_files)) {
+ if (prg_dir.status().type() == boost::filesystem::file_type::directory_file
+ && boost::starts_with(prg_dir.path().filename().string(), "FreeCAD")
+ && (freecad_path.empty() || freecad_path.filename().string() < prg_dir.path().filename().string())) {
+ freecad_path = prg_dir.path();
+ }
+ }
+ }
+ if (!freecad_path.empty())
+ set("freecad_path", freecad_path.string());
+#else
+#ifdef __APPLE__
+ //apple
+ if (boost::filesystem::exists("/Applications/FreeCAD.app/Contents/Frameworks/FreeCAD"))
+ set("freecad_path", "/Applications/FreeCAD.app/Contents/Frameworks/FreeCAD");
+
+#else
+ // linux
+ if (boost::filesystem::exists("/usr/local/bin/FreeCAD"))
+ set("freecad_path", "/usr/local/bin/FreeCAD");
+#endif
+#endif
+ }
if (get("show_overwrite_dialog").empty())
set("show_overwrite_dialog", "1");
diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp
index f05d35d2d..bc8041c75 100644
--- a/src/libslic3r/Config.cpp
+++ b/src/libslic3r/Config.cpp
@@ -820,7 +820,7 @@ ConfigSubstitutions ConfigBase::load_from_ini(const std::string &file, ForwardCo
return this->load(tree, compatibility_rule);
} catch (const ConfigurationError &e) {
throw ConfigurationError(format("Failed loading configuration file \"%1%\": %2%", file, e.what()));
-}
+ }
}
ConfigSubstitutions ConfigBase::load(const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule)
@@ -933,6 +933,14 @@ size_t ConfigBase::load_from_gcode_string(const char* str, ConfigSubstitutionCon
}
catch (UnknownOptionException & /* e */) {
// ignore
+ } catch (BadOptionValueException & e) {
+ if (substitutions.rule == ForwardCompatibilitySubstitutionRule::Disable)
+ throw e;
+ // log the error
+ const ConfigDef* def = this->def();
+ if (def == nullptr) throw e;
+ const ConfigOptionDef* optdef = def->get(std::string(key, key_end));
+ substitutions.substitutions.emplace_back(optdef, std::string(value, end), ConfigOptionUniquePtr(optdef->default_value->clone()));
}
end = start;
}
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index 43c770d3f..83d52c847 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -1326,6 +1326,9 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
if ((initial_extruder_id = tool_ordering.first_extruder()) != static_cast<uint16_t>(-1))
break;
}
+ if (initial_extruder_id == static_cast<unsigned int>(-1))
+ // No object to print was found, cancel the G-code export.
+ throw Slic3r::SlicingError(_(L("No extrusions were generated for objects.")));
// We don't allow switching of extruders per layer by Model::custom_gcode_per_print_z in sequential mode.
// Use the extruder IDs collected from Regions.
std::set<uint16_t> extruder_set = print.extruders();
@@ -1337,6 +1340,9 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it.
tool_ordering = print.tool_ordering();
tool_ordering.assign_custom_gcodes(print);
+ if (tool_ordering.all_extruders().empty())
+ // No object to print was found, cancel the G-code export.
+ throw Slic3r::SlicingError(_(L("No extrusions were generated for objects.")));
has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower();
initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ?
// The priming towers will be skipped.
diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp
index 44e713d18..a974b5a7a 100644
--- a/src/libslic3r/GCode/SeamPlacer.cpp
+++ b/src/libslic3r/GCode/SeamPlacer.cpp
@@ -340,6 +340,7 @@ Point SeamPlacer::get_seam(const Layer& layer, SeamPosition seam_position,
// Look for all lambda-seam-modifiers below current z, choose the highest one
ModelVolume* v_lambda_seam = nullptr;
Vec3d lambda_pos;
+ double lambda_z;
double lambda_dist;
double lambda_radius;
//get model_instance (like from po->model_object()->instances, but we don't have the index for that array)
@@ -347,28 +348,34 @@ Point SeamPlacer::get_seam(const Layer& layer, SeamPosition seam_position,
for (ModelVolume* v : po->model_object()->volumes) {
if (v->is_seam_position()) {
//xy in object coordinates, z in plater coordinates
- Vec3d test_lambda_pos = model_instance->transform_vector(v->get_offset(), true);
+ // created/moved shpere have offset in their transformation, and loaded ones have their loaded transformation in the source transformation.
+ Vec3d test_lambda_pos = model_instance->transform_vector((v->get_transformation() * v->source.transform).get_offset(), false);
+ // remove shift, as we used the transform_vector(.., FALSE). that way, we have a correct z vs the layer height, and same for the x and y vs polygon.
+ test_lambda_pos.x() -= unscaled(po->instances()[print_object_instance_idx].shift.x());
+ test_lambda_pos.y() -= unscaled(po->instances()[print_object_instance_idx].shift.y());
+ double test_lambda_z = std::abs(layer.print_z - test_lambda_pos.z());
Point xy_lambda(scale_(test_lambda_pos.x()), scale_(test_lambda_pos.y()));
Point nearest = polygon.point_projection(xy_lambda);
Vec3d polygon_3dpoint{ unscaled(nearest.x()), unscaled(nearest.y()), (double)layer.print_z };
double test_lambda_dist = (polygon_3dpoint - test_lambda_pos).norm();
double sphere_radius = po->model_object()->instance_bounding_box(0, true).size().x() / 2;
- //if (test_lambda_dist > sphere_radius)
- // continue;
- //use this one if the first or nearer (in z)
- if (v_lambda_seam == nullptr || lambda_dist > test_lambda_dist) {
+
+ //use this one if the first or nearer (in z, or in xy if same z)
+ if (v_lambda_seam == nullptr
+ || ( lambda_z > test_lambda_z )
+ || ( lambda_z == test_lambda_z && lambda_dist > test_lambda_dist ) ){
v_lambda_seam = v;
lambda_pos = test_lambda_pos;
lambda_radius = sphere_radius;
lambda_dist = test_lambda_dist;
+ lambda_z = test_lambda_z;
}
}
}
if (v_lambda_seam != nullptr) {
- lambda_pos = model_instance->transform_vector(v_lambda_seam->get_offset(), true);
// Found, get the center point and apply rotation and scaling of Model instance. Continues to spAligned if not found or Weight set to Zero.
last_pos = Point::new_scale(lambda_pos.x(), lambda_pos.y());
// Weight is set by user and stored in the radius of the sphere
diff --git a/src/libslic3r/MedialAxis.cpp b/src/libslic3r/MedialAxis.cpp
index 1e31c714f..c6e1128ab 100644
--- a/src/libslic3r/MedialAxis.cpp
+++ b/src/libslic3r/MedialAxis.cpp
@@ -16,9 +16,6 @@
#include <list>
namespace Slic3r {
- int count_error = 0;
-
- //int Slic3r::MedialAxis::staticid = 0;
void
MedialAxis::build(Polylines &polylines)
@@ -667,6 +664,7 @@ MedialAxis::fusion_corners(ThickPolylines &pp)
//if (polyline.points.size() != 2) continue; // maybe we should have something to merge X-point to 2-point if it's near enough.
if (polyline.endpoints.first) polyline.reverse();
else if (!polyline.endpoints.second) continue;
+ if (polyline.width.back() > min_width) continue;
//check my length is small
coord_t length = (coord_t)polyline.length();
@@ -1210,6 +1208,7 @@ MedialAxis::remove_too_thin_extrusion(ThickPolylines& pp)
bool changes = false;
for (size_t i = 0; i < pp.size(); ++i) {
ThickPolyline& polyline = pp[i];
+ bool polyline_changes = false;
// remove bits with too small extrusion
while (polyline.points.size() > 1 && polyline.width.front() < this->min_width && polyline.endpoints.first) {
//try to split if possible
@@ -1226,11 +1225,13 @@ MedialAxis::remove_too_thin_extrusion(ThickPolylines& pp)
polyline.width.erase(polyline.width.begin());
}
changes = true;
+ polyline_changes = true;
break;
}
polyline.points.erase(polyline.points.begin());
polyline.width.erase(polyline.width.begin());
changes = true;
+ polyline_changes = true;
}
while (polyline.points.size() > 1 && polyline.width.back() < this->min_width && polyline.endpoints.second) {
//try to split if possible
@@ -1247,14 +1248,16 @@ MedialAxis::remove_too_thin_extrusion(ThickPolylines& pp)
polyline.width.erase(polyline.width.end() - 1);
}
changes = true;
+ polyline_changes = true;
break;
}
polyline.points.erase(polyline.points.end() - 1);
polyline.width.erase(polyline.width.end() - 1);
changes = true;
+ polyline_changes = true;
}
//remove points and bits that comes from a "main line"
- if (polyline.points.size() < 2 || (changes && polyline.length() < this->max_width && polyline.points.size() ==2)) {
+ if (polyline.points.size() < 2 || (polyline_changes && polyline.length() < this->max_width && polyline.points.size() ==2)) {
//remove self if too small
pp.erase(pp.begin() + i);
--i;
@@ -1264,6 +1267,110 @@ MedialAxis::remove_too_thin_extrusion(ThickPolylines& pp)
}
void
+MedialAxis::concatenate_small_polylines(ThickPolylines& pp)
+{
+
+ /*
+ new goal: ensure that if there is a too short segment, it will be connected with a sufficiently long one, to save it
+ */
+ coordf_t shortest_size = (coordf_t)this->min_length;
+ std::set<size_t> deleted;
+ std::vector<size_t> idx_per_size;
+ //TODO: cache the length
+ for (size_t i = 0; i < pp.size(); ++i) {
+ ThickPolyline& polyline = pp[i];
+ if (polyline.endpoints.first && polyline.endpoints.second) continue; // optimization
+ if (polyline.length() <= shortest_size)
+ idx_per_size.push_back(i);
+ }
+ std::sort(idx_per_size.begin(), idx_per_size.end(), [&pp](size_t a, size_t b) -> bool {return pp[a].length() > pp[b].length(); });
+ for (size_t idx_sorted = 0; idx_sorted < idx_per_size.size(); ++idx_sorted) {
+ if (deleted.find(idx_per_size[idx_sorted]) != deleted.end()) continue;
+ //all these polylines need to be saved
+ ThickPolyline& polyline = pp[idx_per_size[idx_sorted]];
+
+ ThickPolyline* best_candidate = nullptr;
+ float best_dot = -1;
+ coordf_t best_length = -1;
+ size_t best_idx = 0;
+
+ // find another polyline starting here
+ for (size_t j = 0; j < pp.size(); ++j) {
+ if (deleted.find(j) != deleted.end()) continue;
+ if (j == idx_per_size[idx_sorted]) continue;
+ ThickPolyline& other = pp[j];
+ if (other.endpoints.first && other.endpoints.second) continue;
+ coordf_t other_length = other.length();
+ if (other_length + polyline.length() <= shortest_size) continue; // need to be long enough to save it
+ bool me_reverse = false;
+ bool other_reverse = false;
+ if (polyline.last_point().coincides_with_epsilon(other.last_point())) {
+ other_reverse = true;
+ } else if (polyline.first_point().coincides_with_epsilon(other.last_point())) {
+ me_reverse = true;
+ other_reverse = true;
+ } else if (polyline.first_point().coincides_with_epsilon(other.first_point())) {
+ me_reverse = true;
+ } else if (!polyline.last_point().coincides_with_epsilon(other.first_point())) {
+ continue;
+ }
+
+ //find the straitest
+ Vec2d v_poly(me_reverse ? polyline.lines().front().vector().x() : polyline.lines().back().vector().x(),
+ me_reverse ? polyline.lines().front().vector().y() : polyline.lines().back().vector().y());
+ v_poly *= (1 / std::sqrt(v_poly.x() * v_poly.x() + v_poly.y() * v_poly.y()));
+ Vec2d v_other(other_reverse ? other.lines().back().vector().x() : other.lines().front().vector().x(),
+ other_reverse ? other.lines().back().vector().y() : other.lines().front().vector().y());
+ v_other *= (1 / std::sqrt(v_other.x() * v_other.x() + v_other.y() * v_other.y()));
+ float other_dot = std::abs(float(v_poly.x() * v_other.x() + v_poly.y() * v_other.y()));
+ // use the straitest one
+ // but if almost equal, use the shortest one
+ if (std::abs(other_dot - best_dot) < 0.01) {
+ if (best_length < 0 || best_length > other_length) {
+ best_candidate = &other;
+ best_idx = j;
+ best_dot = other_dot;
+ best_length = other_length;
+ }
+ } else if (other_dot > best_dot) {
+ best_candidate = &other;
+ best_idx = j;
+ best_dot = other_dot;
+ best_length = other_length;
+ }
+ }
+ if (best_candidate != nullptr && best_candidate->points.size() > 1) {
+ if (polyline.last_point().coincides_with_epsilon(best_candidate->last_point())) {
+ best_candidate->reverse();
+ } else if (polyline.first_point().coincides_with_epsilon(best_candidate->last_point())) {
+ polyline.reverse();
+ best_candidate->reverse();
+ } else if (polyline.first_point().coincides_with_epsilon(best_candidate->first_point())) {
+ polyline.reverse();
+ }
+ //intersections may create over-extrusion because the included circle can be a bit larger. We have to make it short again if needed.
+ if (polyline.points.size() > 1 && best_candidate->points.size() > 1
+ && polyline.width.back() > polyline.width[polyline.width.size() - 2]
+ && polyline.width.back() > best_candidate->width[1]) {
+ polyline.width.back() = std::min(polyline.width[polyline.width.size() - 2], best_candidate->width[1]);
+ }
+ //be far enough
+ int far_idx = 1;
+ while (far_idx < best_candidate->points.size() && polyline.last_point().coincides_with_epsilon(best_candidate->points[far_idx]))
+ far_idx++;
+ polyline.points.insert(polyline.points.end(), best_candidate->points.begin() + far_idx, best_candidate->points.end());
+ polyline.width.insert(polyline.width.end(), best_candidate->width.begin() + far_idx, best_candidate->width.end());
+ polyline.endpoints.second = best_candidate->endpoints.second;
+ assert(polyline.width.size() == polyline.points.size());
+ deleted.insert(best_idx);
+ }
+ }
+ //delete items to delete (iterate in reverse order to not invalidate the idxs
+ for (auto rit = deleted.rbegin(); rit != deleted.rend(); rit++)
+ pp.erase(pp.begin() + (*rit));
+}
+
+void
MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp)
{
@@ -1402,7 +1509,7 @@ MedialAxis::remove_too_thin_points(ThickPolylines& pp)
}
void
-MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_size)
+MedialAxis::remove_too_short_polylines(ThickPolylines& pp)
{
// reduce the flow at the intersection ( + ) points
//FIXME: TODO: note that crossings are unnafected right now. they may need a different codepath directly in their method
@@ -1468,7 +1575,7 @@ MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_siz
while (changes) {
changes = false;
- coordf_t shortest_size = (coordf_t) min_size;
+ coordf_t shortest_size = (coordf_t)this->min_length;
size_t shortest_idx = -1;
for (size_t i = 0; i < pp.size(); ++i) {
ThickPolyline& polyline = pp[i];
@@ -1499,8 +1606,6 @@ MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_siz
changes = true;
while (changes) {
changes = false;
-
- coordf_t shortest_size = (coordf_t)min_size;
size_t shortest_idx = -1;
for (size_t polyidx = 0; polyidx < pp.size(); ++polyidx) {
ThickPolyline& tp = pp[polyidx];
@@ -2000,10 +2105,20 @@ MedialAxis::build(ThickPolylines &polylines_out)
// svg.Close();
//}
//TODO: reduce the flow at the intersection ( + ) points on crossing?
+ concatenate_small_polylines(pp);
+ //{
+ // std::stringstream stri;
+ // stri << "medial_axis_6_concat_small_" << id << ".svg";
+ // SVG svg(stri.str());
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
+ // svg.Close();
+ //}
concatenate_polylines_with_crossing(pp);
//{
// std::stringstream stri;
- // stri << "medial_axis_6_concat_" << id << ".svg";
+ // stri << "medial_axis_7_concat_" << id << ".svg";
// SVG svg(stri.str());
// svg.draw(*bounds, "grey");
// svg.draw(this->expolygon, "green");
@@ -2011,7 +2126,7 @@ MedialAxis::build(ThickPolylines &polylines_out)
// svg.Close();
//}
- remove_too_short_polylines(pp, max_w * 2);
+ remove_too_short_polylines(pp);
//{
// std::stringstream stri;
// stri << "medial_axis_8_tooshort_" << id << ".svg";
diff --git a/src/libslic3r/MedialAxis.hpp b/src/libslic3r/MedialAxis.hpp
index e8614c5ba..f16741302 100644
--- a/src/libslic3r/MedialAxis.hpp
+++ b/src/libslic3r/MedialAxis.hpp
@@ -30,7 +30,7 @@ class MedialAxis {
/// _height: height of the extrusion, used to compute the difference between width and spacing.
MedialAxis(const ExPolygon &_expolygon, const coord_t _max_width, const coord_t _min_width, const coord_t _height)
: surface(_expolygon), max_width(_max_width), min_width(_min_width), height(_height),
- bounds(&_expolygon), nozzle_diameter(_min_width), taper_size(0), stop_at_min_width(true){/*id= staticid;staticid++;*/};
+ bounds(&_expolygon), nozzle_diameter(_min_width), taper_size(0), stop_at_min_width(true), min_length(_max_width) {/*id= staticid;staticid++;*/};
/// create the polylines_out collection of variable-width polyline to extrude.
void build(ThickPolylines &polylines_out);
@@ -45,6 +45,7 @@ class MedialAxis {
MedialAxis& use_tapers(const coord_t taper_size) { this->taper_size = taper_size; return *this; }
/// optional parameter: if true, the entension inside the bounds can be cut if the width is too small. Default : true
MedialAxis& set_stop_at_min_width(const bool stop_at_min_width) { this->stop_at_min_width = stop_at_min_width; return *this; }
+ MedialAxis& set_min_length(const coord_t min_length) { this->min_length = min_length; return *this; }
private:
@@ -57,6 +58,8 @@ class MedialAxis {
const coord_t max_width;
/// minimum width of the extrusion, every spot where a circle diameter is lower than that will be ignored (unless it's the tip of the extrusion)
const coord_t min_width;
+ /// minimum length of continuous segments (may cross a crossing)
+ coord_t min_length;
/// height of the extrusion, used to compute the diufference between width and spacing.
const coord_t height;
/// Used to compute the real minimum width we can extrude. if != min_width, it activate grow_to_nozzle_diameter().
@@ -96,12 +99,14 @@ class MedialAxis {
void extends_line(ThickPolyline& polyline, const ExPolygons& anchors, const coord_t join_width);
/// remove too thin bits at start & end of polylines
void remove_too_thin_extrusion(ThickPolylines& pp);
- /// instead of keeping polyline split at each corssing, we try to create long strait polylines that can cross each other.
+ /// when we have a too small polyline, try to see if we can't concatenate it at a crossing to keep it.
+ void concatenate_small_polylines(ThickPolylines& pp);
+ /// instead of keeping polyline split at each crossing, we try to create long strait polylines that can cross each other.
void concatenate_polylines_with_crossing(ThickPolylines& pp);
/// remove bits around points that are too thin (can be inside the polyline)
void remove_too_thin_points(ThickPolylines& pp);
- /// delete polylines that are too short
- void remove_too_short_polylines(ThickPolylines& pp, const coord_t min_size);
+ /// delete polylines that are too short (below the this->min_length)
+ void remove_too_short_polylines(ThickPolylines& pp);
/// be sure we didn't try to push more plastic than the volume defined by surface * height can receive. If overextruded, reduce all widths by the correct %.
void ensure_not_overextrude(ThickPolylines& pp);
/// if nozzle_diameter > min_width, grow bits that are < width(nozzle_diameter) to width(nozzle_diameter) (don't activate that for gapfill)
diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp
index 283eeb9c6..0b372b451 100644
--- a/src/libslic3r/PerimeterGenerator.cpp
+++ b/src/libslic3r/PerimeterGenerator.cpp
@@ -390,9 +390,10 @@ void PerimeterGenerator::process()
ExPolygons top_fills;
ExPolygons fill_clip;
// simplification already done at slicing
- //ExPolygons last = union_ex(surface.expolygon.simplify_p(SCALED_RESOLUTION));
- ExPolygons last = union_ex(surface.expolygon);
- double last_area = -1;
+ //simplify the loop to avoid artifacts when shrinking almost-0 segments
+ coord_t resolution = scale_t(this->print_config->resolution.value);
+ ExPolygons last = union_ex(surface.expolygon.simplify_p((resolution < SCALED_EPSILON ? SCALED_EPSILON : resolution)));
+ double last_area = -1;
if (loop_number >= 0) {
@@ -562,6 +563,7 @@ void PerimeterGenerator::process()
ma.use_bounds(bound)
.use_min_real_width(scale_t(this->ext_perimeter_flow.nozzle_diameter))
.use_tapers(thin_walls_overlap)
+ .set_min_length(ext_perimeter_width + ext_perimeter_spacing)
.build(thin_walls_thickpolys);
}
break;
@@ -702,7 +704,12 @@ void PerimeterGenerator::process()
holes[i].emplace_back(hole, i, false, has_steep_overhang);
}
}
- last = std::move(next_onion);
+
+ //simplify the loop to avoid artifacts when shrinking almost-0 segments
+ resolution = scale_t(this->print_config->resolution.value);
+ last.clear();
+ for(ExPolygon& exp : next_onion)
+ exp.simplify((resolution < SCALED_EPSILON ? SCALED_EPSILON : resolution), &last);
//store surface for top infill if only_one_perimeter_top
if (i == 0 && (config->only_one_perimeter_top && this->upper_slices != NULL)) {
diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp
index d4683b351..002b3aa11 100644
--- a/src/libslic3r/Preset.cpp
+++ b/src/libslic3r/Preset.cpp
@@ -1471,7 +1471,7 @@ inline t_config_option_keys deep_diff(const ConfigBase &config_this, const Confi
&& (ignore_phony || !(this_opt->is_phony() && other_opt->is_phony()))
&& ((*this_opt != *other_opt) || (this_opt->is_phony() != other_opt->is_phony())))
{
- if (opt_key == "bed_shape" || opt_key == "compatible_prints" || opt_key == "compatible_printers") {
+ if (opt_key == "bed_shape" || opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "filament_ramming_parameters" || opt_key == "gcode_substitutions") {
// Scalar variable, or a vector variable, which is independent from number of extruders,
// thus the vector is presented to the user as a single input.
// note that thumbnails are not here becasue it has individual # entries
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index 98b7e2c8a..a2a870de5 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -2141,7 +2141,7 @@ void Print::_make_skirt(const PrintObjectPtrs &objects, ExtrusionEntityCollectio
out_first_layer->append(eloop);
if (m_config.min_skirt_length.value > 0 && !first_layer_only) {
// The skirt length is limited. Sum the total amount of filament length extruded, in mm.
- extruded_length[extruder_idx] += unscale<double>(loop.length());// *extruders_e_per_mm[extruder_idx];
+ extruded_length[extruder_idx] += unscale<double>(loop.length()) * extruders_e_per_mm[extruder_idx];
if (extruded_length[extruder_idx] < m_config.min_skirt_length.value) {
// Not extruded enough yet with the current extruder. Add another loop.
if (i == 1 && extruded_length[extruder_idx] > 0)
@@ -2374,7 +2374,11 @@ void Print::_make_brim(const Flow &flow, const PrintObjectPtrs &objects, ExPolyg
if (!object->support_layers().empty()) {
Polygons polys = object->support_layers().front()->support_fills.polygons_covered_by_spacing(flow.spacing_ratio, float(SCALED_EPSILON));
for (Polygon poly : polys) {
- object_islands.emplace_back(brim_offset == 0 ? ExPolygon{ poly } : offset_ex(poly, brim_offset)[0]);
+ if (brim_offset == 0) {
+ object_islands.emplace_back(poly);
+ } else {
+ append(object_islands, offset_ex(Polygons{ poly }, brim_offset));
+ }
}
}
islands.reserve(islands.size() + object_islands.size() * object->m_instances.size());
diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp
index beabfb76b..4a348022f 100644
--- a/src/libslic3r/PrintBase.cpp
+++ b/src/libslic3r/PrintBase.cpp
@@ -64,9 +64,10 @@ std::string PrintBase::output_filename(const std::string &format, const std::str
cfg.set_key_value("input_filename_base", new ConfigOptionString(filename_base));
}
try {
+ uint16_t extruder_initial = config_override->option("initial_extruder") != nullptr ? config_override->option("initial_extruder")->getInt() : 0;
boost::filesystem::path filepath = format.empty() ?
- cfg.opt_string("input_filename_base") + default_ext :
- this->placeholder_parser().process(format, 0, &cfg);
+ cfg.opt_string("input_filename_base") + default_ext :
+ this->placeholder_parser().process(format, extruder_initial, &cfg);
//remove unwanted characters
std::string forbidden_base;
if (const ConfigOptionString* opt = this->placeholder_parser().external_config()->option<ConfigOptionString>("gcode_filename_illegal_char")) {
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index 68b4d3475..a8e1c49f3 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -489,7 +489,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("Max angle");
def->full_label = L("Brim ear max angle");
def->category = OptionCategory::skirtBrim;
- def->tooltip = L("Maximum angle to let a brim ear appear. \nIf set to 0, no brim will be created. \nIf set to ~178, brim will be created on everything but strait sections.");
+ def->tooltip = L("Maximum angle to let a brim ear appear. \nIf set to 0, no brim will be created. \nIf set to ~178, brim will be created on everything but straight sections.");
def->sidetext = L("°");
def->min = 0;
def->max = 180;
@@ -5932,6 +5932,12 @@ std::map<std::string,std::string> PrintConfigDef::from_prusa(t_config_option_key
output["first_layer_min_speed"] = value;
output["first_layer_infill_speed"] = value;
}
+ if ("resolution" == opt_key) {
+ value = "0.0125";
+ }
+ if ("gcode_resolution" == opt_key) {
+ output["min_length"] = value;
+ }
return output;
}
@@ -6166,8 +6172,14 @@ void PrintConfigDef::to_prusa(t_config_option_key& opt_key, std::string& value,
}
} else if ("elephant_foot_min_width" == opt_key) {
opt_key = "elefant_foot_min_width";
- } else if("first_layer_acceleration" == opt_key || "infill_acceleration" == opt_key || "bridge_acceleration" == opt_key || "default_acceleration" == opt_key || "perimeter_acceleration" == opt_key
- || "overhangs_speed" == opt_key || "ironing_speed" == opt_key){
+ } else if("first_layer_acceleration" == opt_key) {
+ if (value.find("%") != std::string::npos) {
+ // can't support %, so we uese the default accel a baseline for half-assed conversion
+ value = std::to_string(all_conf.get_abs_value(opt_key, all_conf.get_computed_value("default_acceleration")));
+ }
+ } else if ("infill_acceleration" == opt_key || "bridge_acceleration" == opt_key || "default_acceleration" == opt_key || "perimeter_acceleration" == opt_key
+ || "overhangs_speed" == opt_key || "ironing_speed" == opt_key
+ ) {
// remove '%'
if (value.find("%") != std::string::npos) {
value = std::to_string(all_conf.get_computed_value(opt_key));
diff --git a/src/slic3r/GUI/CalibrationBedDialog.cpp b/src/slic3r/GUI/CalibrationBedDialog.cpp
index f24f86888..e0ec46615 100644
--- a/src/slic3r/GUI/CalibrationBedDialog.cpp
+++ b/src/slic3r/GUI/CalibrationBedDialog.cpp
@@ -103,11 +103,11 @@ void CalibrationBedDialog::create_geometry(wxCommandEvent& event_args) {
plat->arrange();
//TODO add message
} else {
- model.objects[objs_idx[0]]->translate({ bed_min.x() + offsetx, bed_min.y() + bed_size.y() - offsety,0 });
- model.objects[objs_idx[1]]->translate({ bed_min.x() + bed_size.x() - offsetx,bed_min.y() + offsety , 0 });
- model.objects[objs_idx[2]]->translate({ bed_min.x() + bed_size.x()/2, bed_min.y() + bed_size.y() / 2, 0 });
- model.objects[objs_idx[3]]->translate({ bed_min.x() + offsetx, bed_min.y() + offsety, 0 });
- model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() - offsetx,bed_min.y() + bed_size.y() - offsety,0 });
+ model.objects[objs_idx[0]]->translate({ bed_min.x() + offsetx, bed_min.y() + bed_size.y() - offsety, 1 * zscale });
+ model.objects[objs_idx[1]]->translate({ bed_min.x() + bed_size.x() - offsetx,bed_min.y() + offsety , 1 * zscale });
+ model.objects[objs_idx[2]]->translate({ bed_min.x() + bed_size.x()/2, bed_min.y() + bed_size.y() / 2, 1 * zscale });
+ model.objects[objs_idx[3]]->translate({ bed_min.x() + offsetx, bed_min.y() + offsety, 1 * zscale });
+ model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() - offsetx,bed_min.y() + bed_size.y() - offsety, 1 * zscale });
}
/// --- main config, please modify object config when possible ---
diff --git a/src/slic3r/GUI/CalibrationBridgeDialog.cpp b/src/slic3r/GUI/CalibrationBridgeDialog.cpp
index 302c0c856..3755c43cf 100644
--- a/src/slic3r/GUI/CalibrationBridgeDialog.cpp
+++ b/src/slic3r/GUI/CalibrationBridgeDialog.cpp
@@ -96,7 +96,7 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool
float z_scale = nozzle_diameter / 0.4;
//do scaling
if (z_scale < 0.9 || 1.2 < z_scale) {
- for (size_t i = 0; i < 5; i++)
+ for (size_t i = 0; i < nb_items; i++)
model.objects[objs_idx[i]]->scale(1, 1, z_scale);
} else {
z_scale = 1;
@@ -120,9 +120,9 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool
Vec2d bed_size = BoundingBoxf(bed_shape->values).size();
Vec2d bed_min = BoundingBoxf(bed_shape->values).min;
float offsety = 2 + 10 * 1 + extruder_clearance_radius->value + brim_width + (brim_width > extruder_clearance_radius->value ? brim_width - extruder_clearance_radius->value : 0);
- model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2, 0 });
+ model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2, 2.5 * z_scale });
for (int i = 1; i < nb_items; i++) {
- model.objects[objs_idx[i]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2 + (i % 2 == 0 ? -1 : 1) * offsety * ((i + 1) / 2), 0 });
+ model.objects[objs_idx[i]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2 + (i % 2 == 0 ? -1 : 1) * offsety * ((i + 1) / 2), 2.5 * z_scale });
}
// if not enough space, forget about complete_objects
if (bed_size.y() < offsety * (nb_items + 1))
diff --git a/src/slic3r/GUI/CalibrationFlowDialog.cpp b/src/slic3r/GUI/CalibrationFlowDialog.cpp
index edaafcaeb..5cabc666a 100644
--- a/src/slic3r/GUI/CalibrationFlowDialog.cpp
+++ b/src/slic3r/GUI/CalibrationFlowDialog.cpp
@@ -78,7 +78,7 @@ void CalibrationFlowDialog::create_geometry(float start, float delta) {
//do scaling
if (xyScale < 0.9 || 1.2 < xyScale) {
for (size_t i = 0; i < 5; i++)
- model.objects[objs_idx[i]]->scale(xyScale, xyScale, zscale);
+ model.objects[objs_idx[i]]->scale(xyScale, xyScale, zscale); // base: 10 10 1
} else {
for (size_t i = 0; i < 5; i++)
model.objects[objs_idx[i]]->scale(1, 1, zscale);
@@ -106,7 +106,7 @@ void CalibrationFlowDialog::create_geometry(float start, float delta) {
add_part(model.objects[objs_idx[4]], (boost::filesystem::path(Slic3r::resources_dir()) / "calibration" / "filament_flow" / "_0.amf").string(), Vec3d{ 10 * xyScale,0,zshift }, Vec3d{ xyScale , xyScale, zscale_number});
}
for (size_t i = 0; i < 5; i++) {
- add_part(model.objects[objs_idx[i]], (boost::filesystem::path(Slic3r::resources_dir()) / "calibration" / "filament_flow" / "O.amf").string(), Vec3d{ 0,0,zscale/2.f + 0.5 }, Vec3d{xyScale , xyScale, layer_height / 0.2});
+ add_part(model.objects[objs_idx[i]], (boost::filesystem::path(Slic3r::resources_dir()) / "calibration" / "filament_flow" / "O.amf").string(), Vec3d{ 0,0,zscale/2.f + 0.5 }, Vec3d{xyScale , xyScale, layer_height / 0.2}); // base: 0.2mm height
}
/// --- translate ---;
@@ -118,11 +118,11 @@ void CalibrationFlowDialog::create_geometry(float start, float delta) {
Vec2d bed_min = BoundingBoxf(bed_shape->values).min;
float offsetx = 3 + 20 * xyScale + extruder_clearance_radius->value + brim_width + (brim_width > extruder_clearance_radius->value ? brim_width - extruder_clearance_radius->value : 0);
float offsety = 3 + 20 * xyScale + extruder_clearance_radius->value + brim_width + (brim_width > extruder_clearance_radius->value ? brim_width - extruder_clearance_radius->value : 0);
- model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 - offsety, 0 });
- model.objects[objs_idx[1]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 , 0 });
- model.objects[objs_idx[2]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, 0 });
- model.objects[objs_idx[3]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 - offsety, 0 });
- model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, 0 });
+ model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 - offsety, zscale / 2 });
+ model.objects[objs_idx[1]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 , zscale / 2 });
+ model.objects[objs_idx[2]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, zscale / 2 });
+ model.objects[objs_idx[3]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 - offsety, zscale / 2 });
+ model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, zscale / 2 });
// if not enough space, forget about complete_objects
if (bed_size.y() < offsety * 2 + 25 * xyScale + brim_width || bed_size.x() < offsetx + 25 * xyScale + brim_width)
diff --git a/src/slic3r/GUI/CalibrationOverBridgeDialog.cpp b/src/slic3r/GUI/CalibrationOverBridgeDialog.cpp
index 829193326..323eb331b 100644
--- a/src/slic3r/GUI/CalibrationOverBridgeDialog.cpp
+++ b/src/slic3r/GUI/CalibrationOverBridgeDialog.cpp
@@ -99,12 +99,12 @@ void CalibrationOverBridgeDialog::create_geometry(bool over_bridge) {
Vec2d bed_min = BoundingBoxf(bed_shape->values).min;
float offsetx = 3 + 30 * xyz_scale + extruder_clearance_radius->value + brim_width + (brim_width > extruder_clearance_radius->value ? brim_width - extruder_clearance_radius->value : 0);
float offsety = 3 + 25 * xyz_scale + extruder_clearance_radius->value + brim_width + (brim_width > extruder_clearance_radius->value ? brim_width - extruder_clearance_radius->value : 0);
- model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 - offsety, 0 });
- model.objects[objs_idx[1]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 , 0 });
- model.objects[objs_idx[2]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, 0 });
- model.objects[objs_idx[3]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 - offsety, 0 });
- model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 , 0 });
- model.objects[objs_idx[5]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, 0 });
+ model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 - offsety, (nozzle_diameter / 0.4) });
+ model.objects[objs_idx[1]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 , (nozzle_diameter / 0.4) });
+ model.objects[objs_idx[2]]->translate({ bed_min.x() + bed_size.x() / 2 - offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, (nozzle_diameter / 0.4) });
+ model.objects[objs_idx[3]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 - offsety, (nozzle_diameter / 0.4) });
+ model.objects[objs_idx[4]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 , (nozzle_diameter / 0.4) });
+ model.objects[objs_idx[5]]->translate({ bed_min.x() + bed_size.x() / 2 + offsetx / 2, bed_min.y() + bed_size.y() / 2 + offsety, (nozzle_diameter / 0.4) });
// if not enough space, forget about complete_objects
if (bed_size.y() < offsety * 2 + 30 * xyz_scale + brim_width * 2 + skirt_width * 2 + 5 || bed_size.x() < offsetx + 35 * xyz_scale + brim_width * 2 + skirt_width * 2 + 5)
diff --git a/src/slic3r/GUI/CalibrationRetractionDialog.cpp b/src/slic3r/GUI/CalibrationRetractionDialog.cpp
index 1de3f179c..f69c44219 100644
--- a/src/slic3r/GUI/CalibrationRetractionDialog.cpp
+++ b/src/slic3r/GUI/CalibrationRetractionDialog.cpp
@@ -179,7 +179,7 @@ void CalibrationRetractionDialog::create_geometry(wxCommandEvent& event_args) {
int mytemp = temp - temp_decr * id_item;
if (mytemp <= 285 && mytemp >= 180 && mytemp % 5 == 0) {
add_part(model.objects[objs_idx[id_item]], (boost::filesystem::path(Slic3r::resources_dir()) / "calibration" / "filament_temp" / ("t" + std::to_string(mytemp) + ".amf")).string(),
- Vec3d{ 0,0, scale * 0.2 - 4.8 }, Vec3d{ scale,scale,scale });
+ Vec3d{ 0,0, scale * 0.0 - 4.8 }, Vec3d{ scale,scale,scale });
model.objects[objs_idx[id_item]]->volumes[1]->rotate(PI / 2, Vec3d(0, 0, 1));
model.objects[objs_idx[id_item]]->volumes[1]->rotate(-PI / 2, Vec3d(1, 0, 0));
}
@@ -199,7 +199,7 @@ void CalibrationRetractionDialog::create_geometry(wxCommandEvent& event_args) {
Vec2d bed_min = BoundingBoxf(bed_shape->values).min;
float offset = 4 + 26 * scale * 1 + extruder_clearance_radius->value + brim_width + (brim_width > extruder_clearance_radius->value ? brim_width - extruder_clearance_radius->value : 0);
if (nb_items == 1) {
- model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2, 0 });
+ model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2, zscale_number });
} else {
has_to_arrange = true;
}
diff --git a/src/slic3r/GUI/CalibrationTempDialog.cpp b/src/slic3r/GUI/CalibrationTempDialog.cpp
index 440975887..70c4b199b 100644
--- a/src/slic3r/GUI/CalibrationTempDialog.cpp
+++ b/src/slic3r/GUI/CalibrationTempDialog.cpp
@@ -109,7 +109,8 @@ void CalibrationTempDialog::create_geometry(wxCommandEvent& event_args) {
float zshift = (1 - xyzScale) / 2;
if (temperature > 175 && temperature < 290 && temperature%5==0) {
tower.push_back(add_part(model.objects[objs_idx[0]], (boost::filesystem::path(Slic3r::resources_dir()) / "calibration" / "filament_temp" / ("t"+std::to_string(temperature)+".amf")).string(),
- Vec3d{ xyzScale * 5, - xyzScale * 2.5, zshift - xyzScale * 2.5}, Vec3d{ xyzScale, xyzScale, xyzScale * 0.43 }));
+ //Vec3d{ xyzScale * 5, - xyzScale * 2.5, zshift - xyzScale * 2.5}, Vec3d{ xyzScale, xyzScale, xyzScale * 0.43 }));
+ Vec3d{ 8 - xyzScale * 5, -xyzScale * 2.3, xyzScale * (0 * 10 - 2.45) }, Vec3d{ xyzScale, xyzScale, xyzScale * 0.43 }));
}
for (int16_t i = 1; i < nb_items; i++) {
tower.push_back(add_part(model.objects[objs_idx[0]], (boost::filesystem::path(Slic3r::resources_dir()) / "calibration" / "filament_temp" / ("Smart_compact_temperature_calibration_item.amf")).string(),
@@ -117,7 +118,7 @@ void CalibrationTempDialog::create_geometry(wxCommandEvent& event_args) {
int sub_temp = temperature - i * step_temp;
if (sub_temp > 175 && sub_temp < 290 && sub_temp % 5 == 0) {
tower.push_back(add_part(model.objects[objs_idx[0]], (boost::filesystem::path(Slic3r::resources_dir()) / "calibration" / "filament_temp" / ("t" + std::to_string(sub_temp) + ".amf")).string(),
- Vec3d{ xyzScale * 5, -xyzScale * 2.5, xyzScale * (i * 10 - 2.5) }, Vec3d{ xyzScale, xyzScale, xyzScale * 0.43 }));
+ Vec3d{ 8 - xyzScale * 5, -xyzScale * 2.3, xyzScale * (i * 10 - 2.5) }, Vec3d{ xyzScale, xyzScale, xyzScale * 0.43 }));
}
}
@@ -128,7 +129,7 @@ void CalibrationTempDialog::create_geometry(wxCommandEvent& event_args) {
const ConfigOptionPoints* bed_shape = printer_config->option<ConfigOptionPoints>("bed_shape");
Vec2d bed_size = BoundingBoxf(bed_shape->values).size();
Vec2d bed_min = BoundingBoxf(bed_shape->values).min;
- model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2, 0 });
+ model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2, 5 * xyzScale - 5 });
}
/// --- main config, please modify object config when possible ---
diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index 0bc236e43..8e1e929c9 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -15,6 +15,9 @@
#include <wx/tooltip.h>
#include <wx/notebook.h>
#include <wx/richtooltip.h>
+#ifdef __WXGTK2__
+#include <wx/tglbtn.h>
+#endif
#include <wx/tokenzr.h>
#include <boost/algorithm/string/predicate.hpp>
#include "OG_CustomCtrl.hpp"
@@ -875,24 +878,64 @@ void CheckBox::BUILD() {
m_last_meaningful_value = static_cast<unsigned char>(check_value);
- // Set Label as a string of at least one space simbol to correct system scaling of a CheckBox
- auto temp = new wxCheckBox(m_parent, wxID_ANY, wxString(" "), wxDefaultPosition, size);
- temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
- if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
- temp->SetValue(check_value);
- if (m_opt.readonly) temp->Disable();
-
- temp->Bind(wxEVT_CHECKBOX, ([this](wxCommandEvent e) {
- m_is_na_val = false;
- on_change_field();
- }), temp->GetId());
-
- // recast as a wxWindow to fit the calling convention
- window = dynamic_cast<wxWindow*>(temp);
+#ifdef __WXGTK2__
+ //gtk2 can't resize checkboxes, so we are using togglable buttons instead
+ if (m_em_unit > 14) {
+ size = wxSize(def_width_thinner() * m_em_unit / 2, def_width_thinner() * m_em_unit / 2);
+ auto temp = new wxToggleButton(m_parent, wxID_ANY, wxString(" "), wxDefaultPosition, size, wxCHK_2STATE);
+ temp->Bind(wxEVT_TOGGLEBUTTON, ([this, temp](wxCommandEvent e) {
+ m_is_na_val = false;
+ if (temp->GetValue())
+ temp->SetLabel("X");
+ else
+ temp->SetLabel("");
+ on_change_field();
+ }), temp->GetId());
+ // recast as a wxWindow to fit the calling convention
+ window = dynamic_cast<wxWindow*>(temp);
+ }
+ else
+#endif
+ {
+ // Set Label as a string of at least one space simbol to correct system scaling of a CheckBox
+ auto temp = new wxCheckBox(m_parent, wxID_ANY, wxString(" "), wxDefaultPosition, size, wxCHK_2STATE);
+ temp->Bind(wxEVT_CHECKBOX, ([this](wxCommandEvent e) {
+ m_is_na_val = false;
+ on_change_field();
+ }), temp->GetId());
+ // recast as a wxWindow to fit the calling convention
+ window = dynamic_cast<wxWindow*>(temp);
+ temp->SetValue(check_value);
+ }
+ window->SetFont(Slic3r::GUI::wxGetApp().normal_font());
+ if (!wxOSX) window->SetBackgroundStyle(wxBG_STYLE_PAINT);
+ if (m_opt.readonly) window->Enable(false);
+
this->set_tooltip(check_value ? "true" : "false");
}
+void CheckBox::set_widget_value(bool new_val)
+{
+ wxCheckBox* chk = dynamic_cast<wxCheckBox*>(window);
+ if (chk != nullptr) {
+ chk->SetValue(new_val);
+ }
+#ifdef __WXGTK2__
+ else
+ {
+ wxToggleButton* tgl = dynamic_cast<wxToggleButton*>(window);
+ if (tgl) {
+ tgl->SetValue(new_val);
+ if (new_val)
+ tgl->SetLabel("X");
+ else
+ tgl->SetLabel("");
+ }
+ }
+#endif
+}
+
void CheckBox::set_value(const boost::any& value, bool change_event)
{
m_disable_change_event = !change_event;
@@ -900,10 +943,10 @@ void CheckBox::set_value(const boost::any& value, bool change_event)
m_is_na_val = boost::any_cast<unsigned char>(value) == ConfigOptionBoolsNullable::nil_value();
if (!m_is_na_val)
m_last_meaningful_value = value;
- dynamic_cast<wxCheckBox*>(window)->SetValue(m_is_na_val ? false : boost::any_cast<unsigned char>(value) != 0);
+ set_widget_value(m_is_na_val ? false : boost::any_cast<unsigned char>(value) != 0);
}
else
- dynamic_cast<wxCheckBox*>(window)->SetValue(boost::any_cast<bool>(value));
+ set_widget_value(boost::any_cast<bool>(value));
m_disable_change_event = false;
}
@@ -911,7 +954,7 @@ void CheckBox::set_last_meaningful_value()
{
if (m_opt.nullable) {
m_is_na_val = false;
- dynamic_cast<wxCheckBox*>(window)->SetValue(boost::any_cast<unsigned char>(m_last_meaningful_value) != 0);
+ set_widget_value(boost::any_cast<unsigned char>(m_last_meaningful_value) != 0);
on_change_field();
}
}
@@ -920,7 +963,7 @@ void CheckBox::set_na_value()
{
if (m_opt.nullable) {
m_is_na_val = true;
- dynamic_cast<wxCheckBox*>(window)->SetValue(false);
+ set_widget_value(false);
on_change_field();
}
}
@@ -928,7 +971,18 @@ void CheckBox::set_na_value()
boost::any& CheckBox::get_value()
{
// boost::any m_value;
- bool value = dynamic_cast<wxCheckBox*>(window)->GetValue();
+ bool value = false;
+ wxCheckBox* chk = dynamic_cast<wxCheckBox*>(window);
+ if (chk != nullptr) {
+ value = chk->GetValue();
+ }
+#ifdef __WXGTK2__
+ else
+ {
+ wxToggleButton* tgl = dynamic_cast<wxToggleButton*>(window);
+ if (tgl) value = tgl->GetValue();
+ }
+#endif
if (m_opt.type == coBool)
m_value = static_cast<bool>(value);
else
@@ -940,8 +994,17 @@ void CheckBox::msw_rescale()
{
Field::msw_rescale();
- wxCheckBox* field = dynamic_cast<wxCheckBox*>(window);
- field->SetMinSize(wxSize(-1, int(1.5f*field->GetFont().GetPixelSize().y +0.5f)));
+ wxCheckBox* chk = dynamic_cast<wxCheckBox*>(window);
+ if (chk != nullptr) {
+ chk->SetMinSize(wxSize(-1, int(1.5f * chk->GetFont().GetPixelSize().y + 0.5f)));
+ }
+#ifdef __WXGTK2__
+ else
+ { //a bit useless as it's a windows-only func. To have a correct thing, you have to del the previous window and create a new one anyway.
+ wxToggleButton* tgl = dynamic_cast<wxToggleButton*>(window);
+ if (tgl) tgl->SetMinSize(wxSize(def_width_thinner() * m_em_unit / 2, def_width_thinner() * m_em_unit / 2));
+ }
+#endif
}
diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp
index e48473346..5095015ef 100644
--- a/src/slic3r/GUI/Field.hpp
+++ b/src/slic3r/GUI/Field.hpp
@@ -295,6 +295,8 @@ public:
class CheckBox : public Field {
using Field::Field;
bool m_is_na_val {false};
+
+ void set_widget_value(bool new_val);
public:
CheckBox(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
CheckBox(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
@@ -315,8 +317,8 @@ public:
void msw_rescale() override;
- void enable() override { dynamic_cast<wxCheckBox*>(window)->Enable(); }
- void disable() override { dynamic_cast<wxCheckBox*>(window)->Disable(); }
+ void enable() override { window->Enable(true); }
+ void disable() override { window->Enable(false); }
wxWindow* getWindow() override { return window; }
};
diff --git a/src/slic3r/GUI/FreeCADDialog.cpp b/src/slic3r/GUI/FreeCADDialog.cpp
index c02788ff6..1d2bc1b8a 100644
--- a/src/slic3r/GUI/FreeCADDialog.cpp
+++ b/src/slic3r/GUI/FreeCADDialog.cpp
@@ -452,7 +452,7 @@ void FreeCADDialog::on_autocomp_complete(wxStyledTextEvent& event) {
} else if (((command->type & PyCommandType::pctMODIFIER) != 0) && !has_already_parenthese) {
int nb_add_pos = 0;
//check if there's not a forgotten '.' before
- std::cout << "char before the word : " << stc->GetCharAt(currentPos - command->name.length() - 1) << "\n";
+ BOOST_LOG_TRIVIAL(warning) << "char before the word : " << stc->GetCharAt(currentPos - command->name.length() - 1) << "\n";
if (stc->GetCharAt(currentPos - command->name.length() - 1) == ')') {
stc->InsertText(currentPos - command->name.length(), ".");
nb_add_pos++;
@@ -481,19 +481,9 @@ void FreeCADDialog::on_word_change_for_autocomplete(wxStyledTextEvent& event) {
if ((event.GetModificationType() & (wxSTC_MOD_INSERTTEXT | wxSTC_PERFORMED_USER)) != (wxSTC_MOD_INSERTTEXT | wxSTC_PERFORMED_USER)) {
return; // not our event
}
- //std::cout << "word_change "<<event.GetModificationType()<<" typed: " << (int)stc->GetCharAt(current_pos) << " with len_entered " << len_entered
- //<< ", event_string='"<< event_string << "' (last='"<< (event_string.empty()?-1:event_string.Last().GetValue()) <<"') ; Str is '" << str << "' with length " << str.length()
- // << "' chars are (c-1)='" << stc->GetCharAt(current_pos - 1) << "' : (c)='" << stc->GetCharAt(current_pos)
- //<< "', text length=" << stc->GetTextLength() << ", currentPos=" << current_pos << " , " << int('\n') << "\n";
- //std::cout << "test: " << (!(stc->GetCharAt(current_pos - 1) <= '\n')) << ", 2=" << (len_entered >= 0) << ", 3=" << (!str.empty())
- // << ", 4=" << (std::regex_match(str.ToStdString(), word_regex))
- // <<", Mod5="<<((event.GetModificationType() & wxSTC_STARTACTION) != 0)
- // <<", 6="<< (current_pos <= 1 || str != ".")<<", 6b="<< (str == ".")
- // << "\n";
if ((event.GetModificationType() & wxSTC_STARTACTION) != 0 && (str.empty() || str.Last() != '.'))
return;
- //if (!event_string.empty() && !str.empty() && int(str[str.length() - 1]) != event_string.Last().GetValue()) std::cout << "removecall?\n";
if (len_entered >= 0 && !str.empty() && std::regex_match(str.ToStdString(), word_regex)) {
//check for possible words
//todo: check for '.' to filter for modifiers
@@ -509,33 +499,24 @@ void FreeCADDialog::on_word_change_for_autocomplete(wxStyledTextEvent& event) {
if (nb_words >= 1)
stc->AutoCompShow(len_entered, possible);
} else if (!str.empty() && str.Last() == '.') {
- //wxString possible;
- //for(const wxString &str : modif_words)
- // possible += possible.empty() ? str : (" " + str);
wxString possible;
for (const PyCommand &cmd : commands) {
if (((cmd.type & PyCommandType::pctMODIFIER) != 0) && ((cmd.type & PyCommandType::pctDO_NOT_SHOW) == 0)) {
possible += possible.empty() ? cmd.name : (" " + cmd.name);
}
}
- //std::cout << "autocomplete: modifier: '"<< possible.ToStdString() <<"'\n";
if (possible.length() >= 1)
stc->AutoCompShow(0, possible);
}
}
void FreeCADDialog::on_char_add(wxStyledTextEvent& event) {
- //if (event.GetUpdated() != wxSTC_UPDATE_CONTENT) return;
wxStyledTextCtrl* stc = (wxStyledTextCtrl*)event.GetEventObject();
// Find the word start
int current_pos = stc->GetCurrentPos();
int word_start_pos = stc->WordStartPosition(current_pos, true);
//int len_entered = current_pos - word_start_pos;
const wxString str = stc->GetTextRange(word_start_pos, current_pos + 1);
- //if(current_pos>1)
- // std::cout << "char typed: " << (char)stc->GetCharAt(current_pos)<<" with length "<< len_entered
- // << ", str is "<< str << "chars are '"<< stc->GetCharAt(current_pos - 1) << "' : '" << stc->GetCharAt(current_pos)
- // <<"', text length="<< stc->GetTextLength()<<", currentPos="<< current_pos<<" , "<<int('\n')<<"\n";
if(current_pos > 2 && stc->GetCharAt(current_pos-1) == '\n'){
//TODO: check that we are really in a freepyscad section.
int lastpos = current_pos - 2;
@@ -615,7 +596,6 @@ void FreeCADDialog::comment(bool is_switch) {
}
void FreeCADDialog::on_char_type(wxKeyEvent &event) {
- //std::cout << "on_char_type " << event.GetUnicodeKey() <<", " << event.GetModifiers() << "\n";
if (event.GetUnicodeKey() == 'Q' && event.GetModifiers() == wxMOD_CONTROL) {
comment(true);
} else if (event.GetUnicodeKey() == 'K' && event.GetModifiers() == wxMOD_CONTROL) {
@@ -629,14 +609,12 @@ void FreeCADDialog::on_char_type(wxKeyEvent &event) {
// space, back, del are ok but no ascii char
void FreeCADDialog::on_key_type(wxKeyEvent& event)
{
- //std::cout << "on_key_type " << event.GetUnicodeKey() << " ? "<< int('Q') <<", "<< event.GetKeyCode() << ", " << event.GetModifiers() << "\n";
if (event.GetKeyCode() == WXK_SPACE && event.GetModifiers() == wxMOD_CONTROL)
{
//get word, if any
int current_pos = m_text->GetCurrentPos();
int word_start_pos = m_text->WordStartPosition(current_pos, true);
const wxString str = m_text->GetTextRange(word_start_pos, current_pos);
- //std::cout << "ctrl-space! " << event.GetEventType() << " '" << str.ToStdString() << "' " << int(m_text->GetCharAt(current_pos - 1)) << "\n";
if (current_pos > 0 && m_text->GetCharAt(current_pos - 1) == '.') {
//only modifiers
wxString possible;
@@ -656,7 +634,6 @@ void FreeCADDialog::on_key_type(wxKeyEvent& event)
nb_words++; possible += possible.empty() ? cmd.name : (" " + cmd.name);
}
}
- //std::cout << "space autocomplete: find " << nb_words << " forstring '" << str << "'\n";
// Display the autocompletion list
if (nb_words >= 1)
m_text->AutoCompShow(str.length(), possible);
@@ -714,10 +691,8 @@ void FreeCADDialog::createSTC()
m_text = new wxStyledTextCtrl(this, wxID_ANY,
wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO);
- //m_text->SetMarginWidth(MARGIN_LINE_NUMBERS, 50);
m_text->StyleSetForeground(wxSTC_STYLE_LINENUMBER, wxColour(75, 75, 75));
m_text->StyleSetBackground(wxSTC_STYLE_LINENUMBER, wxColour(220, 220, 220));
- //m_text->SetMarginType(MARGIN_LINE_NUMBERS, wxSTC_MARGIN_NUMBER);
m_text->SetTabWidth(4);
m_text->SetIndent(4);
@@ -818,22 +793,20 @@ void FreeCADDialog::test_update_script_file(std::string &json) {
boost::locale::generator gen;
std::locale loc = gen.generate(""); // or "C", "en_US.UTF-8" etc.
std::locale::global(loc);
- std::cout.imbue(loc);
- std::cout << "root.commit.committer.date=" << str_date << "\n";
+ BOOST_LOG_TRIVIAL(debug) << "root.commit.committer.date=" << str_date;
std::time_t commit_time = parse_iso_time(str_date);
- std::cout << "github time_t = "<<commit_time<<"\n";
+ BOOST_LOG_TRIVIAL(debug) << "github time_t = " << commit_time;
std::time_t last_modif = boost::filesystem::last_write_time(pyscad_path / "freepyscad.py");
- std::cout << "pyscad_path time_t = " << commit_time << "\n";
+ BOOST_LOG_TRIVIAL(debug) << "pyscad_path time_t = " << commit_time;
if (commit_time > last_modif) {
- std::cout << "have to update!!\n";
get_file_from_web("https://raw.githubusercontent.com/supermerill/FreePySCAD/master/__init__.py", pyscad_path / "__init__.py");
get_file_from_web("https://raw.githubusercontent.com/supermerill/FreePySCAD/master/Init.py", pyscad_path / "Init.py");
get_file_from_web("https://raw.githubusercontent.com/supermerill/FreePySCAD/master/freepyscad.py", pyscad_path / "freepyscad.py");
}
}
catch (std::exception ex) {
- std::cerr << "Error, cannot parse https://api.github.com/repos/supermerill/FreePySCAD/commits/master: " << ex.what() << "\n";
+ BOOST_LOG_TRIVIAL(error) << "Error, cannot parse https://api.github.com/repos/supermerill/FreePySCAD/commits/master: " << ex.what();
}
}
@@ -872,7 +845,7 @@ bool FreeCADDialog::init_start_python() {
get_file_from_web("https://raw.githubusercontent.com/supermerill/FreePySCAD/master/__init__.py", scripts_path / "FreePySCAD" / "__init__.py");
get_file_from_web("https://raw.githubusercontent.com/supermerill/FreePySCAD/master/Init.py", scripts_path / "FreePySCAD" / "Init.py");
get_file_from_web("https://raw.githubusercontent.com/supermerill/FreePySCAD/master/freepyscad.py", scripts_path / "FreePySCAD" / "freepyscad.py");
- }else if (!update_done){
+ } else if (!update_done) {
update_done = true;
//try to check last version on website
//it's async so maybe you won't update it in time, but it's not the end of the world.
@@ -881,7 +854,7 @@ bool FreeCADDialog::init_start_python() {
get_string_from_web_async("https://api.github.com/repos/supermerill/FreePySCAD/commits/master", this, &FreeCADDialog::test_update_script_file);
}
- exec_var->process.reset(new boost::process::child(pythonpath.string() + " -u -i", boost::process::std_in < exec_var->pyin,
+ exec_var->process.reset(new boost::process::child(pythonpath.string() + " -u -i", boost::process::std_in < exec_var->pyin,
boost::process::std_out > exec_var->data_out, boost::process::std_err > exec_var->data_err, exec_var->ios));
exec_var->pyin << "import sys" << std::endl;
#ifndef __WINDOWS__
@@ -892,9 +865,7 @@ bool FreeCADDialog::init_start_python() {
exec_var->pyin << "import Part" << std::endl;
exec_var->pyin << "import Draft" << std::endl;
exec_var->pyin << "sys.path.append('" << scripts_path.generic_string() << "')" << std::endl;
- //std::cout << "sys.path.append('" << pyscad_path.generic_string() << "')" << std::endl;
exec_var->pyin << "from FreePySCAD.freepyscad import *" << std::endl;
- //std::cout << "from FreePySCAD.freepyscad import *" << std::endl;
exec_var->pyin << "App.newDocument(\"document\")" << std::endl;
#ifdef __WINDOWS__
exec_var->pyin << "set_font_dir(\"C:/Windows/Fonts/\")" << std::endl;
@@ -997,7 +968,6 @@ void FreeCADDialog::create_geometry(wxCommandEvent& event_args) {
}
- //std::cout<< "scene().redraw(" << boost::replace_all_copy(boost::replace_all_copy(m_text->GetText(), "\r", ""), "\n", "") << ")" << std::endl;
//exec_var->pyin << "scene().redraw("<< boost::replace_all_copy(boost::replace_all_copy(m_text->GetText(), "\r", ""), "\n", "") <<")" << std::endl;
exec_var->pyin << ("exec(open('" + temp_file.generic_string() + "').read())\n");
//filter to avoid importing "intermediate" object like ones from importStl
@@ -1008,11 +978,9 @@ void FreeCADDialog::create_geometry(wxCommandEvent& event_args) {
end_python();
std::string pyout_str_hello;
- std::cout << "==cout==\n";
- std::cout << exec_var->data_out.get();
- std::cout << "==cerr==\n";
+ BOOST_LOG_TRIVIAL(trace) << "==cout==\n" << exec_var->data_out.get()<<"\n";
std::string errStr = exec_var->data_err.get();
- std::cout << errStr << "\n";
+ BOOST_LOG_TRIVIAL(trace) << "==cerr==\n" << errStr <<"\n";
std::string cleaned = boost::replace_all_copy(boost::replace_all_copy(errStr, ">>> ", ""),"\r","");
boost::replace_all(cleaned, "QWaitCondition: Destroyed while threads are still waiting\n", "");
boost::replace_all(cleaned, "Type \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n", "");
diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp
index dfca32b7a..3bcd38ab8 100644
--- a/src/slic3r/GUI/NotificationManager.cpp
+++ b/src/slic3r/GUI/NotificationManager.cpp
@@ -1204,11 +1204,19 @@ bool NotificationManager::push_notification_data(std::unique_ptr<NotificationMan
if (this->activate_existing(notification.get())) {
m_pop_notifications.back()->update(notification->get_data());
- canvas.request_extra_frame_delayed(33);
+ //request_extra_frame_delayed has to run from main thread
+ if (wxThread::IsMain())
+ canvas.request_extra_frame_delayed(33);
+ else
+ wxGetApp().CallAfter([&canvas]() { canvas.request_extra_frame_delayed(33); });
return false;
} else {
m_pop_notifications.emplace_back(std::move(notification));
- canvas.request_extra_frame_delayed(33);
+ //request_extra_frame_delayed has to run from main thread
+ if (wxThread::IsMain())
+ canvas.request_extra_frame_delayed(33);
+ else
+ wxGetApp().CallAfter([&canvas]() { canvas.request_extra_frame_delayed(33); });
return true;
}
}
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 0739bbd56..95766b1a5 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -1899,6 +1899,9 @@ bool Tab::create_pages(std::string setting_type_name, int idx_page)
}
else if (boost::starts_with(params[i], "width$")) {
option.opt.width = atoi(params[i].substr(6, params[i].size() - 6).c_str());
+#ifdef __WXGTK3__
+ option.opt.width += 4; // add width for the big [-][+] buttons
+#endif
}
else if (boost::starts_with(params[i], "height$")) {
option.opt.height = atoi(params[i].substr(7, params[i].size() - 7).c_str());
diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp
index 970cd8528..3053073c4 100644
--- a/src/slic3r/GUI/WipeTowerDialog.cpp
+++ b/src/slic3r/GUI/WipeTowerDialog.cpp
@@ -9,7 +9,11 @@
#include <wx/sizer.h>
int scale(const int val) { return val * Slic3r::GUI::wxGetApp().em_unit(); }
-int ITEM_WIDTH() { return scale(6); }
+#ifdef __WXGTK3__
+int ITEM_WIDTH() { return scale(10); }
+#else
+int ITEM_WIDTH() { return scale(6); }
+#endif
RammingDialog::RammingDialog(wxWindow* parent,const std::string& parameters)
: wxDialog(parent, wxID_ANY, _(L("Ramming customization")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/)