diff --git a/src/libslic3r/EdgeGrid.cpp b/src/libslic3r/EdgeGrid.cpp
index 2b2893c80..c34aca8f2 100644
--- a/src/libslic3r/EdgeGrid.cpp
+++ b/src/libslic3r/EdgeGrid.cpp
@@ -9,7 +9,9 @@
 #endif /* SLIC3R_GUI */
 
 #include "libslic3r.h"
+#include "ClipperUtils.hpp"
 #include "EdgeGrid.hpp"
+#include "SVG.hpp"
 
 #if 0
 // Enable debugging and assert in this file.
@@ -756,8 +758,8 @@ void EdgeGrid::Grid::calculate_sdf()
 	float search_radius = float(m_resolution<<1);
 	m_signed_distance_field.assign(nrows * ncols, search_radius);
 	// For each cell:
-	for (size_t r = 0; r < m_rows; ++ r) {
-		for (size_t c = 0; c < m_cols; ++ c) {
+	for (int r = 0; r < (int)m_rows; ++ r) {
+		for (int c = 0; c < (int)m_cols; ++ c) {
 			const Cell &cell = m_cells[r * m_cols + c];
 			// For each segment in the cell:
 			for (size_t i = cell.begin; i != cell.end; ++ i) {
@@ -842,6 +844,8 @@ void EdgeGrid::Grid::calculate_sdf()
 #if 0
 	static int iRun = 0;
 	++ iRun;
+    if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
+        wxImage::AddHandler(new wxPNGHandler);
 //#ifdef SLIC3R_GUI
 	{ 
 		wxImage img(ncols, nrows);
@@ -1356,9 +1360,101 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset, bool fill_holes) co
 	return out;
 }
 
+inline int segments_could_intersect(
+	const Slic3r::Point &ip1, const Slic3r::Point &ip2, 
+	const Slic3r::Point &jp1, const Slic3r::Point &jp2)
+{
+	Vec2i64 iv   = (ip2 - ip1).cast<int64_t>();
+	Vec2i64 vij1 = (jp1 - ip1).cast<int64_t>();
+	Vec2i64 vij2 = (jp2 - ip1).cast<int64_t>();
+	int64_t tij1 = cross2(iv, vij1);
+	int64_t tij2 = cross2(iv, vij2);
+	int     sij1 = (tij1 > 0) ? 1 : ((tij1 < 0) ? -1 : 0); // signum
+	int     sij2 = (tij2 > 0) ? 1 : ((tij2 < 0) ? -1 : 0);
+	return sij1 * sij2;
+}
+
+inline bool segments_intersect(
+	const Slic3r::Point &ip1, const Slic3r::Point &ip2, 
+	const Slic3r::Point &jp1, const Slic3r::Point &jp2)
+{
+	return segments_could_intersect(ip1, ip2, jp1, jp2) <= 0 && 
+		   segments_could_intersect(jp1, jp2, ip1, ip2) <= 0;
+}
+
+std::vector<std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge>> EdgeGrid::Grid::intersecting_edges() const
+{
+	std::vector<std::pair<ContourEdge, ContourEdge>> out;
+	// For each cell:
+	for (int r = 0; r < (int)m_rows; ++ r) {
+		for (int c = 0; c < (int)m_cols; ++ c) {
+			const Cell &cell = m_cells[r * m_cols + c];
+			// For each pair of segments in the cell:
+			for (size_t i = cell.begin; i != cell.end; ++ i) {
+				const Slic3r::Points &ipts = *m_contours[m_cell_data[i].first];
+				size_t ipt = m_cell_data[i].second;
+				// End points of the line segment and their vector.
+				const Slic3r::Point &ip1 = ipts[ipt];
+				const Slic3r::Point &ip2 = ipts[(ipt + 1 == ipts.size()) ? 0 : ipt + 1];
+				for (size_t j = i + 1; j != cell.end; ++ j) {
+					const Slic3r::Points &jpts = *m_contours[m_cell_data[j].first];
+					size_t 				  jpt  = m_cell_data[j].second;
+					// End points of the line segment and their vector.
+					const Slic3r::Point  &jp1  = jpts[jpt];
+					const Slic3r::Point  &jp2  = jpts[(jpt + 1 == jpts.size()) ? 0 : jpt + 1];
+					if (&ipts == &jpts && (&ip1 == &jp2 || &jp1 == &ip2))
+						// Segments of the same contour share a common vertex.
+						continue;
+					if (segments_intersect(ip1, ip2, jp1, jp2)) {
+						// The two segments intersect. Add them to the output.
+						int jfirst = (&jpts < &ipts) || (&jpts == &ipts && jpt < ipt);
+						out.emplace_back(jfirst ? 
+							std::make_pair(std::make_pair(&ipts, ipt), std::make_pair(&jpts, jpt)) : 
+							std::make_pair(std::make_pair(&ipts, ipt), std::make_pair(&jpts, jpt)));
+					}
+				}
+			}
+		}
+	}
+	Slic3r::sort_remove_duplicates(out);
+	return out;
+}
+
+bool EdgeGrid::Grid::has_intersecting_edges() const
+{
+	// For each cell:
+	for (int r = 0; r < (int)m_rows; ++ r) {
+		for (int c = 0; c < (int)m_cols; ++ c) {
+			const Cell &cell = m_cells[r * m_cols + c];
+			// For each pair of segments in the cell:
+			for (size_t i = cell.begin; i != cell.end; ++ i) {
+				const Slic3r::Points &ipts = *m_contours[m_cell_data[i].first];
+				size_t ipt = m_cell_data[i].second;
+				// End points of the line segment and their vector.
+				const Slic3r::Point &ip1 = ipts[ipt];
+				const Slic3r::Point &ip2 = ipts[(ipt + 1 == ipts.size()) ? 0 : ipt + 1];
+				for (size_t j = i + 1; j != cell.end; ++ j) {
+					const Slic3r::Points &jpts = *m_contours[m_cell_data[j].first];
+					size_t 				  jpt  = m_cell_data[j].second;
+					// End points of the line segment and their vector.
+					const Slic3r::Point  &jp1  = jpts[jpt];
+					const Slic3r::Point  &jp2  = jpts[(jpt + 1 == jpts.size()) ? 0 : jpt + 1];
+					if (! (&ipts == &jpts && (&ip1 == &jp2 || &jp1 == &ip2)) && 
+						segments_intersect(ip1, ip2, jp1, jp2))
+						return true;
+				}
+			}
+		}
+	}
+	return false;
+}
+
 #if 0
 void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path)
 {
+    if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
+        wxImage::AddHandler(new wxPNGHandler);
+
 	unsigned int w = (bbox.max(0) - bbox.min(0) + resolution - 1) / resolution;
 	unsigned int h = (bbox.max(1) - bbox.min(1) + resolution - 1) / resolution;
 	wxImage img(w, h);
@@ -1450,4 +1546,59 @@ void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coo
 }
 #endif /* SLIC3R_GUI */
 
+// Find all pairs of intersectiong edges from the set of polygons.
+std::vector<std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge>> intersecting_edges(const Polygons &polygons)
+{
+	double len = 0;
+	size_t cnt = 0;
+	BoundingBox bbox;
+	for (const Polygon &poly : polygons) {
+		if (poly.points.size() < 2)
+			continue;
+		for (size_t i = 0; i < poly.points.size(); ++ i) {
+			bbox.merge(poly.points[i]);
+			size_t j = (i == 0) ? (poly.points.size() - 1) : i - 1;
+			len += (poly.points[j] - poly.points[i]).cast<double>().norm();
+			++ cnt;
+		}
+	}
+	len /= double(cnt);
+	bbox.offset(20);
+	EdgeGrid::Grid grid;
+	grid.set_bbox(bbox);
+	grid.create(polygons, len);
+	return grid.intersecting_edges();
+}
+
+// Find all pairs of intersectiong edges from the set of polygons, highlight them in an SVG.
+void export_intersections_to_svg(const std::string &filename, const Polygons &polygons)
+{
+	std::vector<std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge>> intersections = intersecting_edges(polygons);
+    BoundingBox bbox = get_extents(polygons);
+    SVG svg(filename.c_str(), bbox);
+    svg.draw(union_ex(polygons), "gray", 0.25f);
+    svg.draw_outline(polygons, "black");
+    std::set<const Points*> intersecting_contours;
+    for (const std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge> &ie : intersections) {
+    	intersecting_contours.insert(ie.first.first);
+    	intersecting_contours.insert(ie.second.first);
+    }
+    // Highlight the contours with intersections.
+    coord_t line_width = coord_t(scale_(0.01));
+    for (const Points *ic : intersecting_contours) {
+	    svg.draw_outline(Polygon(*ic), "green");
+	    svg.draw_outline(Polygon(*ic), "black", line_width);
+    }
+	// Paint the intersections.
+    for (const std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge> &intersecting_edges : intersections) {
+    	auto edge = [](const EdgeGrid::Grid::ContourEdge &e) {
+    		return Line(e.first->at(e.second),
+    					e.first->at((e.second + 1 == e.first->size()) ? 0 : e.second + 1));
+    	};
+        svg.draw(edge(intersecting_edges.first), "red", line_width);
+        svg.draw(edge(intersecting_edges.second), "red", line_width);
+    }
+    svg.Close();
+}
+
 } // namespace Slic3r
diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp
index d6bf03ce6..04319bb26 100644
--- a/src/libslic3r/Fill/FillGyroid.cpp
+++ b/src/libslic3r/Fill/FillGyroid.cpp
@@ -133,7 +133,7 @@ void FillGyroid::_fill_surface_single(
     // no rotation is supported for this infill pattern (yet)
     BoundingBox bb = expolygon.contour.bounding_box();
     // Density adjusted to have a good %of weight.
-    double      density_adjusted = std::max(0., params.density * 2.);
+    double      density_adjusted = std::max(0., params.density * 2.44);
     // Distance between the gyroid waves in scaled coordinates.
     coord_t     distance = coord_t(scale_(this->spacing) / density_adjusted);
 
diff --git a/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/src/libslic3r/GCode/WipeTowerPrusaMM.cpp
index f8f5fddd6..5c24cd71c 100644
--- a/src/libslic3r/GCode/WipeTowerPrusaMM.cpp
+++ b/src/libslic3r/GCode/WipeTowerPrusaMM.cpp
@@ -545,7 +545,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(
 	m_print_brim = true;
 
     // Ask our writer about how much material was consumed:
-    m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
+    if (m_current_tool < m_used_filament_length.size())
+    	m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
 
 	ToolChangeResult result;
     result.priming      = true;
@@ -698,7 +699,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(bool sideOnly, flo
     m_print_brim = false;  // Mark the brim as extruded
 
     // Ask our writer about how much material was consumed:
-    m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
+    if (m_current_tool < m_used_filament_length.size())
+    	m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
 
 	ToolChangeResult result;
     result.priming      = false;
@@ -868,7 +870,8 @@ void WipeTowerPrusaMM::toolchange_Change(
 	material_type 		new_material)
 {
     // Ask the writer about how much of the old filament we consumed:
-    m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
+    if (m_current_tool < m_used_filament_length.size())
+    	m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
 
 	// Speed override for the material. Go slow for flex and soluble materials.
 	int speed_override;
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index 84c34e232..b02153128 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -521,10 +521,14 @@ void Model::adjust_min_z()
 unsigned int Model::get_auto_extruder_id(unsigned int max_extruders)
 {
     unsigned int id = s_auto_extruder_id;
-
-    if (++s_auto_extruder_id > max_extruders)
+    if (id > max_extruders) {
+        // The current counter is invalid, likely due to switching the printer profiles
+        // to a profile with a lower number of extruders.
         reset_auto_extruder_id();
-
+        id = s_auto_extruder_id;
+    } else if (++ s_auto_extruder_id > max_extruders) {
+        reset_auto_extruder_id();
+    }
     return id;
 }
 
diff --git a/src/libslic3r/MultiPoint.hpp b/src/libslic3r/MultiPoint.hpp
index 521b4dc4f..38020d6e8 100644
--- a/src/libslic3r/MultiPoint.hpp
+++ b/src/libslic3r/MultiPoint.hpp
@@ -107,6 +107,23 @@ extern BoundingBox get_extents(const MultiPoint &mp);
 extern BoundingBox get_extents_rotated(const std::vector<Point> &points, double angle);
 extern BoundingBox get_extents_rotated(const MultiPoint &mp, double angle);
 
+inline double length(const Points &pts) {
+    double total = 0;
+    if (! pts.empty()) {
+        auto it = pts.begin();
+        for (auto it_prev = it ++; it != pts.end(); ++ it, ++ it_prev)
+            total += (*it - *it_prev).cast<double>().norm();
+    }
+    return total;
+}
+
+inline double area(const Points &polygon) {
+    double area = 0.;
+    for (size_t i = 0, j = polygon.size() - 1; i < polygon.size(); j = i ++)
+		area += double(polygon[i](0) + polygon[j](0)) * double(polygon[i](1) - polygon[j](1));
+    return area;
+}
+
 } // namespace Slic3r
 
 #endif
diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp
index 277fc5877..82df93cc1 100644
--- a/src/libslic3r/Point.hpp
+++ b/src/libslic3r/Point.hpp
@@ -187,6 +187,24 @@ public:
             m_map.emplace(std::make_pair(Vec2crd(pt->x()>>m_grid_log2, pt->y()>>m_grid_log2), std::move(value)));
     }
 
+    // Erase a data point equal to value. (ValueType has to declare the operator==).
+    // Returns true if the data point equal to value was found and removed.
+    bool erase(const ValueType &value) {
+        const Point *pt = m_point_accessor(value);
+        if (pt != nullptr) {
+            // Range of fragment starts around grid_corner, close to pt.
+            auto range = m_map.equal_range(Point(pt->x>>m_grid_log2, pt->y>>m_grid_log2));
+            // Remove the first item.
+            for (auto it = range.first; it != range.second; ++ it) {
+                if (it->second == value) {
+                    m_map.erase(it);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     // Return a pair of <ValueType*, distance_squared>
     std::pair<const ValueType*, double> find(const Vec2crd &pt) {
         // Iterate over 4 closest grid cells around pt,
@@ -214,7 +232,7 @@ public:
                 }
             }
         }
-        return (value_min != nullptr && dist_min < coordf_t(m_search_radius * m_search_radius)) ? 
+        return (value_min != nullptr && dist_min < coordf_t(m_search_radius) * coordf_t(m_search_radius)) ? 
             std::make_pair(value_min, dist_min) : 
             std::make_pair(nullptr, std::numeric_limits<double>::max());
     }
diff --git a/src/libslic3r/Polyline.hpp b/src/libslic3r/Polyline.hpp
index 925b88aca..e17fafd62 100644
--- a/src/libslic3r/Polyline.hpp
+++ b/src/libslic3r/Polyline.hpp
@@ -81,8 +81,8 @@ extern BoundingBox get_extents(const Polylines &polylines);
 
 inline double total_length(const Polylines &polylines) {
     double total = 0;
-    for (Polylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it)
-        total += it->length();
+    for (const Polyline &pl : polylines)
+        total += pl.length();
     return total;
 }
 
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index fb6d90d60..e382c7dbc 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -281,16 +281,17 @@ bool Print::is_step_done(PrintObjectStep step) const
 std::vector<unsigned int> Print::object_extruders() const
 {
     std::vector<unsigned int> extruders;
+    extruders.reserve(m_regions.size() * 3);
     
-    for (PrintRegion* region : m_regions) {
+    for (const PrintRegion *region : m_regions) {
         // these checks reflect the same logic used in the GUI for enabling/disabling
         // extruder selection fields
         if (region->config().perimeters.value > 0 || m_config.brim_width.value > 0)
-            extruders.push_back(region->config().perimeter_extruder - 1);
+            extruders.emplace_back(region->config().perimeter_extruder - 1);
         if (region->config().fill_density.value > 0)
-            extruders.push_back(region->config().infill_extruder - 1);
+            extruders.emplace_back(region->config().infill_extruder - 1);
         if (region->config().top_solid_layers.value > 0 || region->config().bottom_solid_layers.value > 0)
-            extruders.push_back(region->config().solid_infill_extruder - 1);
+            extruders.emplace_back(region->config().solid_infill_extruder - 1);
     }
     
     sort_remove_duplicates(extruders);
@@ -480,14 +481,6 @@ bool Print::apply_config(DynamicPrintConfig config)
         PrintObjectConfig new_config = this->default_object_config();
         // we override the new config with object-specific options
         normalize_and_apply_config(new_config, object->model_object()->config);
-        // Force a refresh of a variable layer height profile at the PrintObject if it is not valid.
-        if (! object->layer_height_profile_valid) {
-            // The layer_height_profile is not valid for some reason (updated by the user or invalidated due to some option change).
-            // Invalidate the slicing step, which in turn invalidates everything.
-            object->invalidate_step(posSlice);
-            // Trigger recalculation.
-            invalidated = true;
-        }
         // check whether the new config is different from the current one
         t_config_option_keys diff = object->config().diff(new_config);
         object->config_apply_only(new_config, diff, true);
@@ -567,8 +560,7 @@ exit_for_rearrange_regions:
 
     // Always make sure that the layer_height_profiles are set, as they should not be modified from the worker threads.
     for (PrintObject *object : m_objects)
-        if (! object->layer_height_profile_valid)
-            object->update_layer_height_profile();
+        object->update_layer_height_profile();
     
     return invalidated;
 }
@@ -1141,6 +1133,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
     // Always make sure that the layer_height_profiles are set, as they should not be modified from the worker threads.
     for (PrintObject *object : m_objects)
         if (! object->layer_height_profile_valid)
+            // No need to call the next line as the step should already be invalidated above.
+            // update_apply_status(object->invalidate_step(posSlice));
             object->update_layer_height_profile();
 
     //FIXME there may be a race condition with the G-code export running at the background thread.
@@ -1165,6 +1159,7 @@ bool Print::has_skirt() const
         || this->has_infinite_skirt();
 }
 
+// Precondition: Print::validate() requires the Print::apply() to be called its invocation.
 std::string Print::validate() const
 {
     if (m_objects.empty())
@@ -1253,12 +1248,10 @@ std::string Print::validate() const
                 return L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance");
             if (! equal_layering(slicing_params, slicing_params0))
                 return L("The Wipe Tower is only supported for multiple objects if they are sliced equally.");
-            bool was_layer_height_profile_valid = object->layer_height_profile_valid;
-            object->update_layer_height_profile();
-            object->layer_height_profile_valid = was_layer_height_profile_valid;
 
             if ( m_config.variable_layer_height ) { // comparing layer height profiles
                 bool failed = false;
+                // layer_height_profile should be set by Print::apply().
                 if (tallest_object->layer_height_profile.size() >= object->layer_height_profile.size() ) {
                     int i = 0;
                     while ( i < object->layer_height_profile.size() && i < tallest_object->layer_height_profile.size()) {
diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp
index 872ce31db..529608445 100644
--- a/src/libslic3r/Print.hpp
+++ b/src/libslic3r/Print.hpp
@@ -78,7 +78,6 @@ private: // Prevents erroneous use by other classes.
 public:
     // vector of (vectors of volume ids), indexed by region_id
     std::vector<std::vector<int>> region_volumes;
-    t_layer_height_ranges   layer_height_ranges;
 
     // Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
     // The pairs of <z, layer_height> are packed into a 1D array to simplify handling by the Perl XS.
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 10f5a1ac2..4b7a8906f 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -65,7 +65,6 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_insta
         this->set_copies(copies);
     }
 
-    this->layer_height_ranges = model_object->layer_height_ranges;
     this->layer_height_profile = model_object->layer_height_profile;
 }
 
@@ -1109,7 +1108,7 @@ void PrintObject::discover_vertical_shells()
 #if 1
                     // Intentionally inflate a bit more than how much the region has been shrunk, 
                     // so there will be some overlap between this solid infill and the other infill regions (mainly the sparse infill).
-                    shell = offset2(shell, - 0.5f * min_perimeter_infill_spacing, 0.8f * min_perimeter_infill_spacing, ClipperLib::jtSquare);
+                    shell = offset(offset_ex(union_ex(shell), - 0.5f * min_perimeter_infill_spacing), 0.8f * min_perimeter_infill_spacing, ClipperLib::jtSquare);
                     if (shell.empty())
                         continue;
 #else
@@ -1330,7 +1329,7 @@ bool PrintObject::update_layer_height_profile(std::vector<coordf_t> &layer_heigh
     bool updated = false;
 
     // If the layer height profile is not set, try to use the one stored at the ModelObject.
-    if (layer_height_profile.empty() && layer_height_profile.data() != this->model_object()->layer_height_profile.data()) {
+    if (layer_height_profile.empty()) {
         layer_height_profile = this->model_object()->layer_height_profile;
         updated = true;
     }
@@ -1347,10 +1346,9 @@ bool PrintObject::update_layer_height_profile(std::vector<coordf_t> &layer_heigh
     if (layer_height_profile.empty()) {
         if (0)
 //        if (this->layer_height_profile.empty())
-            layer_height_profile = layer_height_profile_adaptive(slicing_params, this->layer_height_ranges,
-                this->model_object()->volumes);
+			layer_height_profile = layer_height_profile_adaptive(slicing_params, this->model_object()->layer_height_ranges, this->model_object()->volumes);
         else
-            layer_height_profile = layer_height_profile_from_ranges(slicing_params, this->layer_height_ranges);
+			layer_height_profile = layer_height_profile_from_ranges(slicing_params, this->model_object()->layer_height_ranges);
         updated = true;
     }
     return updated;
diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp
index d85cf334b..28e6e1018 100644
--- a/src/slic3r/GUI/AppConfig.cpp
+++ b/src/slic3r/GUI/AppConfig.cpp
@@ -16,6 +16,7 @@
 #include <boost/property_tree/ini_parser.hpp>
 #include <boost/property_tree/ptree.hpp>
 #include <boost/algorithm/string/predicate.hpp>
+#include <boost/format.hpp>
 
 namespace Slic3r {
 
@@ -125,8 +126,13 @@ void AppConfig::load()
 
 void AppConfig::save()
 {
+    // The config is first written to a file with a PID suffix and then moved
+    // to avoid race conditions with multiple instances of Slic3r
+    const auto path = config_path();
+    std::string path_pid = (boost::format("%1%.%2%") % path % get_current_pid()).str();
+
     boost::nowide::ofstream c;
-    c.open(AppConfig::config_path(), std::ios::out | std::ios::trunc);
+    c.open(path_pid, std::ios::out | std::ios::trunc);
     c << "# " << Slic3r::header_slic3r_generated() << std::endl;
     // Make sure the "no" category is written first.
     for (const std::pair<std::string, std::string> &kvp : m_storage[""])
@@ -155,6 +161,8 @@ void AppConfig::save()
         }
     }
     c.close();
+
+    rename_file(path_pid, path);
     m_dirty = false;
 }
 
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 5dc685111..ae5743f67 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -323,17 +323,17 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) :
                 double brim_width = config->opt_float("brim_width");
                 if (boost::any_cast<bool>(value) == true)
                 {
-                    new_val = m_brim_width == 0.0 ? 10 :
+                    new_val = m_brim_width == 0.0 ? 5 :
                         m_brim_width < 0.0 ? m_brim_width * (-1) :
                         m_brim_width;
                 }
-                else{
+                else {
                     m_brim_width = brim_width * (-1);
                     new_val = 0;
                 }
                 new_conf.set_key_value("brim_width", new ConfigOptionFloat(new_val));
             }
-            else{ //(opt_key == "support")
+            else { //(opt_key == "support")
                 const wxString& selection = boost::any_cast<wxString>(value);
 
                 auto support_material = selection == _("None") ? false : true;