diff options
author | supermerill <merill@free.fr> | 2022-08-05 03:27:23 +0300 |
---|---|---|
committer | supermerill <merill@free.fr> | 2022-08-05 03:27:23 +0300 |
commit | 3b62b1979ffce95632597e7af7c1c554948aaf8f (patch) | |
tree | 8c16db7b723af3427c6155986f0be052677b7666 | |
parent | 572e3f970e78febddb73808eaa6c4a013ae5eed4 (diff) | |
parent | 373dd2658459a8be2118a2eb97994fa66c9347fc (diff) |
Fix arachne issues and some others
-rw-r--r-- | src/libslic3r/Arachne/utils/ExtrusionLine.cpp | 12 | ||||
-rw-r--r-- | src/libslic3r/Arachne/utils/ExtrusionLine.hpp | 1 | ||||
-rw-r--r-- | src/libslic3r/ClipperUtils.cpp | 169 | ||||
-rw-r--r-- | src/libslic3r/ClipperUtils.hpp | 2 | ||||
-rw-r--r-- | src/libslic3r/Flow.cpp | 12 | ||||
-rw-r--r-- | src/libslic3r/GCode.cpp | 2 | ||||
-rw-r--r-- | src/libslic3r/GCode/SeamPlacer.cpp | 13 | ||||
-rw-r--r-- | src/libslic3r/PerimeterGenerator.cpp | 149 | ||||
-rw-r--r-- | src/libslic3r/ShortestPath.cpp | 7 | ||||
-rw-r--r-- | src/slic3r/GUI/3DBed.cpp | 2 | ||||
-rw-r--r-- | src/slic3r/GUI/FreeCADDialog.cpp | 2 |
11 files changed, 257 insertions, 114 deletions
diff --git a/src/libslic3r/Arachne/utils/ExtrusionLine.cpp b/src/libslic3r/Arachne/utils/ExtrusionLine.cpp index 69f235853..426f9064d 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionLine.cpp +++ b/src/libslic3r/Arachne/utils/ExtrusionLine.cpp @@ -28,6 +28,18 @@ int64_t ExtrusionLine::getLength() const return len; } +bool ExtrusionLine::isZeroLength() const +{ + if (junctions.empty()) + return true; + ExtrusionJunction prev = junctions.front(); + for (const ExtrusionJunction& next : junctions) { + if ((next.p - prev.p).cast<int64_t>().squaredNorm() > SCALED_EPSILON) + return false; + } + return true; +} + coord_t ExtrusionLine::getMinimalWidth() const { return std::min_element(junctions.cbegin(), junctions.cend(), diff --git a/src/libslic3r/Arachne/utils/ExtrusionLine.hpp b/src/libslic3r/Arachne/utils/ExtrusionLine.hpp index 776a175b6..d7c4d6b14 100644 --- a/src/libslic3r/Arachne/utils/ExtrusionLine.hpp +++ b/src/libslic3r/Arachne/utils/ExtrusionLine.hpp @@ -119,6 +119,7 @@ struct ExtrusionLine * Sum the total length of this path. */ int64_t getLength() const; + bool isZeroLength() const; int64_t polylineLength() const { return getLength(); } /*! diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 6b0c95c1f..1faa5f6c3 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -755,7 +755,7 @@ Polylines _clipper_pl_open(ClipperLib::ClipType clipType, PathsProvider1 &&subje //perform y safing : if a line is on the same Y, clipper may not pick the good point. //note: if not enough, next time, add some of the X coordinate (modulo it so it's contained in the scaling part) - for (ClipperLib::Paths* input : { &input_subject, &input_clip }) + for (ClipperLib::Paths* input : { &input_subject, &input_clip }) { for (ClipperLib::Path& path : *input) { coord_t lasty = 0; for (ClipperLib::IntPoint& pt : path) { @@ -765,6 +765,7 @@ Polylines _clipper_pl_open(ClipperLib::ClipType clipType, PathsProvider1 &&subje lasty = pt.y(); } } + } // init Clipper ClipperLib::Clipper clipper; @@ -809,6 +810,172 @@ Polylines _clipper_pl_open(ClipperLib::ClipType clipType, PathsProvider1 &&subje return PolyTreeToPolylines(std::move(retval)); } +void scaleClipperPolygons(ClipperLib_Z::Paths& polygons) +{ + CLIPPERUTILS_PROFILE_FUNC(); + for (ClipperLib_Z::Paths::iterator it = polygons.begin(); it != polygons.end(); ++it) + for (ClipperLib_Z::Path::iterator pit = (*it).begin(); pit != (*it).end(); ++pit) { + pit->x() <<= CLIPPER_OFFSET_POWER_OF_2; + pit->y() <<= CLIPPER_OFFSET_POWER_OF_2; + pit->z() <<= CLIPPER_OFFSET_POWER_OF_2; + } +} +ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Paths& subjects, const ClipperLib_Z::Paths& clip, ClipperLib_Z::ClipType clipType) +{ + ClipperLib_Z::Clipper clipper; + clipper.ZFillFunction([](const ClipperLib_Z::IntPoint& e1bot, const ClipperLib_Z::IntPoint& e1top, const ClipperLib_Z::IntPoint& e2bot, + const ClipperLib_Z::IntPoint& e2top, ClipperLib_Z::IntPoint& pt) { + ClipperLib_Z::IntPoint start = e1bot; + ClipperLib_Z::IntPoint end = e1top; + + if (start.z() <= 0 && end.z() <= 0) { + start = e2bot; + end = e2top; + } + + assert(start.z() > 0 && end.z() > 0); + + // Interpolate extrusion line width. + double length_sqr = (end - start).cast<double>().squaredNorm(); + double dist_sqr = (pt - start).cast<double>().squaredNorm(); + double t = std::sqrt(dist_sqr / length_sqr); + + pt.z() = start.z() + coord_t((end.z() - start.z()) * t); + }); + + //TODO: //scale to have some more precision to do some Y-bugfix like in _clipper_pl_open + + // read input + ClipperLib_Z::Paths input_subject; + for (const ClipperLib_Z::Path& pg : subjects) + input_subject.push_back(pg); + ClipperLib_Z::Paths input_clip; + for (const ClipperLib_Z::Path& pg : clip) + input_clip.push_back(pg); + + //scale to have some more precision to do some Y-bugfix + scaleClipperPolygons(input_subject); + scaleClipperPolygons(input_clip); + + //perform y safing : if a line is on the same Y, clipper may not pick the good point. + //note: if not enough, next time, add some of the X coordinate (modulo it so it's contained in the scaling part) + for (ClipperLib_Z::Paths* input : { &input_subject, &input_clip }) { + for (ClipperLib_Z::Path& path : *input) { + coord_t lasty = 0; + for (ClipperLib_Z::IntPoint& pt : path) { + if (lasty == pt.y()) { + pt.y() += 2048;// well below CLIPPER_OFFSET_POWER_OF_2, need also to be high enough that it won't be reduce to 0 if cut near an end + } + lasty = pt.y(); + } + } + } + + clipper.AddPaths(input_subject, ClipperLib_Z::ptSubject, false); + clipper.AddPaths(input_clip, ClipperLib_Z::ptClip, true); + + ClipperLib_Z::PolyTree clipped_polytree; + ClipperLib_Z::Paths clipped_paths; + clipper.Execute(clipType, clipped_polytree, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero); + + + //restore good y + std::vector<ClipperLib_Z::PolyNode*> to_check; + to_check.push_back(&clipped_polytree); + while (!to_check.empty()) { + ClipperLib_Z::PolyNode* node = to_check.back(); + to_check.pop_back(); + for (ClipperLib_Z::IntPoint& pit : node->Contour) { + pit.x() += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA; + pit.y() += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA; + pit.z() += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA; + pit.x() >>= CLIPPER_OFFSET_POWER_OF_2; + pit.y() >>= CLIPPER_OFFSET_POWER_OF_2; + pit.z() >>= CLIPPER_OFFSET_POWER_OF_2; + } + //note: moving in Y may create 0-length segment, so it needs an extra post-processing step to remove these duplicate points. + for (size_t idx = 1; idx < node->Contour.size(); ++idx) { + ClipperLib_Z::IntPoint& pit = node->Contour[idx]; + ClipperLib_Z::IntPoint& previous = node->Contour[idx - 1]; + // unscaling remove too small differences. The equality is enough. + if (pit.x() == previous.x() && pit.y() == previous.y()) { + node->Contour.erase(node->Contour.begin() + idx); + --idx; + } + } + //be sure you don't save 1-point paths + if (node->Contour.size() == 1) + node->Contour.clear(); + to_check.insert(to_check.end(), node->Childs.begin(), node->Childs.end()); + } + + ClipperLib_Z::PolyTreeToPaths(clipped_polytree, clipped_paths); + + //can contain 0-length segments + for (ClipperLib_Z::Path& path : clipped_paths) { + for (size_t i = 1; i < path.size(); i++) { + if ((path[i - 1] - path[i]).squaredNorm() < SCALED_EPSILON) { + path.erase(path.begin() + i); + i--; + } + } + } + + // Clipped path could contain vertices from the clip with a Z coordinate equal to zero. + // For those vertices, we must assign value based on the subject. + // This happens only in sporadic cases. + for (ClipperLib_Z::Path& path : clipped_paths) + for (ClipperLib_Z::IntPoint& c_pt : path) + if (c_pt.z() == 0) { + const Point pt(c_pt.x(), c_pt.y()); + Point projected_pt_min; + const ClipperLib_Z::IntPoint* it_a = nullptr; + const ClipperLib_Z::IntPoint* it_b = nullptr; + auto dist_sqr_min = std::numeric_limits<double>::max(); + Point prev(0, 0); + for (const ClipperLib_Z::Path& subject : subjects) { + // Now we must find the corresponding line on with this point is located and compute line width (Z coordinate). + if (subject.size() <= 2) + continue; + + for (auto it = std::next(subject.begin()); it != subject.end(); ++it) { + Point curr(it->x(), it->y()); + if (it_a == nullptr) { + assert(std::prev(it) == subject.begin()); + prev = Point(subject.front().x(), subject.front().y()); + } + Point projected_pt = pt.projection_onto(Line(prev, curr)); + if (double dist_sqr = (projected_pt - pt).cast<double>().squaredNorm(); dist_sqr < dist_sqr_min) { + dist_sqr_min = dist_sqr; + projected_pt_min = projected_pt; + it_a = &*std::prev(it); + it_b = &*it; + } + prev = curr; + } + + assert(dist_sqr_min <= SCALED_EPSILON); + assert(*it_a != subject.back()); + } + + const Point pt_a(it_a->x(), it_a->y()); + const Point pt_b(it_b->x(), it_b->y()); + const double line_len = (pt_b - pt_a).cast<double>().norm(); + const double dist = (projected_pt_min - pt_a).cast<double>().norm(); + c_pt.z() = coord_t(double(it_a->z()) + (dist / line_len) * double(it_b->z() - it_a->z())); + } + assert([&clipped_paths = std::as_const(clipped_paths)]() -> bool { + for (const ClipperLib_Z::Path& path : clipped_paths) + for (const ClipperLib_Z::IntPoint& pt : path) + if (pt.z() <= 0) + return false; + return true; + }()); + + return clipped_paths; +} + + // If the split_at_first_point() call above happens to split the polygon inside the clipping area // we would get two consecutive polylines instead of a single one, so we go through them in order // to recombine continuous polylines. diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp index 069ddd1ba..35109821c 100644 --- a/src/libslic3r/ClipperUtils.hpp +++ b/src/libslic3r/ClipperUtils.hpp @@ -3,6 +3,7 @@ #include "libslic3r.h" #include "clipper.hpp" +#include "clipper/clipper_z.hpp" #include "ExPolygon.hpp" #include "Polygon.hpp" #include "Surface.hpp" @@ -405,6 +406,7 @@ Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPoly Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip); Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip); Slic3r::Polylines diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip); +ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Paths& subjects, const ClipperLib_Z::Paths& clip, ClipperLib_Z::ClipType clipType); inline Slic3r::Lines diff_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip) { diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp index 888f678f8..9bfa2d519 100644 --- a/src/libslic3r/Flow.cpp +++ b/src/libslic3r/Flow.cpp @@ -430,6 +430,9 @@ Flow support_material_flow(const PrintObject* object, float layer_height) layer_height = object->config().support_material_layer_height.get_abs_value(nzd); if (layer_height == 0) { layer_height = object->print()->config().max_layer_height.get_abs_value(extruder_id, nzd); + if (layer_height == 0) { + layer_height = nzd * 0.75; + } } } layer_height = std::min(layer_height, max_height); @@ -489,6 +492,9 @@ Flow support_material_interface_flow(const PrintObject* object, float layer_heig layer_height = object->config().support_material_interface_layer_height.get_abs_value(nzd); if (layer_height == 0) { layer_height = object->print()->config().max_layer_height.get_abs_value(extruder_id, nzd); + if (layer_height == 0) { + layer_height = nzd * 0.75; + } } } layer_height = std::min(layer_height, max_height); @@ -524,6 +530,9 @@ Flow raft_flow(const PrintObject* object, float layer_height) layer_height = object->config().raft_interface_layer_height.get_abs_value(nzd); if (layer_height == 0) { layer_height = object->print()->config().max_layer_height.get_abs_value(extruder_id, nzd); + if (layer_height == 0) { + layer_height = nzd * 0.75; + } } } layer_height = std::min(layer_height, max_height); @@ -559,6 +568,9 @@ Flow raft_interface_flow(const PrintObject* object, float layer_height) layer_height = object->config().raft_interface_layer_height.get_abs_value(nzd); if (layer_height == 0) { layer_height = object->print()->config().max_layer_height.get_abs_value(extruder_id, nzd); + if (layer_height == 0) { + layer_height = nzd * 0.75; + } } } layer_height = std::min(layer_height, max_height); diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 07a5a7150..33a189291 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -4039,7 +4039,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s current_pos = pt_inside.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) * dist); + Polygons polys = offset(original_polygon, -dist); //find nearest point size_t best_poly_idx = 0; size_t best_pt_idx = 0; diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 83751a3c2..09259d041 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -792,13 +792,24 @@ Point SeamPlacer::calculate_seam(const Layer& layer, SeamPosition seam_position, if (saw_custom) last_pos = candidate; } - if(!saw_custom) + if (!saw_custom) { if (external_perimeters_first || (loop.loop_role() & ExtrusionLoopRole::elrFirstLoop) != 0) { // this is if external_perimeters_first // this is if only space for one externalperimeter. //in these case, there isn't a seam from the inner loops, so we had to creat our on last_pos = this->get_random_seam(layer_idx, polygon, po_idx); + } else if (po != nullptr) { + //just in case, do random if it's on top of a previous one + Point aligned_last_pos; + std::optional<Point> pos = m_seam_history.get_last_seam(m_po_list[po_idx], layer_po->print_z, loop.polygon().bounding_box()); + if (pos.has_value()) { + aligned_last_pos = *pos; + } + if (aligned_last_pos.distance_to(last_pos) < std::max(coord_t(polygon.length() / 100), nozzle_r*5) ){ + last_pos = this->get_random_seam(layer_idx, polygon, po_idx); + } } + } } else if (loop.role() == erThinWall) { //thin wall loop is like an external perimeter, but without anything near it. last_pos = this->get_random_seam(layer_idx, polygon, po_idx); diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 502622463..de76437d6 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -5,7 +5,6 @@ #include "ExtrusionEntityCollection.hpp" #include "Geometry.hpp" #include "ShortestPath.hpp" -#include "clipper/clipper_z.hpp" #include "Arachne/WallToolPaths.hpp" #include "Arachne/utils/ExtrusionLine.hpp" @@ -126,91 +125,6 @@ static void fuzzy_extrusion_line(Arachne::ExtrusionLine &ext_lines, double fuzzy ext_lines.junctions = std::move(out); } -static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Paths &subjects, const ClipperLib_Z::Paths &clip, ClipperLib_Z::ClipType clipType) -{ - ClipperLib_Z::Clipper clipper; - clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot, - const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) { - ClipperLib_Z::IntPoint start = e1bot; - ClipperLib_Z::IntPoint end = e1top; - - if (start.z() <= 0 && end.z() <= 0) { - start = e2bot; - end = e2top; - } - - assert(start.z() > 0 && end.z() > 0); - - // Interpolate extrusion line width. - double length_sqr = (end - start).cast<double>().squaredNorm(); - double dist_sqr = (pt - start).cast<double>().squaredNorm(); - double t = std::sqrt(dist_sqr / length_sqr); - - pt.z() = start.z() + coord_t((end.z() - start.z()) * t); - }); - - clipper.AddPaths(subjects, ClipperLib_Z::ptSubject, false); - clipper.AddPaths(clip, ClipperLib_Z::ptClip, true); - - ClipperLib_Z::PolyTree clipped_polytree; - ClipperLib_Z::Paths clipped_paths; - clipper.Execute(clipType, clipped_polytree, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero); - ClipperLib_Z::PolyTreeToPaths(clipped_polytree, clipped_paths); - - // Clipped path could contain vertices from the clip with a Z coordinate equal to zero. - // For those vertices, we must assign value based on the subject. - // This happens only in sporadic cases. - for (ClipperLib_Z::Path &path : clipped_paths) - for (ClipperLib_Z::IntPoint &c_pt : path) - if (c_pt.z() == 0) { - const Point pt(c_pt.x(), c_pt.y()); - Point projected_pt_min; - const ClipperLib_Z::IntPoint* it_a = nullptr; - const ClipperLib_Z::IntPoint* it_b = nullptr; - auto dist_sqr_min = std::numeric_limits<double>::max(); - Point prev(0,0); - for (const ClipperLib_Z::Path& subject : subjects) { - // Now we must find the corresponding line on with this point is located and compute line width (Z coordinate). - if (subject.size() <= 2) - continue; - - for (auto it = std::next(subject.begin()); it != subject.end(); ++it) { - Point curr(it->x(), it->y()); - if (it_a == nullptr) { - assert(std::prev(it) == subject.begin()); - prev = Point(subject.front().x(), subject.front().y()); - } - Point projected_pt = pt.projection_onto(Line(prev, curr)); - if (double dist_sqr = (projected_pt - pt).cast<double>().squaredNorm(); dist_sqr < dist_sqr_min) { - dist_sqr_min = dist_sqr; - projected_pt_min = projected_pt; - it_a = &*std::prev(it); - it_b = &*it; - } - prev = curr; - } - - assert(dist_sqr_min <= SCALED_EPSILON); - assert(*it_a != subject.back()); - } - - const Point pt_a(it_a->x(), it_a->y()); - const Point pt_b(it_b->x(), it_b->y()); - const double line_len = (pt_b - pt_a).cast<double>().norm(); - const double dist = (projected_pt_min - pt_a).cast<double>().norm(); - c_pt.z() = coord_t(double(it_a->z()) + (dist / line_len) * double(it_b->z() - it_a->z())); - } - assert([&clipped_paths = std::as_const(clipped_paths)]() -> bool { - for (const ClipperLib_Z::Path &path : clipped_paths) - for (const ClipperLib_Z::IntPoint &pt : path) - if (pt.z() <= 0) - return false; - return true; - }()); - - return clipped_paths; -} - void convert_to_clipperpath(const Polygons& source, ClipperLib_Z::Paths& dest) { dest.clear(); dest.reserve(source.size()); @@ -2049,8 +1963,9 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const Polyline& loop_polygon } -ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& loop_polygons, ExtrusionRole role, bool is_external) const { +ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& arachne_path, ExtrusionRole role, bool is_external) const { ExtrusionPaths paths; + const bool is_loop = Point{ arachne_path.front().x(), arachne_path.front().y() }.coincides_with_epsilon(Point{ arachne_path.back().x(), arachne_path.back().y() }); const double overhangs_width = this->config->overhangs_width.get_abs_value(this->overhang_flow.nozzle_diameter()); const double overhangs_width_speed = this->config->overhangs_width_speed.get_abs_value(this->overhang_flow.nozzle_diameter()); if (0 == overhangs_width && 0 == overhangs_width_speed) { @@ -2058,7 +1973,7 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& lo //assert(path.mm3_per_mm == path.mm3_per_mm); //assert(path.width == path.width); //assert(path.height == path.height); - append(paths, Geometry::variable_width(Arachne::to_thick_polyline(loop_polygons), + append(paths, Geometry::variable_width(Arachne::to_thick_polyline(arachne_path), role, is_external ? this->ext_perimeter_flow : this->perimeter_flow, std::max(this->ext_perimeter_flow.scaled_width() / 4, scale_t(this->print_config->resolution)), @@ -2068,7 +1983,7 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& lo } //set the fan & speed before the flow - ClipperLib_Z::Paths ok_polylines = { loop_polygons }; + ClipperLib_Z::Paths ok_polylines = { arachne_path }; ClipperLib_Z::Paths small_speed; ClipperLib_Z::Paths big_speed; @@ -2264,7 +2179,7 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& lo bool has_speed = !small_speed.empty() || !big_speed.empty(); bool has_flow = !small_flow.empty() || !big_flow.empty(); - std::function<void(ExtrusionPaths&, const std::function<bool(ExtrusionPath&, ExtrusionPath&, ExtrusionPath&)>&)> foreach = [](ExtrusionPaths& paths, const std::function<bool(ExtrusionPath&, ExtrusionPath&, ExtrusionPath&)>& doforeach) { + std::function<void(ExtrusionPaths&, const std::function<bool(ExtrusionPath&, ExtrusionPath&, ExtrusionPath&)>&)> foreach = [is_loop](ExtrusionPaths& paths, const std::function<bool(ExtrusionPath&, ExtrusionPath&, ExtrusionPath&)>& doforeach) { if (paths.size() > 2) for (int i = 1; i < paths.size() - 1; i++) { if (doforeach(paths[i - 1], paths[i], paths[i + 1])) { @@ -2276,22 +2191,26 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const ClipperLib_Z::Path& lo } } } - if (paths.size() > 2) - if (doforeach(paths[paths.size() - 2], paths.back(), paths.front())) { - paths.erase(paths.end() - 1); - if (paths.back().height == paths.front().height) { - paths.front().polyline.points.insert(paths.front().polyline.points.begin(), paths.back().polyline.points.begin(), paths.back().polyline.points.end() - 1); + if (is_loop) { + if (paths.size() > 2) { + if (doforeach(paths[paths.size() - 2], paths.back(), paths.front())) { paths.erase(paths.end() - 1); + if (paths.back().height == paths.front().height) { + paths.front().polyline.points.insert(paths.front().polyline.points.begin(), paths.back().polyline.points.begin(), paths.back().polyline.points.end() - 1); + paths.erase(paths.end() - 1); + } } } - if (paths.size() > 2) - if (doforeach(paths.back(), paths.front(), paths[1])) { - paths.erase(paths.begin()); - if (paths.back().height == paths.front().height) { - paths.front().polyline.points.insert(paths.front().polyline.points.begin(), paths.back().polyline.points.begin(), paths.back().polyline.points.end() - 1); - paths.erase(paths.end() - 1); + if (paths.size() > 2) { + if (doforeach(paths.back(), paths.front(), paths[1])) { + paths.erase(paths.begin()); + if (paths.back().height == paths.front().height) { + paths.front().polyline.points.insert(paths.front().polyline.points.begin(), paths.back().polyline.points.begin(), paths.back().polyline.points.end() - 1); + paths.erase(paths.end() - 1); + } } } + } }; if (paths.size() > 2) { @@ -2393,12 +2312,11 @@ static void fuzzy_paths(ExtrusionPaths& paths, coordf_t fuzzy_skin_thickness, co //not always a loop, with arachne bool is_loop = paths.front().first_point() == last_point; #ifdef _DEBUG - assert(paths.back().last_point() == paths.front().first_point()); + if (is_loop) + assert(paths.back().last_point() == paths.front().first_point()); for (int i = 1; i < paths.size(); i++) { assert(paths[i - 1].last_point() == paths[i].first_point()); } - if (is_loop) - assert(paths.front().polyline.points.front() == paths.back().polyline.points.back()); #endif Point p0 = is_loop ? last_point : paths.front().first_point(); const Point* previous_point = is_loop ? &last_point : &paths.front().first_point(); @@ -2438,7 +2356,8 @@ static void fuzzy_paths(ExtrusionPaths& paths, coordf_t fuzzy_skin_thickness, co paths.back().polyline.points.push_back(last_point); } #ifdef _DEBUG - assert(paths.back().last_point() == paths.front().first_point()); + if (is_loop) + assert(paths.back().last_point() == paths.front().first_point()); for (int i = 1; i < paths.size(); i++) { assert(paths[i - 1].last_point() == paths[i].first_point()); } @@ -2580,13 +2499,21 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops( ExtrusionEntityCollection PerimeterGenerator::_traverse_extrusions(std::vector<PerimeterGeneratorArachneExtrusion>& pg_extrusions) { ExtrusionEntityCollection extrusion_coll; + size_t biggest_inset_idx = 0; + for (PerimeterGeneratorArachneExtrusion& pg_extrusion : pg_extrusions) { + biggest_inset_idx = std::max(biggest_inset_idx, pg_extrusion.extrusion->inset_idx); + } for (PerimeterGeneratorArachneExtrusion& pg_extrusion : pg_extrusions) { Arachne::ExtrusionLine* extrusion = pg_extrusion.extrusion; - if (extrusion->empty()) + if (extrusion->isZeroLength()) continue; const bool is_external = extrusion->inset_idx == 0; ExtrusionRole role = is_external ? erExternalPerimeter : erPerimeter; + ExtrusionLoopRole loop_role = ExtrusionLoopRole::elrDefault; + if (biggest_inset_idx == extrusion->inset_idx) { + loop_role = ExtrusionLoopRole(ExtrusionLoopRole::elrInternal | ExtrusionLoopRole::elrFirstLoop); + } // fuzzy_extrusion_line() don't work. I can use fuzzy_paths() anyway, not a big deal. //if (pg_extrusion.fuzzify) @@ -2599,8 +2526,12 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_extrusions(std::vector<P this->object_config->support_material_contact_distance.value == 0)) { ClipperLib_Z::Path extrusion_path; extrusion_path.reserve(extrusion->size()); - for (const Arachne::ExtrusionJunction& ej : extrusion->junctions) - extrusion_path.emplace_back(ej.p.x(), ej.p.y(), ej.w); + for (const Arachne::ExtrusionJunction& ej : extrusion->junctions) { + //remove duplicate poitns from arachne + if(extrusion_path.empty() || + (ej.p.x() != extrusion_path.back().x() || ej.p.y() != extrusion_path.back().y())) + extrusion_path.emplace_back(ej.p.x(), ej.p.y(), ej.w); + } paths = this->create_overhangs(extrusion_path, role, is_external); // Reapply the nearest point search for starting point. @@ -2659,7 +2590,7 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_extrusions(std::vector<P // Append paths to collection. if (!paths.empty()) { if (extrusion->is_closed) { - ExtrusionLoop extrusion_loop(std::move(paths)); + ExtrusionLoop extrusion_loop(std::move(paths), loop_role); // Restore the orientation of the extrusion loop. //TODO: use if (loop.is_steep_overhang && this->layer->id() % 2 == 1) to make_clockwise => need to detect is_steep_overhang on the arachne path if (pg_extrusion.is_contour) diff --git a/src/libslic3r/ShortestPath.cpp b/src/libslic3r/ShortestPath.cpp index aae443395..d5a920759 100644 --- a/src/libslic3r/ShortestPath.cpp +++ b/src/libslic3r/ShortestPath.cpp @@ -1069,6 +1069,13 @@ void reorder_extrusion_paths(std::vector<ExtrusionPath> &extrusion_paths, const if (idx.second) out.back().reverse(); } + //FIXME: TODO: find the real cause inside chain_extrusion_paths + // for now on, jsut verify & patch that + if (out.size() > 1 + && !out.front().last_point().coincides_with_epsilon(out[1].first_point()) + && out.front().first_point().coincides_with_epsilon(out[1].first_point())) { + out.front().reverse(); + } extrusion_paths.swap(out); } diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index c9d227a85..a263dd8c4 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -25,7 +25,7 @@ #include <boost/property_tree/ptree.hpp> static const float GROUND_Z = -0.02f; -static const std::array<float, 4> DEFAULT_GRID_COLOR = { 0.9f, 0.9, 0.9, 0.6f }; +static const std::array<float, 4> DEFAULT_GRID_COLOR = { 0.9f, 0.9f, 0.9f, 0.6f }; static const std::array<float, 4> DEFAULT_MODEL_COLOR = { 0.235f, 0.235f, 0.235f, 1.0f }; static const std::array<float, 4> PICKING_MODEL_COLOR = { 0.0f, 0.0f, 0.0f, 1.0f }; diff --git a/src/slic3r/GUI/FreeCADDialog.cpp b/src/slic3r/GUI/FreeCADDialog.cpp index 959756f6d..271e3ef2d 100644 --- a/src/slic3r/GUI/FreeCADDialog.cpp +++ b/src/slic3r/GUI/FreeCADDialog.cpp @@ -784,7 +784,7 @@ bool FreeCADDialog::init_start_python() { delete exec_var; exec_var = new ExecVar(); -#ifdef __WINDO2WS__ +#ifdef __WINDOWS__ // Get the freecad path (python path) boost::filesystem::path pythonpath(gui_app->app_config->get("freecad_path")); if (pythonpath.filename().string().find("python") == std::string::npos) { |