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
path: root/src
diff options
context:
space:
mode:
authorsupermerill <merill@free.fr>2021-12-23 01:26:51 +0300
committersupermerill <merill@free.fr>2021-12-23 01:26:51 +0300
commitde7bfabae8677914aab6bb047e5fcaf24f7b7d6d (patch)
tree9c88fd4ee36aa796d5733583d296715fedbcd4ea /src
parent8dc30cf6353e085134d5d8147437e368f269e924 (diff)
parent9198f9e26eb4f49296d3a88e6f182ae95c908968 (diff)
merge fixes
Diffstat (limited to 'src')
-rw-r--r--src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp5
-rw-r--r--src/libslic3r/AppConfig.cpp9
-rw-r--r--src/libslic3r/Config.hpp1
-rw-r--r--src/libslic3r/Fill/FillConcentric.cpp4
-rw-r--r--src/libslic3r/Fill/FillGyroid.cpp2
-rw-r--r--src/libslic3r/Format/CWS.cpp4
-rw-r--r--src/libslic3r/GCode.cpp120
-rw-r--r--src/libslic3r/GCode.hpp2
-rw-r--r--src/libslic3r/GCode/AvoidCrossingPerimeters.cpp2
-rw-r--r--src/libslic3r/GCode/FanMover.cpp2
-rw-r--r--src/libslic3r/GCodeWriter.cpp5
-rw-r--r--src/libslic3r/MedialAxis.cpp232
-rw-r--r--src/libslic3r/PerimeterGenerator.cpp44
-rw-r--r--src/libslic3r/PlaceholderParser.cpp86
-rw-r--r--src/libslic3r/Point.hpp2
-rw-r--r--src/libslic3r/Polyline.cpp18
-rw-r--r--src/libslic3r/Preset.cpp2
-rw-r--r--src/libslic3r/Print.cpp3
-rw-r--r--src/libslic3r/PrintBase.cpp2
-rw-r--r--src/libslic3r/PrintConfig.cpp99
-rw-r--r--src/libslic3r/PrintConfig.hpp2
-rw-r--r--src/libslic3r/PrintObject.cpp2
-rw-r--r--src/libslic3r/libslic3r.h26
-rw-r--r--src/slic3r/GUI/3DBed.cpp4
-rw-r--r--src/slic3r/GUI/CalibrationAbstractDialog.cpp4
-rw-r--r--src/slic3r/GUI/ConfigManipulation.cpp28
-rw-r--r--src/slic3r/GUI/GUI_App.cpp2
-rw-r--r--src/slic3r/GUI/GUI_ObjectList.cpp2
-rw-r--r--src/slic3r/GUI/KBShortcutsDialog.cpp16
-rw-r--r--src/slic3r/GUI/MainFrame.cpp4
-rw-r--r--src/slic3r/GUI/PhysicalPrinterDialog.cpp1
-rw-r--r--src/slic3r/GUI/Preferences.cpp8
-rw-r--r--src/slic3r/GUI/Search.cpp2
-rw-r--r--src/slic3r/GUI/Tab.cpp29
-rw-r--r--src/slic3r/Utils/PresetUpdater.cpp5
35 files changed, 545 insertions, 234 deletions
diff --git a/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp b/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp
index 29a1ccd04..07b34f47d 100644
--- a/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp
+++ b/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp
@@ -281,9 +281,10 @@ inline NfpResult<RawShape> nfpConvexOnly(const RawShape& sh,
// cos function. But with the quadrant info we can get the sign back
int sign = q[0] == 1 || q[0] == 2 ? -1 : 1;
+ // supermerill: add safe-check for when two points are on the same position
// If Ratio is an actual rational type, there is no precision loss
- auto pcos1 = Ratio(lcos[0]) / lsq1 * sign * lcos[0];
- auto pcos2 = Ratio(lcos[1]) / lsq2 * sign * lcos[1];
+ auto pcos1 = lsq1 != 0 ? Ratio(lcos[0]) / lsq1 * sign * lcos[0] : 1 * sign * lcos[0];
+ auto pcos2 = lsq2 != 0 ? Ratio(lcos[1]) / lsq2 * sign * lcos[1] : 1 * sign * lcos[1];
return q[0] < 2 ? pcos1 < pcos2 : pcos1 > pcos2;
}
diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp
index 7ea96372c..60e02e626 100644
--- a/src/libslic3r/AppConfig.cpp
+++ b/src/libslic3r/AppConfig.cpp
@@ -9,15 +9,16 @@
#include <vector>
#include <stdexcept>
-#include <boost/filesystem/path.hpp>
+#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/format/format_fwd.hpp>
+#include <boost/locale.hpp>
+#include <boost/log/trivial.hpp>
#include <boost/nowide/cenv.hpp>
#include <boost/nowide/fstream.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree_fwd.hpp>
-#include <boost/algorithm/string/predicate.hpp>
-#include <boost/format/format_fwd.hpp>
-#include <boost/log/trivial.hpp>
#ifdef WIN32
//FIXME replace the two following includes with <boost/md5.hpp> after it becomes mainstream.
diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp
index 5ecd25ff2..5c8058aef 100644
--- a/src/libslic3r/Config.hpp
+++ b/src/libslic3r/Config.hpp
@@ -305,6 +305,7 @@ public:
enum FlagsConfigOption : uint32_t {
FCO_PHONY = 1,
FCO_EXTRUDER_ARRAY = 1 << 1,
+ FCO_PLACEHOLDER_TEMP = 1 << 2,
};
ConfigOption() : flags(uint32_t(0)) {}
diff --git a/src/libslic3r/Fill/FillConcentric.cpp b/src/libslic3r/Fill/FillConcentric.cpp
index c8616f42f..fd3270663 100644
--- a/src/libslic3r/Fill/FillConcentric.cpp
+++ b/src/libslic3r/Fill/FillConcentric.cpp
@@ -78,6 +78,8 @@ FillConcentricWGapFill::fill_surface_extrusion(
const FillParams &params,
ExtrusionEntitiesPtr &out) const {
+ double min_gapfill_area = double(params.flow.scaled_width()) * double(params.flow.scaled_width());
+ if (params.config != nullptr) min_gapfill_area = scale_d(params.config->gap_fill_min_area.get_abs_value(params.flow.width)) * double(params.flow.scaled_width());
// Perform offset.
Slic3r::ExPolygons expp = offset_ex(surface->expolygon, double(scale_(0 - 0.5 * this->get_spacing())));
// Create the infills for each of the regions.
@@ -149,7 +151,7 @@ FillConcentricWGapFill::fill_surface_extrusion(
for (const ExPolygon &ex : gaps_ex) {
//remove too small gaps that are too hard to fill.
//ie one that are smaller than an extrusion with width of min and a length of max.
- if (ex.area() > min*max) {
+ if (ex.area() > min_gapfill_area) {
MedialAxis{ ex, coord_t(max), coord_t(min), coord_t(params.flow.height) }.build(polylines);
}
}
diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp
index 0ff0972c5..461fc0e62 100644
--- a/src/libslic3r/Fill/FillGyroid.cpp
+++ b/src/libslic3r/Fill/FillGyroid.cpp
@@ -168,8 +168,6 @@ void FillGyroid::_fill_surface_single(
const double tolerance_old = std::min(this->get_spacing() / 2, FillGyroid::PatternTolerance) / unscaled(scaleFactor);
const double tolerance_old2 = std::min(this->get_spacing() / 2, FillGyroid::PatternTolerance) * density_adjusted / this->get_spacing();
const double tolerance = params.config->get_computed_value("resolution_internal") * density_adjusted / this->get_spacing();
- std::cout << "gyroid tolerance: " << tolerance_old << " == " << tolerance_old2 << " ? "<< tolerance << "\n";
- std::cout << "this->get_spacing(): " << this->get_spacing() << " , scaleFactor= " << unscaled(scaleFactor) << " , min(spa, 0.2)= " << std::min(this->get_spacing() / 2, FillGyroid::PatternTolerance) << "\n";
// generate pattern
Polylines polylines = make_gyroid_waves(
diff --git a/src/libslic3r/Format/CWS.cpp b/src/libslic3r/Format/CWS.cpp
index b28a47f50..395be5044 100644
--- a/src/libslic3r/Format/CWS.cpp
+++ b/src/libslic3r/Format/CWS.cpp
@@ -2,6 +2,10 @@
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/Time.hpp"
+#include <boost/log/trivial.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
+
namespace Slic3r {
using ConfMap = std::map<std::string, std::string>;
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index d8c6d6285..6a4b0a97a 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -16,9 +16,10 @@
#include <algorithm>
#include <cstdlib>
+#include <map>
#include <math.h>
+#include <unordered_set>
#include <string_view>
-#include <map>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/find.hpp>
@@ -3338,12 +3339,16 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
Point current_point = paths.front().first_point();
Point next_point = paths.front().polyline.points[1]; // second point
+ gcode += ";" + GCodeProcessor::Wipe_Start_Tag + "\n";
//extra wipe before the little move.
if (EXTRUDER_CONFIG_WITH_DEFAULT(wipe_extra_perimeter, 0) > 0) {
coordf_t wipe_dist = scale_(EXTRUDER_CONFIG_WITH_DEFAULT(wipe_extra_perimeter,0));
ExtrusionPaths paths_wipe;
+ m_wipe.reset_path();
for (int i = 0; i < paths.size(); i++) {
ExtrusionPath& path = paths[i];
+ if (wipe_dist > 0) {
+ //first, we use the polyline for wipe_extra_perimeter
if (path.length() < wipe_dist) {
wipe_dist -= path.length();
paths_wipe.push_back(path);
@@ -3362,8 +3367,14 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
} else {
next_point = paths[0].first_point();
}
- break;
+ m_wipe.path.append(path.polyline);
+ m_wipe.path.clip_start(wipe_dist);
+ wipe_dist -= path.length();
}
+ } else {
+ //then, it's stored for the wipe on retract
+ m_wipe.path.append(path.polyline);
+ }
}
//move
for (ExtrusionPath& path : paths_wipe) {
@@ -3371,6 +3382,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
prev_point = current_point;
current_point = pt;
gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), 0.0, config().gcode_comments ? "; extra wipe" : "");
+ this->set_last_pos(pt);
}
}
}
@@ -3398,7 +3410,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
Vec2d current_pos = current_point.cast<double>();
Vec2d next_pos = next_point.cast<double>();
Vec2d vec_dist = next_pos - current_pos;
- double nd = scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter,0));
+ const coordf_t nd = scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter,0));
double l2 = vec_dist.squaredNorm();
// Shift by no more than a nozzle diameter.
//FIXME Hiding the seams will not work nicely for very densely discretized contours!
@@ -3406,6 +3418,65 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
pt.rotate(angle, current_point);
// generate the travel move
gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), 0.0, "move inwards before travel");
+ this->set_last_pos(pt);
+ gcode += ";" + GCodeProcessor::Wipe_End_Tag + "\n";
+
+ // also shift the wipe on retract
+ if (m_wipe.enable) {
+ current_pos = pt.cast<double>();
+ //go to the inside (use clipper for easy shift)
+ Polygon original_polygon = original_loop.polygon();
+ Polygons polys = offset(original_polygon, (original_polygon.is_clockwise()?1:-1) * nd / 2);
+ //find nearest point
+ size_t best_poly_idx = 0;
+ size_t best_pt_idx = 0;
+ coordf_t best_sqr_dist = nd*nd*2;
+ for (size_t poly_idx = 0; poly_idx < polys.size(); poly_idx++) {
+ Polygon& poly = polys[poly_idx];
+ if (poly.is_clockwise() ^ original_polygon.is_clockwise())
+ poly.reverse();
+ for (size_t pt_idx = 0; pt_idx < poly.points.size(); pt_idx++) {
+ if (poly.points[pt_idx].distance_to_square(pt) < best_sqr_dist) {
+ best_sqr_dist = poly.points[pt_idx].distance_to_square(pt);
+ best_poly_idx = poly_idx;
+ best_pt_idx = pt_idx;
+ }
+ }
+ }
+ if (best_sqr_dist == nd * nd * 2) {
+ //try to find an edge
+ for (size_t poly_idx = 0; poly_idx < polys.size(); poly_idx++) {
+ Polygon& poly = polys[poly_idx];
+ if (poly.is_clockwise() ^ original_polygon.is_clockwise())
+ poly.reverse();
+ poly.points.push_back(poly.points.front());
+ for (size_t pt_idx = 0; pt_idx < poly.points.size()-1; pt_idx++) {
+ if (Line{ poly.points[pt_idx], poly.points[pt_idx + 1] }.distance_to_squared(pt) < best_sqr_dist) {
+ poly.points.insert(poly.points.begin() + pt_idx + 1, pt);
+ best_sqr_dist = 0;
+ best_poly_idx = poly_idx;
+ best_pt_idx = pt_idx + 1;
+ poly.points.erase(poly.points.end() - 1);
+ break;
+ }
+ }
+ }
+ }
+ if (best_sqr_dist == nd * nd * 2) {
+ //can't find a path, use the old one
+ //BOOST_LOG_TRIVIAL(warning) << "Warn: can't find a proper path for wipe on retract. Layer " << m_layer_index << ", pos " << this->point_to_gcode(pt).x() << " : " << this->point_to_gcode(pt).y() << " !";
+ } else {
+ m_wipe.reset_path();
+ //get the points from here
+ Polygon& poly = polys[best_poly_idx];
+ for (size_t pt_idx = best_pt_idx; pt_idx < poly.points.size(); pt_idx++) {
+ m_wipe.path.append(poly.points[pt_idx]);
+ }
+ for (size_t pt_idx = 0; pt_idx < best_pt_idx; pt_idx++) {
+ m_wipe.path.append(poly.points[pt_idx]);
+ }
+ }
+ }
}
return gcode;
@@ -4330,40 +4401,49 @@ Polyline GCode::travel_to(std::string &gcode, const Point &point, ExtrusionRole
this->origin in order to get G-code coordinates. */
Polyline travel { this->last_pos(), point };
- // check / compute avoid_crossing_perimeters
- bool will_cross_perimeter = this->can_cross_perimeter(travel);
// check whether wipe could be disabled without causing visible stringing
bool could_be_wipe_disabled = false;
+ //can use the avoid crossing algo?
+ bool can_avoid_cross_peri = m_config.avoid_crossing_perimeters
+ && !m_avoid_crossing_perimeters.disabled_once()
+ && m_avoid_crossing_perimeters.is_init()
+ && !(m_config.avoid_crossing_not_first_layer && this->on_first_layer());
+
+ // check / compute avoid_crossing_perimeters
+ bool will_cross_perimeter = this->can_cross_perimeter(travel, can_avoid_cross_peri);
+
// if a retraction would be needed (with a low min_dist threshold), try to use avoid_crossing_perimeters to plan a
// multi-hop travel path inside the configuration space
if (will_cross_perimeter && this->needs_retraction(travel, role, scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.4)) * 3)
- && m_config.avoid_crossing_perimeters
- && ! m_avoid_crossing_perimeters.disabled_once()
- && m_avoid_crossing_perimeters.is_init()
- && !(m_config.avoid_crossing_not_first_layer && this->on_first_layer())) {
+ && can_avoid_cross_peri) {
travel = m_avoid_crossing_perimeters.travel_to(*this, point, &could_be_wipe_disabled);
}
+ if(can_avoid_cross_peri)
+ will_cross_perimeter = this->can_cross_perimeter(travel, false);
// check whether a straight travel move would need retraction
bool needs_retraction = this->needs_retraction(travel, role);
+ if (m_config.only_retract_when_crossing_perimeters)
+ needs_retraction = needs_retraction && will_cross_perimeter;
// Re-allow avoid_crossing_perimeters for the next travel moves
m_avoid_crossing_perimeters.reset_once_modifiers();
// generate G-code for the travel move
if (needs_retraction) {
- if (m_config.avoid_crossing_perimeters && could_be_wipe_disabled)
+ if (m_config.avoid_crossing_perimeters && could_be_wipe_disabled && EXTRUDER_CONFIG_WITH_DEFAULT(wipe_only_crossing, true))
m_wipe.reset_path();
Point last_post_before_retract = this->last_pos();
gcode += this->retract();
// When "Wipe while retracting" is enabled, then extruder moves to another position, and travel from this position can cross perimeters.
- // Because of it, it is necessary to call avoid crossing perimeters for the path between previous last_post and last_post after calling retraction()
- if (last_post_before_retract != this->last_pos() && m_config.avoid_crossing_perimeters) {
- Polyline retract_travel = m_avoid_crossing_perimeters.travel_to(*this, last_post_before_retract);
- append(retract_travel.points, travel.points);
- travel = std::move(retract_travel);
+ if (last_post_before_retract != this->last_pos() && can_avoid_cross_peri) {
+ // Is the distance is short enough to just shortcut it?
+ if (last_post_before_retract.distance_to(this->last_pos()) > scale_d(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.4)) * 2) {
+ // Because of it, it is necessary to redo the thing
+ travel = m_avoid_crossing_perimeters.travel_to(*this, point);
+ }
}
} else {
// Reset the wipe path when traveling, so one would not wipe along an old path.
@@ -4471,7 +4551,7 @@ bool GCode::needs_retraction(const Polyline& travel, ExtrusionRole role /*=erNon
return true;
}
-bool GCode::can_cross_perimeter(const Polyline& travel)
+bool GCode::can_cross_perimeter(const Polyline& travel, bool offset)
{
if(m_layer != nullptr)
if ( (m_config.only_retract_when_crossing_perimeters && m_config.fill_density.value > 0) || m_config.avoid_crossing_perimeters)
@@ -4490,13 +4570,13 @@ bool GCode::can_cross_perimeter(const Polyline& travel)
//if (inside) {
//contained inside at least one bb
//construct m_layer_slices_offseted if needed
- if (m_layer_slices_offseted.layer != m_layer) {
+ if (m_layer_slices_offseted.layer != m_layer && offset) {
m_layer_slices_offseted.layer = m_layer;
m_layer_slices_offseted.diameter = scale_t(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0.4));
- m_layer_slices_offseted.slices = offset_ex(m_layer->lslices, - m_layer_slices_offseted.diameter * 1.5);
+ m_layer_slices_offseted.slices = offset_ex(m_layer->lslices, -m_layer_slices_offseted.diameter * 1.5f);
}
// test if a expoly contains the entire travel
- for (const ExPolygon &poly : m_layer_slices_offseted.slices)
+ for (const ExPolygon &poly : offset ? m_layer_slices_offseted.slices : m_layer->lslices)
if (poly.contains(travel)) {
return false;
}
@@ -4529,6 +4609,8 @@ std::string GCode::retract(bool toolchange)
methods even if we performed wipe, since this will ensure the entire retraction
length is honored in case wipe path was too short. */
gcode += toolchange ? m_writer.retract_for_toolchange() : m_writer.retract();
+
+ //check if need to lift
bool need_lift = !m_writer.tool_is_extruder() || toolchange
|| (BOOL_EXTRUDER_CONFIG(retract_lift_first_layer) && m_config.print_retract_lift.value != 0 && this->m_layer_index == 0)
|| this->m_writer.get_extra_lift() > 0;
diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp
index 7fab43e75..bfa644595 100644
--- a/src/libslic3r/GCode.hpp
+++ b/src/libslic3r/GCode.hpp
@@ -318,7 +318,7 @@ private:
Polyline travel_to(std::string& gcode, const Point &point, ExtrusionRole role);
void write_travel_to(std::string& gcode, const Polyline& travel, std::string comment);
- bool can_cross_perimeter(const Polyline& travel);
+ bool can_cross_perimeter(const Polyline& travel, bool offset);
bool needs_retraction(const Polyline& travel, ExtrusionRole role = erNone, coordf_t max_min_dist = 0);
std::string retract(bool toolchange = false);
std::string unretract() { return m_writer.unlift() + m_writer.unretract(); }
diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp
index 1d40a62bd..cad59bd32 100644
--- a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp
+++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp
@@ -9,6 +9,8 @@
#include "../SVG.hpp"
#include "AvoidCrossingPerimeters.hpp"
+#include <boost/log/trivial.hpp>
+
#include <numeric>
#include <unordered_set>
diff --git a/src/libslic3r/GCode/FanMover.cpp b/src/libslic3r/GCode/FanMover.cpp
index ca6db9ecf..6e138d1d2 100644
--- a/src/libslic3r/GCode/FanMover.cpp
+++ b/src/libslic3r/GCode/FanMover.cpp
@@ -242,6 +242,8 @@ void FanMover::_process_gcode_line(GCodeReader& reader, const GCodeReader::GCode
if (fan_speed >= 0) {
const auto fan_baseline = (m_writer.config.fan_percentage.value ? 100.0 : 255.0);
fan_speed = 100 * fan_speed / fan_baseline;
+ //speed change: stop kickstart reverting if any
+ m_current_kickstart.time = -1;
if (!m_is_custom_gcode) {
// if slow down => put in the queue. if not =>
if (m_back_buffer_fan_speed < fan_speed) {
diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp
index ede145d8d..09e45f1fe 100644
--- a/src/libslic3r/GCodeWriter.cpp
+++ b/src/libslic3r/GCodeWriter.cpp
@@ -1,10 +1,13 @@
#include "GCodeWriter.hpp"
#include "CustomGCode.hpp"
+
+#include <boost/lexical_cast.hpp>
+
#include <algorithm>
+#include <assert.h>
#include <iomanip>
#include <iostream>
#include <map>
-#include <assert.h>
#define FLAVOR_IS(val) this->config.gcode_flavor.value == val
#define FLAVOR_IS_NOT(val) this->config.gcode_flavor.value != val
diff --git a/src/libslic3r/MedialAxis.cpp b/src/libslic3r/MedialAxis.cpp
index c44c1d97a..02b4816e2 100644
--- a/src/libslic3r/MedialAxis.cpp
+++ b/src/libslic3r/MedialAxis.cpp
@@ -8,6 +8,9 @@
#include "SVG.hpp"
#include "polypartition.h"
#include "poly2tri/poly2tri.h"
+
+#include <boost/log/trivial.hpp>
+
#include <algorithm>
#include <cassert>
#include <list>
@@ -462,7 +465,7 @@ get_coeff_from_angle_countour(Point &point, const ExPolygon &contour, coord_t mi
if (angle >= PI) angle = 2 * PI - angle; // smaller angle
//compute the diff from 90°
angle = abs(angle - PI / 2);
- if (point_near.coincides_with(point_nearest) && std::max(nearest_dist, near_dist) + SCALED_EPSILON < point_nearest.distance_to(point_near)) {
+ if (point_near.coincides_with_epsilon(point_nearest) && std::max(nearest_dist, near_dist) + SCALED_EPSILON < point_nearest.distance_to(point_near)) {
//not only nearest
Point point_before = id_near == 0 ? contour.contour.points.back() : contour.contour.points[id_near - 1];
Point point_after = id_near == contour.contour.points.size() - 1 ? contour.contour.points.front() : contour.contour.points[id_near + 1];
@@ -499,7 +502,7 @@ MedialAxis::fusion_curve(ThickPolylines &pp)
//check my length is small
coord_t length = (coord_t)polyline.length();
- if (length > max_width) continue;
+ if (length > this->max_width) continue;
size_t closest_point_idx = this->expolygon.contour.closest_point_index(polyline.points.back());
@@ -529,13 +532,13 @@ MedialAxis::fusion_curve(ThickPolylines &pp)
for (size_t j = 0; j < pp.size(); ++j) {
if (j == i) continue;
ThickPolyline& other = pp[j];
- if (polyline.first_point().coincides_with(other.last_point())) {
+ if (polyline.first_point().coincides_with_epsilon(other.last_point())) {
other.reverse();
crosspoint.push_back(j);
double dot_temp = dot(Line(polyline.points[0], polyline.points[1]), (Line(other.points[0], other.points[1])));
min_dot = std::min(min_dot, abs(dot_temp));
sum_dot += dot_temp;
- } else if (polyline.first_point().coincides_with(other.first_point())) {
+ } else if (polyline.first_point().coincides_with_epsilon(other.first_point())) {
crosspoint.push_back(j);
double dot_temp = dot(Line(polyline.points[0], polyline.points[1]), (Line(other.points[0], other.points[1])));
min_dot = std::min(min_dot, abs(dot_temp));
@@ -604,7 +607,7 @@ MedialAxis::remove_bits(ThickPolylines &pp)
//check my length is small
coordf_t length = polyline.length();
- if (length > coordf_t(max_width) * 1.5) {
+ if (length > coordf_t(this->max_width) * 1.5) {
continue;
}
@@ -613,10 +616,10 @@ MedialAxis::remove_bits(ThickPolylines &pp)
for (size_t j = 0; j < pp.size(); ++j) {
if (j == i) continue;
ThickPolyline& other = pp[j];
- if (polyline.first_point().coincides_with(other.last_point())) {
+ if (polyline.first_point().coincides_with_epsilon(other.last_point())) {
other.reverse();
crosspoint.push_back(j);
- } else if (polyline.first_point().coincides_with(other.first_point())) {
+ } else if (polyline.first_point().coincides_with_epsilon(other.first_point())) {
crosspoint.push_back(j);
}
}
@@ -631,11 +634,11 @@ MedialAxis::remove_bits(ThickPolylines &pp)
if (nb_better_than_me < 2) continue;
//check if the length of the polyline is small vs width of the other lines
- coord_t max_width = 0;
+ coord_t local_max_width = 0;
for (int i = 0; i < crosspoint.size(); i++) {
- max_width = std::max(max_width, pp[crosspoint[i]].width[0]);
+ local_max_width = std::max(local_max_width, pp[crosspoint[i]].width[0]);
}
- if (length > coordf_t(max_width + min_width))
+ if (length > coordf_t(local_max_width + min_width))
continue;
//delete the now unused polyline
@@ -665,17 +668,17 @@ MedialAxis::fusion_corners(ThickPolylines &pp)
//check my length is small
coord_t length = (coord_t)polyline.length();
- if (length > max_width) continue;
+ if (length > this->max_width) continue;
// look if other end is a cross point with multiple other branch
std::vector<size_t> crosspoint;
for (size_t j = 0; j < pp.size(); ++j) {
if (j == i) continue;
ThickPolyline& other = pp[j];
- if (polyline.first_point().coincides_with(other.last_point())) {
+ if (polyline.first_point().coincides_with_epsilon(other.last_point())) {
other.reverse();
crosspoint.push_back(j);
- } else if (polyline.first_point().coincides_with(other.first_point())) {
+ } else if (polyline.first_point().coincides_with_epsilon(other.first_point())) {
crosspoint.push_back(j);
}
}
@@ -764,7 +767,7 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con
// prevent the line from touching on the other side, otherwise intersection() might return that solution
if (polyline.points.size() == 2 && this->expolygon.contains(line.midpoint())) line.a = line.midpoint();
- line.extend_end((double)max_width);
+ line.extend_end((double)this->max_width);
Point new_back;
if (this->expolygon.contour.has_boundary_point(polyline.points.back())) {
new_back = polyline.points.back();
@@ -842,14 +845,14 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con
}*/
// find anchor
Point best_anchor;
- coordf_t shortest_dist = (coordf_t)max_width;
+ coordf_t shortest_dist = (coordf_t)this->max_width;
for (const ExPolygon& a : anchors) {
Point p_maybe_inside = a.contour.centroid();
coordf_t test_dist = new_bound.distance_to(p_maybe_inside) + new_back.distance_to(p_maybe_inside);
//if (test_dist < max_width / 2 && (test_dist < shortest_dist || shortest_dist < 0)) {
double angle_test = new_back.ccw_angle(p_maybe_inside, line.a);
if (angle_test > PI) angle_test = 2 * PI - angle_test;
- if (test_dist < max_width && test_dist<shortest_dist && abs(angle_test) > PI / 2) {
+ if (test_dist < (coordf_t)this->max_width && test_dist<shortest_dist && abs(angle_test) > PI / 2) {
shortest_dist = test_dist;
best_anchor = p_maybe_inside;
}
@@ -859,7 +862,7 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con
p_obj.x() /= 2;
p_obj.y() /= 2;
Line l2 = Line(new_back, p_obj);
- l2.extend_end((double)max_width);
+ l2.extend_end((coordf_t)this->max_width);
(void)bounds->contour.first_intersection(l2, &new_bound);
}
if (new_bound.coincides_with_epsilon(new_back))
@@ -909,13 +912,13 @@ MedialAxis::main_fusion(ThickPolylines& pp)
// find another polyline starting here
for (size_t j = i + 1; j < pp.size(); ++j) {
ThickPolyline& other = pp[j];
- if (polyline.last_point().coincides_with(other.last_point())) {
+ if (polyline.last_point().coincides_with_epsilon(other.last_point())) {
polyline.reverse();
other.reverse();
- } else if (polyline.first_point().coincides_with(other.last_point())) {
+ } else if (polyline.first_point().coincides_with_epsilon(other.last_point())) {
other.reverse();
- } else if (polyline.first_point().coincides_with(other.first_point())) {
- } else if (polyline.last_point().coincides_with(other.first_point())) {
+ } else if (polyline.first_point().coincides_with_epsilon(other.first_point())) {
+ } else if (polyline.last_point().coincides_with_epsilon(other.first_point())) {
polyline.reverse();
} else {
continue;
@@ -936,10 +939,10 @@ MedialAxis::main_fusion(ThickPolylines& pp)
if (
((polyline.points.back().distance_to(other.points.back())
+ (polyline.width.back() + other.width.back()) / 4)
- > max_width*1.05))
+ > this->max_width *1.05))
continue;
// test if the lines are not too different in length.
- if (abs(polyline.length() - other.length()) > max_width) continue;
+ if (abs(polyline.length() - other.length()) > (coordf_t)this->max_width) continue;
//test if we don't merge with something too different and without any relevance.
@@ -955,7 +958,7 @@ MedialAxis::main_fusion(ThickPolylines& pp)
// << (abs(polyline.length()*coeffSizePolyI - other.length()*coeffSizeOtherJ) > max_width / 2)
// << (abs(polyline.length()*coeffSizePolyI - other.length()*coeffSizeOtherJ) > max_width)
// << "\n";
- if (abs(polyline.length()*coeffSizePolyI - other.length()*coeffSizeOtherJ) > max_width / 2) continue;
+ if (abs(polyline.length()*coeffSizePolyI - other.length()*coeffSizeOtherJ) > (coordf_t)(this->max_width / 2)) continue;
//compute angle to see if it's better than previous ones (straighter = better).
@@ -975,7 +978,7 @@ MedialAxis::main_fusion(ThickPolylines& pp)
//std::cout << "try to find main : " << k << " ? " << i << " " << j << " ";
if (k == i || k == j) continue;
ThickPolyline& main = pp[k];
- if (polyline.first_point().coincides_with(main.last_point())) {
+ if (polyline.first_point().coincides_with_epsilon(main.last_point())) {
main.reverse();
if (!main.endpoints.second)
find_main_branch = true;
@@ -983,7 +986,7 @@ MedialAxis::main_fusion(ThickPolylines& pp)
biggest_main_branch_id = k;
biggest_main_branch_length = (coord_t)main.length();
}
- } else if (polyline.first_point().coincides_with(main.first_point())) {
+ } else if (polyline.first_point().coincides_with_epsilon(main.first_point())) {
if (!main.endpoints.second)
find_main_branch = true;
else if (biggest_main_branch_length < main.length()) {
@@ -1111,8 +1114,8 @@ MedialAxis::main_fusion(ThickPolylines& pp)
//std::cout << "width:" << polyline.width[idx_point] << " = " << value_from_current_width << " + " << value_from_dist
// << " (<" << max_width << " && " << (bounds.contour.closest_point(polyline.points[idx_point])->distance_to(polyline.points[idx_point]) * 2.1)<<")\n";
//failsafes
- if (polyline.width[idx_point] > max_width)
- polyline.width[idx_point] = max_width;
+ if (polyline.width[idx_point] > this->max_width)
+ polyline.width[idx_point] = this->max_width;
//failsafe: try to not go out of the radius of the section, take the width of the merging point for that. (and with some offset)
coord_t main_branch_width = pp[biggest_main_branch_id].width.front();
coordf_t main_branch_dist = pp[biggest_main_branch_id].points.front().distance_to(polyline.points[idx_point]);
@@ -1249,7 +1252,7 @@ MedialAxis::remove_too_thin_extrusion(ThickPolylines& pp)
changes = true;
}
//remove points and bits that comes from a "main line"
- if (polyline.points.size() < 2 || (changes && polyline.length() < max_width && polyline.points.size() ==2)) {
+ if (polyline.points.size() < 2 || (changes && polyline.length() < this->max_width && polyline.points.size() ==2)) {
//remove self if too small
pp.erase(pp.begin() + i);
--i;
@@ -1288,14 +1291,14 @@ MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp)
if (other.endpoints.first && other.endpoints.second) continue;
bool me_reverse = false;
bool other_reverse = false;
- if (polyline.last_point().coincides_with(other.last_point())) {
+ if (polyline.last_point().coincides_with_epsilon(other.last_point())) {
other_reverse = true;
- } else if (polyline.first_point().coincides_with(other.last_point())) {
+ } else if (polyline.first_point().coincides_with_epsilon(other.last_point())) {
me_reverse = true;
other_reverse = true;
- } else if (polyline.first_point().coincides_with(other.first_point())) {
+ } else if (polyline.first_point().coincides_with_epsilon(other.first_point())) {
me_reverse = true;
- } else if (!polyline.last_point().coincides_with(other.first_point())) {
+ } else if (!polyline.last_point().coincides_with_epsilon(other.first_point())) {
continue;
}
@@ -1313,12 +1316,12 @@ MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp)
}
}
if (best_candidate != nullptr && best_candidate->points.size() > 1) {
- if (polyline.last_point().coincides_with(best_candidate->last_point())) {
+ if (polyline.last_point().coincides_with_epsilon(best_candidate->last_point())) {
best_candidate->reverse();
- } else if (polyline.first_point().coincides_with(best_candidate->last_point())) {
+ } else if (polyline.first_point().coincides_with_epsilon(best_candidate->last_point())) {
polyline.reverse();
best_candidate->reverse();
- } else if (polyline.first_point().coincides_with(best_candidate->first_point())) {
+ } 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.
@@ -1327,8 +1330,12 @@ MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp)
&& polyline.width.back() > best_candidate->width[1]) {
polyline.width.back() = std::min(polyline.width[polyline.width.size() - 2], best_candidate->width[1]);
}
- polyline.points.insert(polyline.points.end(), best_candidate->points.begin() + 1, best_candidate->points.end());
- polyline.width.insert(polyline.width.end(), best_candidate->width.begin() + 1, best_candidate->width.end());
+ //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());
if (best_idx < i) i--;
@@ -1412,18 +1419,18 @@ MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_siz
// if (endpoint_not_used[idx_endpoint]) {
// int nb_endpoints;
// Point pt = idx_endpoint % 2 == 0 ? polyline.first_point() : polyline.last_point();
- // if (idx_endpoint % 2 == 0 && pt.coincides_with(polyline.last_point())) {
+ // if (idx_endpoint % 2 == 0 && pt.coincides_with_epsilon(polyline.last_point())) {
// nb_endpoints++;
// endpoint_not_used[(idx_endpoint / 2) + 1] = false;
// }
// //good, now find other points
// for (size_t idx_other_pp = (idx_endpoint / 2) + 1; idx_other_pp < pp.size(); idx_other_pp++) {
// ThickPolyline& other = pp[idx_other_pp];
- // if (pt.coincides_with(other.first_point())) {
+ // if (pt.coincides_with_epsilon(other.first_point())) {
// nb_endpoints++;
// endpoint_not_used[idx_other_pp * 2] = false;
// }
- // if (pt.coincides_with(other.last_point())) {
+ // if (pt.coincides_with_epsilon(other.last_point())) {
// nb_endpoints++;
// endpoint_not_used[idx_other_pp * 2 + 1] = false;
// }
@@ -1435,7 +1442,7 @@ MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_siz
// std::cout << "reduce " << reduction << " points!\n";
// if (idx_endpoint % 2 == 0 ) {
// polyline.width.front() *= reduction;
- // if(pt.coincides_with(polyline.last_point()))
+ // if(pt.coincides_with_epsilon(polyline.last_point()))
// polyline.width.back() *= reduction;
// } else {
// polyline.width.back() *= reduction;
@@ -1443,10 +1450,10 @@ MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_siz
// //good, now find other points
// for (size_t idx_other_pp = (idx_endpoint / 2) + 1; idx_other_pp < pp.size(); idx_other_pp++) {
// ThickPolyline& other = pp[idx_other_pp];
- // if (pt.coincides_with(other.first_point())) {
+ // if (pt.coincides_with_epsilon(other.first_point())) {
// other.width.front() *= reduction;
// }
- // if (pt.coincides_with(other.last_point())) {
+ // if (pt.coincides_with_epsilon(other.last_point())) {
// other.width.back() *= reduction;
// }
// }
@@ -1468,17 +1475,15 @@ MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_siz
// know how long will the endpoints be extended since it depends on polygon thickness
// which is variable - extension will be <= max_width/2 on each side)
if ((polyline.endpoints.first || polyline.endpoints.second)) {
- coordf_t max_width = max_width / 2;
+ coordf_t local_max_width = this->max_width / 2;
for (coordf_t w : polyline.width)
- max_width = std::max(max_width, w);
- if(polyline.length() < max_width) {
+ local_max_width = std::max(local_max_width, w);
+ if(polyline.length() < local_max_width) {
if (shortest_size > polyline.length()) {
shortest_size = polyline.length();
shortest_idx = i;
}
-
}
-
}
}
if (shortest_idx < pp.size()) {
@@ -1490,14 +1495,14 @@ MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_siz
}
void
-MedialAxis::check_width(ThickPolylines& pp, coord_t max_width, std::string msg)
+MedialAxis::check_width(ThickPolylines& pp, coord_t local_max_width, std::string msg)
{
//remove empty polyline
int nb = 0;
for (size_t i = 0; i < pp.size(); ++i) {
for (size_t j = 0; j < pp[i].width.size(); ++j) {
- if (pp[i].width[j] > coord_t(max_width * 1.01)) {
- BOOST_LOG_TRIVIAL(error) << "Error " << msg << " width " << unscaled(pp[i].width[j]) << "(" << i << ":" << j << ") > " << unscaled(max_width) << "\n";
+ if (pp[i].width[j] > coord_t(local_max_width * 1.01)) {
+ BOOST_LOG_TRIVIAL(error) << "Error " << msg << " width " << unscaled(pp[i].width[j]) << "(" << i << ":" << j << ") > " << unscaled(local_max_width) << "\n";
nb++;
}
}
@@ -1696,7 +1701,7 @@ MedialAxis::build(ThickPolylines &polylines_out)
{
//static int id = 0;
//id++;
- //std::cout << this->id << "\n";
+ //std::cout << id << "\n";
//{
// std::stringstream stri;
// stri << "medial_axis_0_enter_" << id << ".svg";
@@ -1709,8 +1714,8 @@ MedialAxis::build(ThickPolylines &polylines_out)
// std::stringstream stri;
// stri << "medial_axis_0.5_simplified_" << id << ".svg";
// SVG svg(stri.str());
- // svg.draw(bounds);
- // svg.draw(this->expolygon);
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
// svg.Close();
//}
//safety check
@@ -1777,9 +1782,9 @@ MedialAxis::build(ThickPolylines &polylines_out)
// std::stringstream stri;
// stri << "medial_axis_0.9_voronoi_" << id << ".svg";
// SVG svg(stri.str());
- // //svg.draw(bounds);
- // svg.draw(this->expolygon);
- // svg.draw(pp);
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
// svg.Close();
//}
@@ -1798,15 +1803,33 @@ MedialAxis::build(ThickPolylines &polylines_out)
// pp.erase(pp.begin() + tp_idx);
// --tp_idx;
//}
+ //voronoi problem: can put two consecutive points at the same position. Delete one.
+ for (size_t i = 1; i < tp.points.size()-1; i++) {
+ if (tp.points[i-1].distance_to_square(tp.points[i]) < SCALED_EPSILON) {
+ tp.points.erase(tp.points.begin() + i);
+ tp.width.erase(tp.width.begin() + i);
+ i--;
+ }
+ }
+ //delete the inner one
+ if (tp.points.size()>2 && tp.points[tp.points.size() - 2].distance_to_square(tp.points.back()) < SCALED_EPSILON) {
+ tp.points.erase(tp.points.end() - 2);
+ tp.width.erase(tp.width.end() - 2);
+ }
+ //delete null-length polylines
+ if (tp.length() < SCALED_EPSILON && tp.first_point().coincides_with_epsilon(tp.last_point())) {
+ pp.erase(pp.begin() + tp_idx);
+ --tp_idx;
+ }
}
//std::cout << "polyline_from_voronoi\n";
//{
// std::stringstream stri;
// stri << "medial_axis_1_voronoi_" << id << ".svg";
// SVG svg(stri.str());
- // svg.draw(*bounds);
- // svg.draw(this->expolygon);
- // svg.draw(pp);
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
// svg.Close();
//}
@@ -1819,9 +1842,9 @@ MedialAxis::build(ThickPolylines &polylines_out)
// std::stringstream stri;
// stri << "medial_axis_1_voronoi_" << id << ".svg";
// SVG svg(stri.str());
- // svg.draw(*bounds);
- // svg.draw(this->expolygon);
- // svg.draw(pp);
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
// svg.Close();
//}
@@ -1845,9 +1868,9 @@ MedialAxis::build(ThickPolylines &polylines_out)
// std::stringstream stri;
// stri << "medial_axis_2_curve_" << id << ".svg";
// SVG svg(stri.str());
- // svg.draw(*bounds);
- // svg.draw(this->expolygon);
- // svg.draw(pp);
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
// svg.Close();
//}
@@ -1862,9 +1885,9 @@ MedialAxis::build(ThickPolylines &polylines_out)
// std::stringstream stri;
// stri << "medial_axis_3_fusion_" << id << ".svg";
// SVG svg(stri.str());
- // svg.draw(bounds);
- // svg.draw(this->expolygon);
- // svg.draw(pp);
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
// svg.Close();
//}
@@ -1874,6 +1897,15 @@ MedialAxis::build(ThickPolylines &polylines_out)
// Loop through all returned polylines in order to extend their endpoints to the
// expolygon boundaries (if done here, it may be cut later if not thick enough)
if (stop_at_min_width) {
+ //{
+ // std::stringstream stri;
+ // stri << "medial_axis_3_3_extends_" << id << ".svg";
+ // SVG svg(stri.str());
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
+ // svg.Close();
+ //}
extends_line_both_side(pp);
}
@@ -1885,14 +1917,24 @@ MedialAxis::build(ThickPolylines &polylines_out)
std::cout << "\n";
}*/
//reduce extrusion when it's too thin to be printable
+ //{
+ // std::stringstream stri;
+ // stri << "medial_axis_3_6_remove_thin_" << id << ".svg";
+ // SVG svg(stri.str());
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
+ // svg.Close();
+ //}
+
remove_too_thin_extrusion(pp);
//{
// std::stringstream stri;
// stri << "medial_axis_4_thinok_" << id << ".svg";
// SVG svg(stri.str());
- // svg.draw(bounds);
- // svg.draw(this->expolygon);
- // svg.draw(pp);
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
// svg.Close();
//}
@@ -1901,9 +1943,9 @@ MedialAxis::build(ThickPolylines &polylines_out)
// std::stringstream stri;
// stri << "medial_axis_5.0_thuinner_" << id << ".svg";
// SVG svg(stri.str());
- // svg.draw(*bounds);
- // svg.draw(this->expolygon);
- // svg.draw(pp);
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
// svg.Close();
//}
@@ -1916,9 +1958,9 @@ MedialAxis::build(ThickPolylines &polylines_out)
// std::stringstream stri;
// stri << "medial_axis_5_expand_" << id << ".svg";
// SVG svg(stri.str());
- // svg.draw(*bounds);
- // svg.draw(this->expolygon);
- // svg.draw(pp);
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
// svg.Close();
//}
//TODO: reduce the flow at the intersection ( + ) points on crossing?
@@ -1927,9 +1969,9 @@ MedialAxis::build(ThickPolylines &polylines_out)
// std::stringstream stri;
// stri << "medial_axis_6_concat_" << id << ".svg";
// SVG svg(stri.str());
- // svg.draw(bounds);
- // svg.draw(this->expolygon);
- // svg.draw(pp);
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
// svg.Close();
//}
@@ -1938,9 +1980,9 @@ MedialAxis::build(ThickPolylines &polylines_out)
// std::stringstream stri;
// stri << "medial_axis_8_tooshort_" << id << ".svg";
// SVG svg(stri.str());
- // svg.draw(bounds);
- // svg.draw(this->expolygon);
- // svg.draw(pp);
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
// svg.Close();
//}
@@ -1949,9 +1991,9 @@ MedialAxis::build(ThickPolylines &polylines_out)
// std::stringstream stri;
// stri << "medial_axis_9.1_end_" << id << ".svg";
// SVG svg(stri.str());
- // svg.draw(*bounds);
- // svg.draw(this->expolygon);
- // svg.draw(pp);
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
// svg.Close();
//}
if (nozzle_diameter != min_width) {
@@ -1964,9 +2006,9 @@ MedialAxis::build(ThickPolylines &polylines_out)
// std::stringstream stri;
// stri << "medial_axis_9.9_endnwithtaper_" << id << ".svg";
// SVG svg(stri.str());
- // svg.draw(*bounds);
- // svg.draw(this->expolygon);
- // svg.draw(pp);
+ // svg.draw(*bounds, "grey");
+ // svg.draw(this->expolygon, "green");
+ // svg.draw(pp, "red");
// svg.Close();
//}
@@ -2058,8 +2100,11 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
continue;
}
} else if (i > 0 && resolution_internal > line_len + prev_line_len) {
- ThickLine& prev_line = lines[i - 1];
//merge lines?
+ //if it's a loop, merge only if the distance is high enough
+ if (p.first_point() == p.last_point() && p.length() < (line_len + prev_line_len) * 6)
+ continue;
+ ThickLine& prev_line = lines[i - 1];
coordf_t width = prev_line_len * (prev_line.a_width + prev_line.b_width) / 2;
width += line_len * (line.a_width + line.b_width) / 2;
prev_line.b = line.b;
@@ -2129,13 +2174,14 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
path.height = flow.height;
}
}
+ assert(path.polyline.points.size() > 2 || path.first_point() != path.last_point());
}
if (path.polyline.is_valid())
paths.emplace_back(std::move(path));
// Append paths to collection.
if (!paths.empty()) {
- if (paths.front().first_point().coincides_with(paths.back().last_point())) {
+ if (paths.front().first_point().coincides_with_epsilon(paths.back().last_point())) {
coll.append(ExtrusionLoop(paths));
} else {
if (role == erThinWall){
diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp
index 6ba0c0815..aba01cfd1 100644
--- a/src/libslic3r/PerimeterGenerator.cpp
+++ b/src/libslic3r/PerimeterGenerator.cpp
@@ -462,7 +462,7 @@ void PerimeterGenerator::process()
// In case no perimeters are to be generated, loop_number will equal to -1.
std::vector<PerimeterGeneratorLoops> contours(loop_number + 1); // depth => loops
std::vector<PerimeterGeneratorLoops> holes(loop_number + 1); // depth => loops
- ThickPolylines thin_walls;
+ ThickPolylines thin_walls_thickpolys;
ExPolygons no_last_gapfill;
// we loop one time more than needed in order to find gaps after the last perimeter was applied
for (int i = 0;; ++i) { // outer loop is 0
@@ -492,15 +492,15 @@ void PerimeterGenerator::process()
next_onion = offset_ex(
last,
-(float)(ext_perimeter_width / 2),
- (round_peri ? ClipperLib::JoinType::jtRound : ClipperLib::JoinType::jtMiter),
- (round_peri ? min_round_spacing : 3));
+ ClipperLib::JoinType::jtMiter,
+ 3);
else
next_onion = offset2_ex(
last,
-(float)(ext_perimeter_width / 2 + ext_min_spacing / 2 - 1),
+(float)(ext_min_spacing / 2 - 1),
- (round_peri ? ClipperLib::JoinType::jtRound : ClipperLib::JoinType::jtMiter),
- (round_peri ? min_round_spacing : 3));
+ ClipperLib::JoinType::jtMiter,
+ 3);
// look for thin walls
if (this->config->thin_walls) {
@@ -562,27 +562,27 @@ void PerimeterGenerator::process()
ma.use_bounds(bound)
.use_min_real_width(scale_t(this->ext_perimeter_flow.nozzle_diameter))
.use_tapers(thin_walls_overlap)
- .build(thin_walls);
+ .build(thin_walls_thickpolys);
}
break;
}
}
}
// use perimeters to extrude area that can't be printed by thin walls
- // it's a bit like re-add thin area in to perimeter area.
+ // it's a bit like re-add thin area into perimeter area.
// it can over-extrude a bit, but it's for a better good.
{
if (thin_perimeter)
next_onion = union_ex(next_onion, offset_ex(diff_ex(last, thins, true),
-(float)(ext_perimeter_width / 2),
- (round_peri ? ClipperLib::JoinType::jtRound : ClipperLib::JoinType::jtMiter),
- (round_peri ? min_round_spacing : 3)));
+ ClipperLib::JoinType::jtMiter,
+ 3));
else
next_onion = union_ex(next_onion, offset2_ex(diff_ex(last, thins, true),
-(float)((ext_perimeter_width / 2) + (ext_min_spacing / 4)),
(float)(ext_min_spacing / 4),
- (round_peri ? ClipperLib::JoinType::jtRound : ClipperLib::JoinType::jtMiter),
- (round_peri ? min_round_spacing : 3)));
+ ClipperLib::JoinType::jtMiter,
+ 3));
next_onion = intersection_ex(next_onion, last);
}
@@ -937,20 +937,23 @@ void PerimeterGenerator::process()
}
// append thin walls
- if (!thin_walls.empty()) {
- ExtrusionEntityCollection tw = thin_variable_width
- (thin_walls, erThinWall, this->ext_perimeter_flow, std::max(ext_perimeter_width/4, scale_t(this->print_config->resolution)));
-
- entities.append(tw.entities);
- thin_walls.clear();
+ if (!thin_walls_thickpolys.empty()) {
+ if (this->object_config->thin_walls_merge) {
+ _merge_thin_walls(entities, thin_walls_thickpolys);
+ } else {
+ ExtrusionEntityCollection tw = thin_variable_width
+ (thin_walls_thickpolys, erThinWall, this->ext_perimeter_flow, std::max(ext_perimeter_width / 4, scale_t(this->print_config->resolution)));
+ entities.append(tw.entities);
+ }
+ thin_walls_thickpolys.clear();
}
} else {
if (this->object_config->thin_walls_merge) {
ThickPolylines no_thin_walls;
entities = this->_traverse_loops(contours.front(), no_thin_walls);
- _merge_thin_walls(entities, thin_walls);
+ _merge_thin_walls(entities, thin_walls_thickpolys);
} else {
- entities = this->_traverse_loops(contours.front(), thin_walls);
+ entities = this->_traverse_loops(contours.front(), thin_walls_thickpolys);
}
}
@@ -1697,11 +1700,12 @@ void PerimeterGenerator::_merge_thin_walls(ExtrusionEntityCollection &extrusions
} else {
//first add the return path
ExtrusionEntityCollection tws_second = tws;
- tws_second.reverse();
change_flow.percent_extrusion = 0.1f;
change_flow.use(tws_second);
+ //force reverse
for (ExtrusionPath &path : change_flow.paths)
path.reverse();
+ std::reverse(change_flow.paths.begin(), change_flow.paths.end());
//std::reverse(change_flow.paths.begin(), change_flow.paths.end());
searcher.search_result.loop->paths.insert(searcher.search_result.loop->paths.begin() + 1 + searcher.search_result.idx_path,
change_flow.paths.begin(), change_flow.paths.end());
diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp
index c077d6cd7..26f77b1ca 100644
--- a/src/libslic3r/PlaceholderParser.cpp
+++ b/src/libslic3r/PlaceholderParser.cpp
@@ -1,11 +1,13 @@
#include "PlaceholderParser.hpp"
#include "Exception.hpp"
#include "Flow.hpp"
+
#include <cstring>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <map>
+
#ifdef _MSC_VER
#include <stdlib.h> // provides **_environ
#else
@@ -25,6 +27,7 @@
#endif
#include <boost/algorithm/string.hpp>
+#include <boost/log/trivial.hpp>
#include <boost/nowide/convert.hpp>
// Spirit v2.5 allows you to suppress automatic generation
@@ -649,6 +652,8 @@ namespace client
bool just_boolean_expression = false;
std::string error_message;
+ static std::map<t_config_option_key, std::unique_ptr<ConfigOption>> checked_vars;
+
// Table to translate symbol tag to a human readable error message.
static std::map<std::string, std::string> tag_to_error_message;
@@ -663,6 +668,11 @@ namespace client
opt = config->option(opt_key);
if (opt == nullptr && external_config != nullptr)
opt = external_config->option(opt_key);
+ if (opt == nullptr) {
+ auto it = MyContext::checked_vars.find(opt_key);
+ if (it != MyContext::checked_vars.end())
+ opt = it->second.get();
+ }
return opt;
}
@@ -822,12 +832,52 @@ namespace client
boost::iterator_range<Iterator> &opt_key,
OptWithPos<Iterator> &output)
{
- const ConfigOption *opt = ctx->resolve_symbol(std::string(opt_key.begin(), opt_key.end()));
+ std::string str_key = std::string(opt_key.begin(), opt_key.end());
+ const ConfigOption *opt = ctx->resolve_symbol(str_key);
if (opt == nullptr)
ctx->throw_exception("Not a variable name", opt_key);
output.opt = opt;
output.it_range = opt_key;
}
+
+ // function to check if a var exist & add a dummy var if not
+ template <typename Iterator>
+ static void check_variable(
+ const MyContext* ctx,
+ boost::iterator_range<Iterator>& opt_key,
+ Iterator& end_pos,
+ expr<Iterator>& out,
+ ConfigOption* default_val = nullptr)
+ {
+ t_config_option_key key = std::string(opt_key.begin(), opt_key.end());
+ const ConfigOption* opt = nullptr;
+ if (ctx->config_override != nullptr)
+ opt = ctx->config_override->option(key);
+ if (opt == nullptr)
+ opt = ctx->config->option(key);
+ if (opt == nullptr && ctx->external_config != nullptr)
+ opt = ctx->external_config->option(key);
+ if (opt == nullptr) {
+ std::unique_ptr<ConfigOption> ppt;
+ if(default_val == nullptr)
+ ppt = std::unique_ptr<ConfigOption>(new ConfigOptionBool(false));
+ else
+ ppt = std::unique_ptr<ConfigOption>(default_val);
+ // set flag to say "it's a var that isn't here, please ignore it"
+ ppt->flags |= ConfigOption::FCO_PLACEHOLDER_TEMP;
+ if (MyContext::checked_vars.find(key) != MyContext::checked_vars.end()) {
+ if (default_val != nullptr) {
+ // erase previous value
+ MyContext::checked_vars[key] = std::move(ppt);
+ }
+ } else {
+ // put the var
+ MyContext::checked_vars.emplace(std::move(key), std::move(ppt));
+ }
+ }
+ //return
+ out = expr<Iterator>(opt != nullptr, out.it_range.begin(), end_pos);
+ }
template <typename Iterator>
static void scalar_variable_reference(
@@ -941,8 +991,11 @@ namespace client
Iterator it_end,
expr<Iterator> &output)
{
- if (opt.opt->is_scalar())
+ if (opt.opt->is_scalar()) {
+ if (0 != (opt.opt->flags & ConfigOption::FCO_PLACEHOLDER_TEMP)) // fake var, from checked_vars
+ return scalar_variable_reference(ctx, opt, output);
ctx->throw_exception("Referencing a scalar variable when vector is expected", opt.it_range);
+ }
const ConfigOptionVectorBase *vec = static_cast<const ConfigOptionVectorBase*>(opt.opt);
if (vec->empty())
ctx->throw_exception("Indexing an empty vector variable", opt.it_range);
@@ -1061,6 +1114,7 @@ namespace client
{ "variable_reference", "Expecting a variable reference."},
{ "regular_expression", "Expecting a regular expression."}
};
+ std::map<t_config_option_key, std::unique_ptr<ConfigOption>> MyContext::checked_vars = {};
// For debugging the boost::spirit parsers. Print out the string enclosed in it_range.
template<typename Iterator>
@@ -1321,6 +1375,15 @@ namespace client
{ out = value.unary_not(out.it_range.begin()); }
static void to_int(expr<Iterator> &value, expr<Iterator> &out)
{ out = value.unary_integer(out.it_range.begin()); }
+ //function for default keyword
+ static void default_bool_(bool &value, const MyContext* ctx, boost::iterator_range<Iterator>& opt_key, Iterator& end_pos, expr<Iterator>& out)
+ { MyContext::check_variable<Iterator>(ctx, opt_key, end_pos, out, new ConfigOptionBool(value)); }
+ static void default_int_(int &value, const MyContext* ctx, boost::iterator_range<Iterator>& opt_key, Iterator& end_pos, expr<Iterator>& out)
+ { MyContext::check_variable<Iterator>(ctx, opt_key, end_pos, out, new ConfigOptionInt(value)); }
+ static void default_double_(double &value, const MyContext* ctx, boost::iterator_range<Iterator>& opt_key, Iterator& end_pos, expr<Iterator>& out)
+ { MyContext::check_variable<Iterator>(ctx, opt_key, end_pos, out, new ConfigOptionFloat(value)); }
+ static void default_string_(boost::iterator_range<Iterator>& it_range, const MyContext* ctx, boost::iterator_range<Iterator>& opt_key, Iterator& end_pos, expr<Iterator>& out)
+ { MyContext::check_variable<Iterator>(ctx, opt_key, end_pos, out, new ConfigOptionString(std::string(it_range.begin() + 1, it_range.end() - 1))); }
};
unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> (
scalar_variable_reference(_r1) [ _val = _1 ]
@@ -1335,6 +1398,15 @@ namespace client
| (kw["random"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')')
[ px::bind(&MyContext::random<Iterator>, _r1, _val, _2) ]
| (kw["int"] > '(' > unary_expression(_r1) > ')') [ px::bind(&FactorActions::to_int, _1, _val) ]
+ | (kw["exists"] > '(' > identifier > ')' > iter_pos) [ px::bind(&MyContext::check_variable<Iterator>, _r1, _1, _2, _val, nullptr) ]
+ | (kw["default"] > '(' > identifier > ',' > strict_double > ')' > iter_pos)
+ [px::bind(&FactorActions::default_double_, _2, _r1, _1, _3, _val)]
+ | (kw["default"] > '(' > identifier > ',' > int_ > ')' > iter_pos)
+ [px::bind(&FactorActions::default_int_, _2, _r1, _1, _3, _val)]
+ | (kw["default"] > '(' > identifier > ',' > kw[bool_] > ')' > iter_pos)
+ [ px::bind(&FactorActions::default_bool_, _2, _r1, _1, _3, _val) ]
+ | (kw["default"] > '(' > identifier > ',' > raw[lexeme['"' > *((utf8char - char_('\\') - char_('"')) | ('\\' > char_)) > '"']] > ')' > iter_pos)
+ [px::bind(&FactorActions::default_string_, _2, _r1, _1, _3, _val)]
| (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ]
| (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ]
| (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _1, _2, _val) ]
@@ -1373,7 +1445,9 @@ namespace client
("random")
("not")
("or")
- ("true");
+ ("true")
+ ("exists")
+ ("default");
if (0) {
debug(start);
@@ -1499,11 +1573,11 @@ void PlaceholderParser::append_custom_variables(std::map<std::string, std::vecto
bool is_array = nb_extruders > 0;
if (!is_array) nb_extruders = 1;
- std::regex is_a_name("[a-zA-Z_]+");
+ SLIC3R_REGEX_NAMESPACE::regex is_a_name("[a-zA-Z_]+");
for (const auto& entry : name2var_array) {
if (entry.first.empty())
continue;
- if (!std::regex_match(entry.first, is_a_name))
+ if (!SLIC3R_REGEX_NAMESPACE::regex_match(entry.first, is_a_name))
continue;
const std::vector<std::string>& values = entry.second;
//check if all values are empty
@@ -1552,7 +1626,7 @@ void PlaceholderParser::append_custom_variables(std::map<std::string, std::vecto
//check if all values are numeric
bool is_not_numeric = !is_not_string || !is_not_bool;
std::vector<double> double_values;
- //std::regex("\\s*[+-]?([0-9]+\\.[0-9]*([Ee][+-]?[0-9]+)?|\\.[0-9]+([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)");
+ //SLIC3R_REGEX_NAMESPACE::regex("\\s*[+-]?([0-9]+\\.[0-9]*([Ee][+-]?[0-9]+)?|\\.[0-9]+([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)");
if (!is_not_numeric) {
for (int extruder_id = 0; extruder_id < nb_extruders; ++extruder_id) {
if (!values[extruder_id].empty()) {
diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp
index aaf1e7e48..b6a511b88 100644
--- a/src/libslic3r/Point.hpp
+++ b/src/libslic3r/Point.hpp
@@ -155,7 +155,7 @@ public:
double distance_to(const Line &line) const;
bool coincides_with(const Point &point) const { return this->x() == point.x() && this->y() == point.y(); }
bool coincides_with_epsilon(const Point &point) const {
- return std::abs(this->x() - point.x()) < SCALED_EPSILON && std::abs(this->y() - point.y()) < SCALED_EPSILON;
+ return std::abs(this->x() - point.x()) < SCALED_EPSILON/2 && std::abs(this->y() - point.y()) < SCALED_EPSILON/2;
}
};
diff --git a/src/libslic3r/Polyline.cpp b/src/libslic3r/Polyline.cpp
index 8f294f162..c7cf15c75 100644
--- a/src/libslic3r/Polyline.cpp
+++ b/src/libslic3r/Polyline.cpp
@@ -273,7 +273,7 @@ void concatThickPolylines(ThickPolylines& pp) {
//concat polyline if only 2 polyline at a point
for (size_t i = 0; i < pp.size(); ++i) {
ThickPolyline *polyline = &pp[i];
- if (polyline->first_point().coincides_with(polyline->last_point())) {
+ if (polyline->first_point().coincides_with_epsilon(polyline->last_point())) {
polyline->endpoints.first = false;
polyline->endpoints.second = false;
continue;
@@ -287,25 +287,25 @@ void concatThickPolylines(ThickPolylines& pp) {
for (size_t j = 0; j < pp.size(); ++j) {
if (j == i) continue;
ThickPolyline *other = &pp[j];
- if (polyline->last_point().coincides_with(other->last_point())) {
+ if (polyline->last_point().coincides_with_epsilon(other->last_point())) {
id_candidate_last_point = j;
nbCandidate_last_point++;
}
- if (polyline->last_point().coincides_with(other->first_point())) {
+ if (polyline->last_point().coincides_with_epsilon(other->first_point())) {
id_candidate_last_point = j;
nbCandidate_last_point++;
}
- if (polyline->first_point().coincides_with(other->last_point())) {
+ if (polyline->first_point().coincides_with_epsilon(other->last_point())) {
id_candidate_first_point = j;
nbCandidate_first_point++;
}
- if (polyline->first_point().coincides_with(other->first_point())) {
+ if (polyline->first_point().coincides_with_epsilon(other->first_point())) {
id_candidate_first_point = j;
nbCandidate_first_point++;
}
}
if (id_candidate_last_point == id_candidate_first_point && nbCandidate_first_point == 1 && nbCandidate_last_point == 1) {
- if (polyline->first_point().coincides_with(pp[id_candidate_first_point].first_point())) pp[id_candidate_first_point].reverse();
+ if (polyline->first_point().coincides_with_epsilon(pp[id_candidate_first_point].first_point())) pp[id_candidate_first_point].reverse();
// it's a trap! it's a loop!
polyline->points.insert(polyline->points.end(), pp[id_candidate_first_point].points.begin() + 1, pp[id_candidate_first_point].points.end());
polyline->width.insert(polyline->width.end(), pp[id_candidate_first_point].width.begin() + 1, pp[id_candidate_first_point].width.end());
@@ -316,7 +316,7 @@ void concatThickPolylines(ThickPolylines& pp) {
} else {
if (nbCandidate_first_point == 1) {
- if (polyline->first_point().coincides_with(pp[id_candidate_first_point].first_point())) pp[id_candidate_first_point].reverse();
+ if (polyline->first_point().coincides_with_epsilon(pp[id_candidate_first_point].first_point())) pp[id_candidate_first_point].reverse();
//concat at front
polyline->width[0] = std::max(polyline->width.front(), pp[id_candidate_first_point].width.back());
polyline->points.insert(polyline->points.begin(), pp[id_candidate_first_point].points.begin(), pp[id_candidate_first_point].points.end() - 1);
@@ -336,7 +336,7 @@ void concatThickPolylines(ThickPolylines& pp) {
polyline->endpoints.first = true;
}
if (nbCandidate_last_point == 1) {
- if (polyline->last_point().coincides_with(pp[id_candidate_last_point].last_point())) pp[id_candidate_last_point].reverse();
+ if (polyline->last_point().coincides_with_epsilon(pp[id_candidate_last_point].last_point())) pp[id_candidate_last_point].reverse();
//concat at back
polyline->width[polyline->width.size() - 1] = std::max(polyline->width.back(), pp[id_candidate_last_point].width.front());
polyline->points.insert(polyline->points.end(), pp[id_candidate_last_point].points.begin() + 1, pp[id_candidate_last_point].points.end());
@@ -353,7 +353,7 @@ void concatThickPolylines(ThickPolylines& pp) {
polyline->endpoints.second = true;
}
- if (polyline->last_point().coincides_with(polyline->first_point())) {
+ if (polyline->last_point().coincides_with_epsilon(polyline->first_point())) {
//the concat has created a loop : update endpoints
polyline->endpoints.first = false;
polyline->endpoints.second = false;
diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp
index 30ce2a8c0..eefb4f4bb 100644
--- a/src/libslic3r/Preset.cpp
+++ b/src/libslic3r/Preset.cpp
@@ -710,7 +710,7 @@ const std::vector<std::string>& Preset::filament_options()
"filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel",
"filament_retract_layer_change", "filament_retract_before_wipe",
"filament_seam_gap",
- "filament_wipe", "filament_wipe_extra_perimeter", "filament_wipe_speed",
+ "filament_wipe", "filament_wipe_only_crossing", "filament_wipe_extra_perimeter", "filament_wipe_speed",
// Profile compatibility
"filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits"
//merill adds
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index c5841ceea..2394adbb7 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -196,6 +196,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
"use_volumetric_e",
"variable_layer_height",
"wipe",
+ "wipe_only_crossing",
"wipe_speed",
"wipe_extra_perimeter"
};
@@ -1644,7 +1645,7 @@ std::pair<PrintBase::PrintValidationError, std::string> Print::validate() const
//check not-first layer
if (object->region_volumes[region_id].front().first.second > layer_height) {
if (layer_height + EPSILON < min_layer_height)
- return { PrintBase::PrintValidationError::pveWrongSettings, (boost::format(L("First layer height can't be higher than %s")) % "min layer height").str() };
+ return { PrintBase::PrintValidationError::pveWrongSettings, (boost::format(L("Layer height can't be higher than %s")) % "min layer height").str() };
for (auto tuple : std::vector<std::pair<double, const char*>>{
{nozzle_diameter, "nozzle diameter"},
{max_layer_height, "max layer height"},
diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp
index e4a0b45cc..5ca0198d5 100644
--- a/src/libslic3r/PrintBase.cpp
+++ b/src/libslic3r/PrintBase.cpp
@@ -4,6 +4,8 @@
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
+#include <regex>
+
#include "I18N.hpp"
//! macro used to mark string used at localization,
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index d50cbecf8..de22a6689 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -138,7 +138,7 @@ void PrintConfigDef::init_common_params()
def = this->add("slice_closing_radius", coFloat);
def->label = L("Slice gap closing radius");
def->category = OptionCategory::slicing;
- def->tooltip = L("Cracks smaller than 2x gap closing radius are being filled during the triangle mesh slicing. "
+ def->tooltip = L("Fill cracks smaller than 2x gap closing radius during the triangle mesh slicing. "
"The gap closing operation may reduce the final print resolution, therefore it is advisable to keep the value reasonably low.");
def->sidetext = L("mm");
def->min = 0;
@@ -223,7 +223,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("Allow empty layers");
def->full_label = L("Allow empty layers");
def->category = OptionCategory::slicing;
- def->tooltip = L("Do not prevent the gcode builder to trigger an exception if a full layer is empty and so the print will have to start from thin air afterward.");
+ def->tooltip = L("Prevent the gcode builder from triggering an exception if a full layer is empty, and allow the print to start from thin air afterward.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false));
@@ -240,7 +240,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("Don't avoid crossing on 1st layer");
def->full_label = L("Don't avoid crossing on 1st layer");
def->category = OptionCategory::perimeter;
- def->tooltip = L("Do not use the 'Avoid crossing perimeters' on the first layer.");
+ def->tooltip = L("Disable 'Avoid crossing perimeters' for the first layer.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(true));
@@ -249,7 +249,7 @@ void PrintConfigDef::init_fff_params()
def->category = OptionCategory::perimeter;
def->tooltip = L("The maximum detour length for avoid crossing perimeters. "
"If the detour is longer than this value, avoid crossing perimeters is not applied for this travel path. "
- "Detour length could be specified either as an absolute value or as percentage (for example 50%) of a direct travel path.");
+ "Detour length can be specified either as an absolute value or as percentage (for example 50%) of a direct travel path.");
def->sidetext = L("mm or % (zero to disable)");
def->min = 0;
def->mode = comExpert;
@@ -259,7 +259,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("Other layers");
def->category = OptionCategory::filament;
def->tooltip = L("Bed temperature for layers after the first one. "
- "Set this to zero to disable bed temperature control commands in the output.");
+ "Set zero to disable bed temperature control commands in the output.");
def->sidetext = L("°C");
def->full_label = L("Bed temperature");
def->sidetext = L("°C");
@@ -627,7 +627,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("Allow only one skirt loop");
def->category = OptionCategory::output;
def->tooltip = L("When using 'Complete individual objects', the default behavior is to draw the skirt around each object."
- " if you prefer to have only one skirt for the whole plater, use this option.");
+ " if you prefer to have only one skirt for the whole platter, use this option.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
@@ -756,7 +756,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("duplicate_distance", coFloat);
def->label = L("Default distance between objects");
def->category = OptionCategory::output;
- def->tooltip = L("Default distance used for the auto-arrange feature of the plater.\nSet to 0 to use the last value instead.");
+ def->tooltip = L("Default distance used for the auto-arrange feature of the platter.\nSet to 0 to use the last value instead.");
def->sidetext = L("mm");
def->aliases = { "multiply_distance" };
def->min = 0;
@@ -1215,7 +1215,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("Set this to the clearance radius around your extruder. "
"If the extruder is not centered, choose the largest value for safety. "
"This setting is used to check for collisions and to display the graphical preview "
- "in the plater."
+ "in the platter."
"\nSet zero to disable clearance checking.");
def->sidetext = L("mm");
def->min = 0;
@@ -1329,7 +1329,7 @@ void PrintConfigDef::init_fff_params()
def->precision = 6;
def->can_phony = true;
def->mode = comAdvanced;
- def->set_default_value(new ConfigOptionFloatOrPercent(100, true, false));
+ def->set_default_value(new ConfigOptionFloatOrPercent(0, false, false));
def = this->add("fan_always_on", coBools);
def->label = L("Keep fan always on");
@@ -1399,7 +1399,7 @@ void PrintConfigDef::init_fff_params()
def->category = OptionCategory::filament;
def->tooltip = L("Maximum speed allowed for this filament. Limits the maximum "
"speed of a print to the minimum of the print speed and the filament speed. "
- "Set to zero for no limit.");
+ "Set zero for no limit.");
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comAdvanced;
@@ -1411,7 +1411,7 @@ void PrintConfigDef::init_fff_params()
def->category = OptionCategory::filament;
def->tooltip = L("Maximum volumetric speed allowed for this filament. Limits the maximum volumetric "
"speed of a print to the minimum of print and filament volumetric speed. "
- "Set to zero for no limit.");
+ "Set zero for no limit.");
def->sidetext = L("mm³/s");
def->min = 0;
def->mode = comAdvanced;
@@ -1964,7 +1964,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("First layer");
def->full_label = L("First layer bed temperature");
def->category = OptionCategory::filament;
- def->tooltip = L("Heated build plate temperature for the first layer. Set this to zero to disable "
+ def->tooltip = L("Heated build plate temperature for the first layer. Set zero to disable "
"bed temperature control commands in the output.");
def->sidetext = L("°C");
def->max = 0;
@@ -2064,7 +2064,7 @@ void PrintConfigDef::init_fff_params()
def->full_label = L("First layer nozzle temperature");
def->category = OptionCategory::filament;
def->tooltip = L("Extruder nozzle temperature for first layer. If you want to control temperature manually "
- "during print, set this to zero to disable temperature control commands in the output file.");
+ "during print, set zero to disable temperature control commands in the output file.");
def->sidetext = L("°C");
def->min = 0;
def->max = max_temp;
@@ -2917,7 +2917,10 @@ void PrintConfigDef::init_fff_params()
def = this->add("max_speed_reduction", coPercents);
def->label = L("Max speed reduction");
def->category = OptionCategory::speed;
- def->tooltip = L("Set to 90% if you don't want the speed to be reduced by more than 90%.");
+ def->tooltip = L("This setting control by how much the speed can be reduced to increase the layer time."
+ " It's a maximum reduction, so a lower value makes the minimum speed higher."
+ " Set to 90% if you don't want the speed to go below 10% of the current speed."
+ "\nSet zero to disable");
def->sidetext = L("%");
def->min = 0;
def->max = 100;
@@ -3580,7 +3583,7 @@ void PrintConfigDef::init_fff_params()
def->full_label = L("Enforce lift on first layer");
def->category = OptionCategory::extruders;
def->tooltip = L("Select this option to enforce z-lift on the first layer."
- "\nIf this is enabled and the lift value is 0 or deactivated, then every first move before each object will be lifted by the first layer height.");
+ "\nUseful to still use the lift on the first layer even if the 'Only lift Z below' (retract_lift_above) is higher than 0.");
def->mode = comAdvanced;
def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionBools{ false });
@@ -3726,7 +3729,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("skirt_distance", coFloat);
def->label = L("Distance from object");
def->category = OptionCategory::skirtBrim;
- def->tooltip = L("Distance between skirt and object(s). Set this to zero to attach the skirt "
+ def->tooltip = L("Distance between skirt and object(s). Set zero to attach the skirt "
"to the object(s) and get a brim for better adhesion.");
def->sidetext = L("mm");
def->min = 0;
@@ -3763,14 +3766,14 @@ void PrintConfigDef::init_fff_params()
def->max_literal = { 10, true };
def->precision = 6;
def->mode = comAdvanced;
- def->set_default_value(new ConfigOptionFloatOrPercent(0, false));
+ def->set_default_value(new ConfigOptionFloatOrPercent(130, true));
def = this->add("skirts", coInt);
def->label = L("Loops (minimum)");
def->full_label = L("Skirt Loops");
def->category = OptionCategory::skirtBrim;
def->tooltip = L("Number of loops for the skirt. If the Minimum Extrusion Length option is set, "
- "the number of loops might be greater than the one configured here. Set this to zero "
+ "the number of loops might be greater than the one configured here. Set zero "
"to disable skirt completely.");
def->min = 0;
def->mode = comSimple;
@@ -4135,14 +4138,16 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("perimeters");
def->sidetext_width = 20;
def->category = OptionCategory::perimeter;
- def->tooltip = L("When you have a medium/hight number of top/bottom solid layers, and a low/medium of perimeters,"
- " then it have to put some solid infill inside the part to have enough solid layers."
- "\nBy setting this to something higher than 0, you can remove this 'inside filling'."
- " This number allow to keep some if there is a low number of perimeter over the void."
- "\nIf this setting is equal or higher than the top/bottom solid layer count, it won't evict anything."
- "\nIf this setting is set to 1, it will evict all solid fill are are only over perimeters."
+ def->tooltip = L("In sloping areas, when you have a number of top / bottom solid layers and few perimeters, "
+ " it may be necessary to put some solid infill above/below the perimeters to fulfill the top/bottom layers criteria."
+ "\nBy setting this to something higher than 0, you can control this behaviour, which might be desirable if "
+ "\nundesirable solid infill is being generated on slopes."
+ "\nThe number set here indicates the number of layers between the inside of the part and the air"
+ " at and beyond which solid infill should no longer be added above/below. If this setting is equal or higher than "
+ " the top/bottom solid layer count, it won't do anything. If this setting is set to 1, it will evict "
+ " all solid fill above/below perimeters. "
"\nSet zero to disable."
- "\n!! ensure_vertical_shell_thickness may be erased by this setting !! You may want to deactivate at least one of the two.");
+ "\n!! ensure_vertical_shell_thickness may be erased by this setting !!.");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(2));
@@ -4426,7 +4431,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("Support material will not be generated for overhangs whose slope angle "
"(90° = vertical) is above the given threshold. In other words, this value "
"represent the most horizontal slope (measured from the horizontal plane) "
- "that you can print without support material. Set to zero for automatic detection "
+ "that you can print without support material. Set zero for automatic detection "
"(recommended).");
def->sidetext = L("°");
def->min = 0;
@@ -4446,7 +4451,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("Other layers");
def->full_label = L("Temperature");
def->category = OptionCategory::filament;
- def->tooltip = L("Extruder nozzle temperature for layers after the first one. Set this to zero to disable "
+ def->tooltip = L("Extruder nozzle temperature for layers after the first one. Set zero to disable "
"temperature control commands in the output G-code.");
def->sidetext = L("°C");
def->full_label = L("Nozzle temperature");
@@ -4773,6 +4778,14 @@ void PrintConfigDef::init_fff_params()
def->is_vector_extruder = true;
def->set_default_value(new ConfigOptionBools{ false });
+ def = this->add("wipe_only_crossing", coBools);
+ def->label = L("Wipe only when crossing perimeters");
+ def->category = OptionCategory::extruders;
+ def->tooltip = L("Don't wipe when you don't cross a perimeter.");
+ def->mode = comAdvanced;
+ def->is_vector_extruder = true;
+ def->set_default_value(new ConfigOptionBools{ true });
+
def = this->add("wipe_speed", coFloats);
def->label = L("Wipe speed");
def->category = OptionCategory::extruders;
@@ -5021,7 +5034,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("z_step", coFloat);
def->label = L("Z full step");
def->tooltip = L("Set this to the height moved when your Z motor (or equivalent) turns one step."
- "If your motor needs 200 steps to move your head/plater by 1mm, this field should be 1/200 = 0.005."
+ "If your motor needs 200 steps to move your head/platter by 1mm, this field should be 1/200 = 0.005."
"\nNote that the gcode will write the z values with 6 digits after the dot if z_step is set (it's 3 digits if it's disabled)."
"\nSet zero to disable.");
def->cli = "z-step=f";
@@ -5047,7 +5060,7 @@ void PrintConfigDef::init_fff_params()
"retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", "retract_restart_extra", "retract_before_travel",
"wipe_extra_perimeter", "wipe_speed",
// bools
- "retract_layer_change", "wipe",
+ "retract_layer_change", "wipe", "wipe_only_crossing",
// percents
"retract_before_wipe",
// floatsOrPercents
@@ -5100,6 +5113,7 @@ void PrintConfigDef::init_extruder_option_keys()
"tool_name",
"wipe",
"wipe_extra_perimeter",
+ "wipe_only_crossing",
"wipe_speed",
};
@@ -5117,6 +5131,7 @@ void PrintConfigDef::init_extruder_option_keys()
"seam_gap",
"wipe",
"wipe_extra_perimeter",
+ "wipe_only_crossing",
"wipe_speed",
};
assert(std::is_sorted(m_extruder_retract_keys.begin(), m_extruder_retract_keys.end()));
@@ -5736,7 +5751,7 @@ void PrintConfigDef::init_sla_params()
def = this->add("pad_wall_height", coFloat);
def->label = L("Pad wall height");
- def->tooltip = L("Defines the pad cavity depth. Set to zero to disable the cavity. "
+ def->tooltip = L("Defines the pad cavity depth. Set zero to disable the cavity. "
"Be careful when enabling this feature, as some resins may "
"produce an extreme suction effect inside the cavity, "
"which makes peeling the print off the vat foil difficult.");
@@ -6328,6 +6343,7 @@ std::unordered_set<std::string> prusa_export_to_remove_keys = {
"wipe_advanced_nozzle_melted_volume",
"wipe_advanced",
"wipe_extra_perimeter",
+"wipe_only_crossing",
"wipe_speed",
"wipe_tower_brim",
"xy_inner_size_compensation",
@@ -6754,6 +6770,9 @@ std::set<const DynamicPrintConfig*> DynamicPrintConfig::value_changed(const t_co
if (width_option) {
width_option->set_phony(true);
spacing_option->set_phony(false);
+ if (spacing_value == 0)
+ width_option->value = 0;
+ else
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
width_option->percent = spacing_option->percent;
something_changed = true;
@@ -6764,6 +6783,9 @@ std::set<const DynamicPrintConfig*> DynamicPrintConfig::value_changed(const t_co
if (width_option) {
width_option->set_phony(true);
spacing_option->set_phony(false);
+ if (spacing_value == 0)
+ width_option->value = 0;
+ else
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
width_option->percent = spacing_option->percent;
something_changed = true;
@@ -6775,9 +6797,13 @@ std::set<const DynamicPrintConfig*> DynamicPrintConfig::value_changed(const t_co
if (width_option && perimeter_overlap_option) {
width_option->set_phony(true);
spacing_option->set_phony(false);
+ if(spacing_value == 0)
+ width_option->value = 0;
+ else {
flow.spacing_ratio = std::min(flow.spacing_ratio, float(perimeter_overlap_option->get_abs_value(1)));
flow.width = spacing_option->get_abs_value(max_nozzle_diameter) + layer_height_option->value * (1. - 0.25 * PI) * flow.spacing_ratio;
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
+ }
width_option->percent = spacing_option->percent;
something_changed = true;
}
@@ -6789,9 +6815,13 @@ std::set<const DynamicPrintConfig*> DynamicPrintConfig::value_changed(const t_co
if (width_option && external_perimeter_overlap_option) {
width_option->set_phony(true);
spacing_option->set_phony(false);
+ if (spacing_value == 0)
+ width_option->value = 0;
+ else {
flow.spacing_ratio = std::min(flow.spacing_ratio * 0.5f, float(external_perimeter_overlap_option->get_abs_value(0.25) + perimeter_overlap_option->get_abs_value(0.25)));
flow.width = spacing_option->get_abs_value(max_nozzle_diameter) + layer_height_option->value * (1. - 0.25 * PI) * flow.spacing_ratio;
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
+ }
width_option->percent = spacing_option->percent;
something_changed = true;
}
@@ -6801,6 +6831,9 @@ std::set<const DynamicPrintConfig*> DynamicPrintConfig::value_changed(const t_co
if (width_option) {
width_option->set_phony(true);
spacing_option->set_phony(false);
+ if (spacing_value == 0)
+ width_option->value = 0;
+ else
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
width_option->percent = spacing_option->percent;
something_changed = true;
@@ -6811,6 +6844,9 @@ std::set<const DynamicPrintConfig*> DynamicPrintConfig::value_changed(const t_co
if (width_option) {
width_option->set_phony(true);
spacing_option->set_phony(false);
+ if (spacing_value == 0)
+ width_option->value = 0;
+ else
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
width_option->percent = spacing_option->percent;
something_changed = true;
@@ -6821,6 +6857,9 @@ std::set<const DynamicPrintConfig*> DynamicPrintConfig::value_changed(const t_co
if (width_option) {
width_option->set_phony(true);
spacing_option->set_phony(false);
+ if (spacing_value == 0)
+ width_option->value = 0;
+ else
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
width_option->percent = spacing_option->percent;
something_changed = true;
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index ce949a135..faa733bae 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -1183,6 +1183,7 @@ public:
ConfigOptionFloat wipe_advanced_multiplier;
ConfigOptionFloats wipe_extra_perimeter;
ConfigOptionEnum<WipeAlgo> wipe_advanced_algo;
+ ConfigOptionBools wipe_only_crossing;
ConfigOptionFloats wipe_speed;
ConfigOptionFloat z_step;
ConfigOptionString color_change_gcode;
@@ -1300,6 +1301,7 @@ protected:
OPT_PTR(wipe_advanced_multiplier);
OPT_PTR(wipe_advanced_algo);
OPT_PTR(wipe_extra_perimeter);
+ OPT_PTR(wipe_only_crossing);
OPT_PTR(wipe_speed);
OPT_PTR(z_step);
OPT_PTR(color_change_gcode);
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 8e8a725dc..9aff46af9 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -14,12 +14,12 @@
#include "Fill/FillAdaptive.hpp"
#include "Format/STL.hpp"
+#include <atomic>
#include <utility>
#include <boost/log/trivial.hpp>
#include <float.h>
#include <tbb/parallel_for.h>
-#include <tbb/atomic.h>
#include <Shiny/Shiny.h>
diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h
index 3b4f34264..d1c816bcb 100644
--- a/src/libslic3r/libslic3r.h
+++ b/src/libslic3r/libslic3r.h
@@ -34,32 +34,27 @@ using coord_t = int64_t;
using coordf_t = double;
-//FIXME This epsilon value is used for many non-related purposes:
-// For a threshold of a squared Euclidean distance,
-// for a trheshold in a difference of radians,
-// for a threshold of a cross product of two non-normalized vectors etc.
-static constexpr double EPSILON = 1e-4;
// Scaling factor for a conversion from coord_t to coordf_t: 10e-6
// This scaling generates a following fixed point representation with for a 32bit integer:
// 0..4294mm with 1nm resolution
// int32_t fits an interval of (-2147.48mm, +2147.48mm)
// with int64_t we don't have to worry anymore about the size of the int.
static constexpr double SCALING_FACTOR = 0.000001;
-#ifdef __linux__
-static constexpr double UNSCALING_FACTOR = 1000000;
-#else
-static constexpr double UNSCALING_FACTOR = 1 / SCALING_FACTOR;
-#endif
+static constexpr double UNSCALING_FACTOR = 1000000; // 1 / SCALING_FACTOR;
+
+//FIXME This epsilon value is used for many non-related purposes:
+// For a threshold of a squared Euclidean distance,
+// for a trheshold in a difference of radians,
+// for a threshold of a cross product of two non-normalized vectors etc.
+static constexpr double EPSILON = 1e-4;
+static constexpr coord_t SCALED_EPSILON = 100; // coord_t(EPSILON/ SCALING_FACTOR);
// RESOLUTION, SCALED_RESOLUTION: Used as an error threshold for a Douglas-Peucker polyline simplification algorithm.
//#define RESOLUTION 0.0125
//#define SCALED_RESOLUTION 12500
//#define SCALED_RESOLUTION (RESOLUTION / SCALING_FACTOR)
static constexpr coordf_t RESOLUTION = 0.0125;
-#ifdef __linux__
-static constexpr coord_t SCALED_RESOLUTION = 12500;
-#else
-static constexpr coord_t SCALED_RESOLUTION = coord_t(0.0125 * UNSCALING_FACTOR);
-#endif
+static constexpr coord_t SCALED_RESOLUTION = 12500; // coord_t(0.0125 * UNSCALING_FACTOR);
+
//for creating circles (for brim_ear)
#define POLY_SIDES 24
#define PI 3.141592653589793238
@@ -72,7 +67,6 @@ static constexpr double INSET_OVERLAP_TOLERANCE = 0.4;
//inline coord_t scale_(coordf_t v) { return coord_t(floor(v / SCALING_FACTOR + 0.5f)); }
#define scale_(val) (coord_t)((val) / SCALING_FACTOR)
-#define SCALED_EPSILON scale_(EPSILON)
#define SLIC3R_DEBUG_OUT_PATH_PREFIX "out/"
diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp
index 54ddeac97..b5e29302d 100644
--- a/src/slic3r/GUI/3DBed.cpp
+++ b/src/slic3r/GUI/3DBed.cpp
@@ -16,7 +16,11 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/operations.hpp>
+#include <boost/locale/generator.hpp>
#include <boost/log/trivial.hpp>
+#include <boost/nowide/fstream.hpp>
+#include <boost/property_tree/ini_parser.hpp>
+#include <boost/property_tree/ptree.hpp>
static const float GROUND_Z = -0.02f;
diff --git a/src/slic3r/GUI/CalibrationAbstractDialog.cpp b/src/slic3r/GUI/CalibrationAbstractDialog.cpp
index 6fa3c1a6b..385d5e0cf 100644
--- a/src/slic3r/GUI/CalibrationAbstractDialog.cpp
+++ b/src/slic3r/GUI/CalibrationAbstractDialog.cpp
@@ -5,10 +5,14 @@
#include "GUI.hpp"
#include "GUI_ObjectList.hpp"
#include "Tab.hpp"
+
#include <wx/scrolwin.h>
#include <wx/display.h>
#include <wx/file.h>
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
+
#if ENABLE_SCROLLABLE
static wxSize get_screen_size(wxWindow* window)
{
diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp
index dd90cea9f..2dabd7dc4 100644
--- a/src/slic3r/GUI/ConfigManipulation.cpp
+++ b/src/slic3r/GUI/ConfigManipulation.cpp
@@ -319,7 +319,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
{
bool have_perimeters = config->opt_int("perimeters") > 0;
for (auto el : { "ensure_vertical_shell_thickness", "external_perimeter_speed", "extra_perimeters", "extra_perimeters_overhangs", "extra_perimeters_odd_layers",
- "external_perimeters_first", "external_perimeters_vase", "external_perimeter_extrusion_width",
+ "external_perimeters_first", "external_perimeters_vase", "external_perimeter_extrusion_width", "external_perimeter_extrusion_spacing",
"no_perimeter_unsupported_algo", "only_one_perimeter_top", "overhangs", "overhangs_reverse",
"perimeter_loop", "perimeter_loop_seam","perimeter_speed",
"seam_position", "small_perimeter_speed", "small_perimeter_min_length", " small_perimeter_max_length", "spiral_vase",
@@ -375,12 +375,12 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
bool has_solid_infill = has_top_solid_infill || has_bottom_solid_infill || (have_infill && (config->opt_int("solid_infill_every_layers") > 0 || config->opt_float("solid_infill_below_area") > 0));
// solid_infill_extruder uses the same logic as in Print::extruders()
for (auto el : { "top_fill_pattern", "bottom_fill_pattern", "solid_fill_pattern", "enforce_full_fill_volume", "external_infill_margin", "bridged_infill_margin",
- "solid_infill_extruder", "solid_infill_extrusion_width", "solid_infill_speed" })
+ "solid_infill_extruder", "solid_infill_extrusion_width", "solid_infill_extrusion_spacing", "solid_infill_speed" })
toggle_field(el, has_solid_infill);
toggle_field("infill_first", (has_solid_infill || have_infill));
- for (auto el : { "fill_angle", "fill_angle_increment", "bridge_angle", "infill_extrusion_width",
+ for (auto el : { "fill_angle", "fill_angle_increment", "bridge_angle", "infill_extrusion_width", "infill_extrusion_spacing",
"infill_speed" })
toggle_field(el, have_infill || has_solid_infill);
@@ -396,7 +396,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
for (auto el : {"fill_smooth_width, fill_smooth_distribution" })
toggle_field(el, has_ironing_pattern);
- for (auto el : { "ironing", "top_fill_pattern", "infill_connection_top", "top_infill_extrusion_width", "top_solid_infill_speed" })
+ for (auto el : { "ironing", "top_fill_pattern", "infill_connection_top", "top_infill_extrusion_width", "top_infill_extrusion_spacing", "top_solid_infill_speed" })
toggle_field(el, has_top_solid_infill);
for (auto el : { "bottom_fill_pattern", "infill_connection_bottom" })
@@ -445,13 +445,27 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
toggle_field(el, have_support_material && have_support_interface);
toggle_field("support_material_synchronize_layers", have_support_soluble);
- toggle_field("perimeter_extrusion_width", have_perimeters || have_skirt || have_brim);
+ toggle_field("perimeter_extrusion_width", have_perimeters || have_brim);
+ toggle_field("perimeter_extrusion_spacing", have_perimeters || have_brim);
+ toggle_field("skirt_extrusion_width", have_skirt);
toggle_field("support_material_extruder", have_support_material || have_skirt);
toggle_field("support_material_speed", have_support_material || have_brim || have_skirt);
+ //for default_extrusion_width/spacing, you need to ahve at least an extrusion_width with 0
+ bool have_default_width = config->option("first_layer_extrusion_width")->getFloat() == 0 ||
+ (config->option("perimeter_extrusion_width")->getFloat() == 0 && (have_perimeters || have_brim)) ||
+ (config->option("external_perimeter_extrusion_width")->getFloat() == 0 && have_perimeters) ||
+ (config->option("infill_extrusion_width")->getFloat() == 0 && (have_infill || has_solid_infill)) ||
+ (config->option("solid_infill_extrusion_width")->getFloat() == 0 && has_solid_infill) ||
+ (config->option("top_infill_extrusion_width")->getFloat() == 0 && has_top_solid_infill) ||
+ (config->option("support_material_extrusion_width")->getFloat() == 0 && have_support_material) ||
+ (config->option("skirt_extrusion_width")->getFloat() == 0 && have_skirt);
+ toggle_field("extrusion_width", have_default_width);
+ toggle_field("extrusion_spacing", have_default_width);
+
bool has_PP_ironing = has_top_solid_infill && config->opt_bool("ironing");
for (auto el : { "ironing_type", "ironing_flowrate", "ironing_spacing", "ironing_angle" })
- toggle_field(el, has_PP_ironing);
+ toggle_field(el, has_PP_ironing);
bool has_ironing = has_PP_ironing || has_ironing_pattern;
for (auto el : { "ironing_speed" })
@@ -460,7 +474,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
bool have_sequential_printing = config->opt_bool("complete_objects");
for (auto el : { /*"extruder_clearance_radius", "extruder_clearance_height",*/ "complete_objects_one_skirt",
- "complete_objects_sort", "complete_objects_one_brim"})
+ "complete_objects_sort", "complete_objects_one_brim"})
toggle_field(el, have_sequential_printing);
bool have_ooze_prevention = config->opt_bool("ooze_prevention");
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index a6a72e3c9..4bc3360e5 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -1908,7 +1908,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
title += " - " + _L("Language selection");
wxMessageDialog dialog(nullptr,
_L("Switching the language will trigger application restart.\n"
- "You will lose content of the plater.") + "\n\n" +
+ "You will lose content of the platter.") + "\n\n" +
_L("Do you want to proceed?"),
title,
wxICON_QUESTION | wxOK | wxCANCEL);
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index bcc1eef24..3d2280523 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -15,6 +15,8 @@
#include "Selection.hpp"
#include <boost/algorithm/string.hpp>
+#include <boost/log/trivial.hpp>
+
#include "slic3r/Utils/FixModelByWin10.hpp"
#ifdef __WXMSW__
diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp
index 42a92b8f1..6603bb782 100644
--- a/src/slic3r/GUI/KBShortcutsDialog.cpp
+++ b/src/slic3r/GUI/KBShortcutsDialog.cpp
@@ -66,13 +66,13 @@ void KBShortcutsDialog::fill_shortcuts()
if (wxGetApp().is_editor()) {
Shortcuts commands_shortcuts = {
// File
- { ctrl + "N", L("New project, clear plater") },
- { ctrl + "O", L("Open project STL/OBJ/AMF/3MF with config, clear plater") },
+ { ctrl + "N", L("New project, clear platter") },
+ { ctrl + "O", L("Open project STL/OBJ/AMF/3MF with config, clear platter") },
{ ctrl + "S", L("Save project (3mf)") },
{ ctrl + alt + "S", L("Save project as (3mf)") },
{ ctrl + "R", L("(Re)slice") },
// File>Import
- { ctrl + "I", L("Import STL/OBJ/AMF/3MF without config, keep plater") },
+ { ctrl + "I", L("Import STL/OBJ/AMF/3MF without config, keep platter") },
{ ctrl + "L", L("Import Config from ini/amf/3mf/gcode") },
{ ctrl + alt + "L", L("Load Config from ini/amf/3mf/gcode and merge") },
// File>Export
@@ -91,9 +91,9 @@ void KBShortcutsDialog::fill_shortcuts()
{ ctrl + "C", L("Copy to clipboard") },
{ ctrl + "V", L("Paste from clipboard") },
#ifdef __APPLE__
- { ctrl + "Shift+" + "R", L("Reload plater from disk") },
+ { ctrl + "Shift+" + "R", L("Reload platter from disk") },
#else
- { "F5", L("Reload plater from disk") },
+ { "F5", L("Reload platter from disk") },
#endif // __APPLE__
{ ctrl + "F", L("Search") },
// Window
@@ -169,7 +169,7 @@ void KBShortcutsDialog::fill_shortcuts()
#endif // ENABLE_RENDER_PICKING_PASS
};
- m_full_shortcuts.push_back({ { _L("Plater"), "" }, plater_shortcuts });
+ m_full_shortcuts.push_back({ { _L("Platter"), "" }, plater_shortcuts });
Shortcuts gizmos_shortcuts = {
{ ctrl, L("All gizmos: Rotate - left mouse button; Pan - right mouse button") },
@@ -187,9 +187,9 @@ void KBShortcutsDialog::fill_shortcuts()
Shortcuts commands_shortcuts = {
{ ctrl + "O", L("Open a G-code file") },
#ifdef __APPLE__
- { ctrl + "Shift+" + "R", L("Reload the plater from disk") },
+ { ctrl + "Shift+" + "R", L("Reload the platter from disk") },
#else
- { "F5", L("Reload plater from disk") },
+ { "F5", L("Reload platter from disk") },
#endif // __APPLE__
};
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 1804cb13d..c3721a4b9 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -428,7 +428,7 @@ void MainFrame::update_layout()
{
//layout
m_plater->Reparent(m_tabpanel);
- m_tabpanel->InsertPage(0, m_plater, _L("Plater"));
+ m_tabpanel->InsertPage(0, m_plater, _L("Platter"));
m_main_sizer->Add(m_tabpanel, 1, wxEXPAND);
update_icon();
// show
@@ -467,7 +467,7 @@ void MainFrame::update_layout()
m_tabpanel->Hide();
m_main_sizer->Add(m_tabpanel, 1, wxEXPAND);
m_plater_page = new wxPanel(m_tabpanel);
- m_tabpanel->InsertPage(0, m_plater_page, _L("Plater")); // empty panel just for Plater tab */
+ m_tabpanel->InsertPage(0, m_plater_page, _L("Platter")); // empty panel just for Plater tab */
update_icon();
m_plater->Show();
break;
diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp
index 6d54b2d71..91be4c917 100644
--- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp
+++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp
@@ -5,6 +5,7 @@
#include <vector>
#include <string>
#include <boost/algorithm/string.hpp>
+#include <boost/log/trivial.hpp>
#include <wx/sizer.h>
#include <wx/stattext.h>
diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp
index cc44d626a..25941120a 100644
--- a/src/slic3r/GUI/Preferences.cpp
+++ b/src/slic3r/GUI/Preferences.cpp
@@ -4,8 +4,12 @@
#include "Plater.hpp"
#include "I18N.hpp"
#include "libslic3r/AppConfig.hpp"
+
#include <wx/notebook.h>
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
+
namespace Slic3r {
namespace GUI {
@@ -134,7 +138,7 @@ void PreferencesDialog::build()
def_combobox_auto_switch_preview.gui_flags = "show_value";
def_combobox_auto_switch_preview.enum_values.push_back(_u8L("Don't switch"));
def_combobox_auto_switch_preview.enum_values.push_back(_u8L("Switch when possible"));
- def_combobox_auto_switch_preview.enum_values.push_back(_u8L("Only if on plater"));
+ def_combobox_auto_switch_preview.enum_values.push_back(_u8L("Only if on platter"));
def_combobox_auto_switch_preview.enum_values.push_back(_u8L("Only when GCode is ready"));
if (app_config->get("auto_switch_preview") == "0")
def_combobox_auto_switch_preview.set_default_value(new ConfigOptionStrings{ def_combobox_auto_switch_preview.enum_values[0] });
@@ -807,7 +811,7 @@ void PreferencesDialog::create_settings_mode_widget(wxNotebook* tabs)
#ifndef WIN32
+ " " + unstable_warning
#endif
- + "\n* " + _L("Old layout: all windows are in the application, settings are on the top tab bar and the plater choice in on the bottom of the plater view.")
+ + "\n* " + _L("Old layout: all windows are in the application, settings are on the top tab bar and the platter choice in on the bottom of the platter view.")
+ "\n* " + _L("Settings button: all windows are in the application, no tabs: you have to clic on settings gears to switch to settings tabs.")
+ "\n* " + _L("Settings window: settings are displayed in their own window. You have to clic on settings gears to show the settings window.")
);
diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp
index 6c75eb153..b35efd92c 100644
--- a/src/slic3r/GUI/Search.cpp
+++ b/src/slic3r/GUI/Search.cpp
@@ -1,7 +1,9 @@
#include "Search.hpp"
#include <cstddef>
+#include <regex>
#include <string>
+
#include <boost/algorithm/string.hpp>
#include <boost/optional.hpp>
#include <boost/nowide/convert.hpp>
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 7fe2c5c7b..38ec11954 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -22,6 +22,7 @@
#include <wx/bmpcbox.h>
#include <wx/bmpbuttn.h>
+#include <wx/collpane.h>
#include <wx/treectrl.h>
#include <wx/imaglist.h>
#include <wx/settings.h>
@@ -29,10 +30,12 @@
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/predicate.hpp>
-
-#include <boost/algorithm/string/replace.hpp>#include <boost/algorithm/string/trim.hpp>
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/algorithm/string/trim.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/path.hpp>
+#include <boost/lexical_cast.hpp>
+
#include "wxExtensions.hpp"
#include "PresetComboBoxes.hpp"
#include <wx/wupdlock.h>
@@ -2345,6 +2348,7 @@ void TabFilament::add_filament_overrides_page()
"filament_retract_layer_change",
"filament_seam_gap",
"filament_wipe",
+ "filament_wipe_extra_perimeter",
"filament_wipe_speed",
"filament_wipe_extra_perimeter"
})
@@ -2374,6 +2378,7 @@ void TabFilament::update_filament_overrides_page()
"filament_retract_layer_change",
"filament_seam_gap",
"filament_wipe",
+ "filament_wipe_extra_perimeter",
"filament_wipe_speed",
"filament_wipe_extra_perimeter"
};
@@ -2920,11 +2925,21 @@ void TabPrinter::clear_pages()
void TabPrinter::toggle_options()
{
- if (!m_active_page || m_presets->get_edited_preset().printer_technology() == ptSLA)
+ if (!m_active_page || m_presets->get_edited_preset().printer_technology() != ptFFF)
return;
Field* field;
+ const DynamicPrintConfig& print_config = m_preset_bundle->fff_prints.get_edited_preset().config;
+ const DynamicPrintConfig& filament_config = m_preset_bundle->filaments.get_edited_preset().config;
+ const DynamicPrintConfig& printer_config = m_preset_bundle->printers.get_edited_preset().config;
+
+ // Print config values
+ DynamicPrintConfig full_print_config;
+ full_print_config.apply(print_config);
+ full_print_config.apply(filament_config);
+ full_print_config.apply(printer_config);
+
bool have_multiple_extruders = m_extruders_count > 1;
field = get_field("toolchange_gcode");
if (field) field->toggle(have_multiple_extruders);
@@ -3001,7 +3016,7 @@ void TabPrinter::toggle_options()
// some options only apply when not using firmware retraction
vec.resize(0);
- vec = { "retract_speed", "deretract_speed", "retract_before_wipe", "retract_restart_extra", "wipe", "wipe_speed" };
+ vec = { "retract_speed", "deretract_speed", "retract_before_wipe", "retract_restart_extra", "wipe", "wipe_speed" , "wipe_only_crossing"};
for (auto el : vec) {
field = get_field(el, i);
if (field)
@@ -3009,13 +3024,17 @@ void TabPrinter::toggle_options()
}
bool wipe = m_config->opt_bool("wipe", i) && have_retract_length;
- vec = { "retract_before_wipe", "wipe_speed" };
+ vec = { "retract_before_wipe", "wipe_only_crossing", "wipe_speed" };
for (auto el : vec) {
field = get_field(el, i);
if (field)
field->toggle(wipe);
}
+ // wipe_only_crossing can only work if avoid_crossing_perimeters
+ if (!full_print_config.opt_bool("avoid_crossing_perimeters"))
+ get_field("wipe_only_crossing", i)->toggle(false);
+
if (use_firmware_retraction && wipe) {
wxMessageDialog dialog(parent(),
_(L("The Wipe option is not available when using the Firmware Retraction mode.\n"
diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp
index bf952bb8c..37821d7c8 100644
--- a/src/slic3r/Utils/PresetUpdater.cpp
+++ b/src/slic3r/Utils/PresetUpdater.cpp
@@ -6,12 +6,15 @@
#include <ostream>
#include <utility>
#include <stdexcept>
-#include <boost/format.hpp>
+
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
+#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/log/trivial.hpp>
+#include <boost/property_tree/json_parser.hpp>
+#include <boost/property_tree/ptree.hpp>
#include <wx/app.h>
#include <wx/msgdlg.h>