Browse Source

Merge remote-tracking branch 'remotes/supermerill/master'

supermerill 5 years ago
parent
commit
a4572696e7

+ 15 - 11
src/libslic3r/Fill/FillRectilinear2.cpp

@@ -1775,13 +1775,18 @@ FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const F
 
     // remove areas for gapfill 
     // factor=0.5 : remove area smaller than a spacing. factor=1 : max spacing for the gapfill (but not the width)
-    float factor = 0.9f;
-    ExPolygons rectilinear_areas = offset2_ex(ExPolygons{ surface->expolygon }, -params.flow->scaled_spacing() * factor, params.flow->scaled_spacing() * factor);
+    //choose between 2 to avoid dotted line  effect.
+    float factor1 = 0.99f;
+    float factor2 = 0.7f;
+    ExPolygons rectilinear_areas1 = offset2_ex(ExPolygons{ surface->expolygon }, -params.flow->scaled_spacing() * factor1, params.flow->scaled_spacing() * factor1);
+    ExPolygons rectilinear_areas2 = offset2_ex(ExPolygons{ surface->expolygon }, -params.flow->scaled_spacing() * factor2, params.flow->scaled_spacing() * factor2);
+    std::cout << "FillRectilinear2WGapFill use " << (rectilinear_areas1.size() <= rectilinear_areas2.size() + 1 ? "1" : "2") << "\n";
+    ExPolygons &rectilinear_areas = rectilinear_areas1.size() <= rectilinear_areas2.size() + 1 ? rectilinear_areas1 : rectilinear_areas2;
     ExPolygons gapfill_areas = diff_ex(ExPolygons{ surface->expolygon }, rectilinear_areas);
     double rec_area = 0;
     for (ExPolygon &p : rectilinear_areas)rec_area += p.area();
     double gf_area = 0;
-    for (ExPolygon &p : gapfill_areas)gf_area += p.area();
+    for (ExPolygon &p : gapfill_areas) gf_area += p.area();
     //std::cout << unscaled(unscaled(surface->expolygon.area())) << " = " << unscaled(unscaled(rec_area)) << " + " << unscaled(unscaled(gf_area)) << "\n";
 
     // rectilinear
@@ -1851,21 +1856,20 @@ FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const F
     //gapfill
     if (gapfill_areas.size() > 0) {
         ThickPolylines polylines_gapfill;
-        double min = 0.2 * params.flow->scaled_width() * (1 - INSET_OVERLAP_TOLERANCE);
+        double min = 0.4 * scale_(params.flow->nozzle_diameter) * (1 - INSET_OVERLAP_TOLERANCE);
         double max = 2. * params.flow->scaled_width();
         // collapse 
-        double min_offset = 0.1 * params.flow->scaled_width() * (1 - INSET_OVERLAP_TOLERANCE);
         //be sure we don't gapfill where the perimeters are already touching each other (negative spacing).
         min = std::max(min, double(Flow::new_from_spacing(EPSILON, params.flow->nozzle_diameter , params.flow->height, false).scaled_width()));
-        double max_offset = 2. * params.flow->scaled_spacing();
-        ExPolygons gapfill_areas_collapsed = diff_ex(
-            offset2_ex(gapfill_areas, double(-min_offset / 2), double(+min_offset / 2)),
-            offset2_ex(gapfill_areas, double(-max_offset / 2), double(+max_offset / 2)),
-            true);
+        //ExPolygons gapfill_areas_collapsed = diff_ex(
+        //    offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2)),
+        //    offset2_ex(gapfill_areas, double(-max / 2), double(+max / 2)),
+        //    true);
+        ExPolygons gapfill_areas_collapsed = offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2));
         for (const ExPolygon &ex : gapfill_areas_collapsed) {
             //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() > scale_(params.flow->nozzle_diameter)*scale_(params.flow->nozzle_diameter) * 2) {
                 MedialAxis{ ex, params.flow->scaled_width() * 2, params.flow->scaled_width() / 5, coord_t(params.flow->height) }.build(polylines_gapfill);
             }
         }

+ 78 - 13
src/libslic3r/MedialAxis.cpp

@@ -29,28 +29,30 @@ MedialAxis::polyline_from_voronoi(const Lines& voronoi_edges, ThickPolylines* po
     this->lines = voronoi_edges;
     construct_voronoi(lines.begin(), lines.end(), &this->vd);
 
-    /*
+    typedef const VD::edge_type   edge_t;
+    
     // DEBUG: dump all Voronoi edges
-    {
+    /*{
         for (VD::const_edge_iterator edge = this->vd.edges().begin(); edge != this->vd.edges().end(); ++edge) {
             if (edge->is_infinite()) continue;
-            
+            const edge_t* edgeptr = &*edge;
             ThickPolyline polyline;
             polyline.points.push_back(Point( edge->vertex0()->x(), edge->vertex0()->y() ));
             polyline.points.push_back(Point( edge->vertex1()->x(), edge->vertex1()->y() ));
+            polyline.width.push_back(this->thickness[edgeptr].first);
+            polyline.width.push_back(this->thickness[edgeptr].second);
             polylines->push_back(polyline);
         }
         return;
-    }
-    */
+    }*/
+    
     
-    typedef const VD::edge_type   edge_t;
     
     // collect valid edges (i.e. prune those not belonging to MAT)
     // note: this keeps twins, so it inserts twice the number of the valid edges
     this->valid_edges.clear();
     {
-        std::set<const VD::edge_type*> seen_edges;
+        std::set<const edge_t*> seen_edges;
         for (VD::const_edge_iterator edge = this->vd.edges().begin(); edge != this->vd.edges().end(); ++edge) {
             // if we only process segments representing closed loops, none if the
             // infinite edges (if any) would be part of our MAT anyway
@@ -71,6 +73,18 @@ MedialAxis::polyline_from_voronoi(const Lines& voronoi_edges, ThickPolylines* po
     // iterate through the valid edges to build polylines
     while (!this->edges.empty()) {
         const edge_t* edge = *this->edges.begin();
+        if (this->thickness[edge].first > this->max_width*1.001) {
+            //std::cerr << "Error, edge.first has a thickness of " << unscaled(this->thickness[edge].first) << " > " << unscaled(this->max_width) << "\n";
+            //(void)this->edges.erase(edge);
+            //(void)this->edges.erase(edge->twin());
+            //continue;
+        }
+        if (this->thickness[edge].second > this->max_width*1.001) {
+            //std::cerr << "Error, edge.second has a thickness of " << unscaled(this->thickness[edge].second) << " > " << unscaled(this->max_width) << "\n";
+            //(void)this->edges.erase(edge);
+            //(void)this->edges.erase(edge->twin());
+            //continue;
+        }
         
         // start a polyline
         ThickPolyline polyline;
@@ -97,7 +111,7 @@ MedialAxis::polyline_from_voronoi(const Lines& voronoi_edges, ThickPolylines* po
         
         assert(polyline.width.size() == polyline.points.size());
         
-        // prevent loop endpoints from being extended
+        // if loop, set endpoints to false
         if (polyline.first_point().coincides_with(polyline.last_point())) {
             polyline.endpoints.first = false;
             polyline.endpoints.second = false;
@@ -446,7 +460,7 @@ MedialAxis::fusion_curve(ThickPolylines &pp)
     for (size_t i = 0; i < pp.size(); ++i) {
         ThickPolyline& polyline = pp[i];
         // only consider 2-point polyline with endpoint
-        if (polyline.points.size() != 2) continue;
+        //if (polyline.points.size() != 2) continue; // too restrictive.
         if (polyline.endpoints.first) polyline.reverse();
         else if (!polyline.endpoints.second) continue;
         if (polyline.width.back() > EPSILON) continue;
@@ -496,6 +510,10 @@ MedialAxis::fusion_curve(ThickPolylines &pp)
                 sum_dot += dot_temp;
             }
         }
+        sum_dot = abs(sum_dot);
+        std::cout << "    with mindot= " << min_dot << "< 0.5" << " ; with sum_dot= " << sum_dot << "< 0.2" << " ; with crosspoint.size= " << crosspoint.size() << " ; with coeff_contour_angle= " << coeff_contour_angle << " 0.2> " << (1 - (coeff_contour_angle / (PI / 2)))
+            << " ; length= " << unscaled(polyline.length())<<" >? 1.42*width= "<< polyline.width.front()<<"->"<< polyline.width.back() << "\n";
+
         //only consider very shallow angle for contour
         if (mindot > 0.15 &&
             (1 - (coeff_contour_angle / (PI / 2))) > 0.2) continue;
@@ -504,6 +522,8 @@ MedialAxis::fusion_curve(ThickPolylines &pp)
         if (crosspoint.size() != 2) continue;
         if (sum_dot > 0.2) continue;
         if (min_dot > 0.5) continue;
+        //don't remove useful bits. TODO: use the mindot to know by how much to multiply (1 when 90°, 1.42 when 45+, 1 when 0°)
+        if (polyline.length() > polyline.width.front()*1.42) continue;
 
         //don't pull, it distords the line if there are too many points.
         //// pull it a bit, depends on my size, the dot?, and the coeff at my 0-end (~14% for a square, almost 0 for a gentle curve)
@@ -534,6 +554,8 @@ MedialAxis::fusion_curve(ThickPolylines &pp)
         concatThickPolylines(pp);
         ///reorder, in case of change
         std::sort(pp.begin(), pp.end(), [](const ThickPolyline & a, const ThickPolyline & b) { return a.length() < b.length(); });
+        //have to redo it to remove multi-branch bits.
+        fusion_curve(pp);
     }
 }
 
@@ -622,8 +644,14 @@ MedialAxis::extends_line_both_side(ThickPolylines& pp) {
     for (size_t i = 0; i < pp.size(); ++i) {
         ThickPolyline& polyline = pp[i];
         this->extends_line(polyline, anchors, this->min_width);
-        polyline.reverse();
-        this->extends_line(polyline, anchors, this->min_width);
+        if (!polyline.points.empty()) {
+            polyline.reverse();
+            this->extends_line(polyline, anchors, this->min_width);
+        }
+        if (polyline.points.empty()) {
+            pp.erase(pp.begin() + i);
+            --i;
+        }
     }
 }
 
@@ -742,9 +770,8 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con
             l2.extend_end(max_width);
             (void)bounds->contour.first_intersection(l2, &new_bound);
         }
-        if (new_bound.coincides_with_epsilon(new_back)) {
+        if (new_bound.coincides_with_epsilon(new_back))
             return;
-        }
         polyline.points.push_back(new_bound);
         //polyline.width.push_back(join_width);
         //it thickens the line a bit too early, imo
@@ -1303,6 +1330,22 @@ MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_siz
     }
 }
 
+void
+MedialAxis::check_width(ThickPolylines& pp, double 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] > max_width * 1.01) {
+                std::cout << "Error " << msg << " width " << unscaled(pp[i].width[j]) << "(" << i << ":" << j << ") > " << unscaled(max_width) << "\n";
+                nb++;
+            }
+        }
+    }
+    if (nb > 0) std::cout << "== nbBig = " << nb << " ==\n";
+}
+
 void
 MedialAxis::ensure_not_overextrude(ThickPolylines& pp)
 {
@@ -1494,6 +1537,27 @@ MedialAxis::build(ThickPolylines &polylines_out)
     // compute the Voronoi diagram and extract medial axis polylines
     ThickPolylines pp;
     this->polyline_from_voronoi(this->expolygon.lines(), &pp);
+
+    //sanity check, as the voronoi can return (abeit very rarely) randomly high values.
+    for (ThickPolyline &tp : pp) {
+        for (int i = 0; i < tp.width.size(); i++) {
+            if (tp.width[i] > this->max_width) {
+                tp.width[i] = this->max_width;
+            }
+        }
+    }
+    //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.Close();
+    //}
+
+    //check_width(pp, this->max_width, "polyline_from_voronoi");
     
     concatThickPolylines(pp);
 
@@ -1522,6 +1586,7 @@ MedialAxis::build(ThickPolylines &polylines_out)
     //    std::cout << "\n";
     //}
 
+    // "remove" the little paths that are at the outside of a curve.
     fusion_curve(pp);
     //{
     //    std::stringstream stri;

+ 2 - 0
src/libslic3r/MedialAxis.hpp

@@ -110,6 +110,8 @@ class MedialAxis {
         void grow_to_nozzle_diameter(ThickPolylines& pp, const ExPolygons& anchors);
         /// taper the ends of polylines (don't activate that for gapfill)
         void taper_ends(ThickPolylines& pp);
+        //cleaning method
+        void check_width(ThickPolylines& pp, double max_width, std::string msg);
 };
     
     /// create a ExtrusionEntityCollection from ThickPolylines, discretizing the variable width into little sections (of 4*SCALED_RESOLUTION length) where needed.

+ 0 - 1
src/libslic3r/Polyline.cpp

@@ -279,7 +279,6 @@ void concatThickPolylines(ThickPolylines& pp) {
             for (size_t j = 0; j < pp.size(); ++j) {
                 if (j == i) continue;
                 ThickPolyline *other = &pp[j];
-                if (other->first_point().coincides_with(other->last_point())) continue;
                 if (polyline->last_point().coincides_with(other->last_point())) {
                     id_candidate_last_point = j;
                     nbCandidate_last_point++;

+ 37 - 8
src/test/libslic3r/test_thin.cpp

@@ -86,30 +86,37 @@ SCENARIO("thin walls: ")
             }
         }
     }
-    
+
     //TODO: compare with mainline slic3r
-    GIVEN("semicicumference"){
+    GIVEN("semicicumference") {
         ExPolygon expolygon;
         expolygon.contour = Slic3r::Polygon{ Points{
-            Point{ 1185881, 829367 }, Point{ 1421988, 1578184 }, Point{ 1722442, 2303558 }, Point{ 2084981, 2999998 }, Point{ 2506843, 3662186 }, Point{ 2984809, 4285086 }, Point{ 3515250, 4863959 }, Point{ 4094122, 5394400 }, Point{ 4717018, 5872368 }, Point{ 5379210, 6294226 }, Point{ 6075653, 6656769 }, Point{ 6801033, 6957229 }, Point{ 7549842, 7193328 }, Point{ 8316383, 7363266 }, Point{ 9094809, 7465751 }, Point{ 9879211, 7500000 }, Point{ 10663611, 7465750 }, Point{ 11442038, 7363265 }, Point{ 12208580, 7193327 }, Point{ 12957389, 6957228 }, Point{ 13682769, 6656768 }, Point{ 14379209, 6294227 }, Point{ 15041405, 5872366 }, Point{ 15664297, 5394401 }, Point{ 16243171, 4863960 }, Point{ 16758641, 4301424 }, Point{ 17251579, 3662185 }, Point{ 17673439, 3000000 }, Point{ 18035980, 2303556 }, Point{ 18336441, 1578177 }, Point{ 18572539, 829368 }, Point{ 18750748, 0 }, Point{ 19758422, 0 }, Point{ 19727293, 236479 }, Point{ 19538467, 1088188 }, Point{ 19276136, 1920196 }, Point{ 18942292, 2726179 }, Point{ 18539460, 3499999 }, Point{ 18070731, 4235755 }, Point{ 17539650, 4927877 }, Point{ 16950279, 5571067 }, Point{ 16307090, 6160437 }, Point{ 15614974, 6691519 }, Point{ 14879209, 7160248 }, Point{ 14105392, 7563079 }, Point{ 13299407, 7896927 }, Point{ 12467399, 8159255 }, Point{ 11615691, 8348082 }, Point{ 10750769, 8461952 }, Point{ 9879211, 8500000 }, Point{ 9007652, 8461952 }, Point{ 8142729, 8348082 }, Point{ 7291022, 8159255 }, Point{ 6459015, 7896927 }, Point{ 5653029, 7563079 }, Point{ 4879210, 7160247 }, Point{ 4143447, 6691519 }, Point{ 3451331, 6160437 }, Point{ 2808141, 5571066 }, Point{ 2218773, 4927878 }, Point{ 1687689, 4235755 }, Point{ 1218962, 3499999 }, Point{ 827499, 2748020 }, Point{ 482284, 1920196 }, Point{ 219954, 1088186 }, Point{ 31126, 236479 }, Point{ 0, 0 }, Point{ 1005754, 0 }
+            Point{ 1185881, 829367 }, Point{ 1421988, 1578184 }, Point{ 1722442, 2303558 }, Point{ 2084981, 2999998 }, Point{ 2506843, 3662186 }, Point{ 2984809, 4285086 }, Point{ 3515250, 4863959 }, Point{ 4094122, 5394400 }, Point{ 4717018, 5872368 }, 
+            Point{ 5379210, 6294226 }, Point{ 6075653, 6656769 }, Point{ 6801033, 6957229 }, Point{ 7549842, 7193328 }, Point{ 8316383, 7363266 }, Point{ 9094809, 7465751 }, Point{ 9879211, 7500000 }, Point{ 10663611, 7465750 }, Point{ 11442038, 7363265 }, 
+            Point{ 12208580, 7193327 }, Point{ 12957389, 6957228 }, Point{ 13682769, 6656768 }, Point{ 14379209, 6294227 }, Point{ 15041405, 5872366 }, Point{ 15664297, 5394401 }, Point{ 16243171, 4863960 }, Point{ 16758641, 4301424 }, Point{ 17251579, 3662185 }, 
+            Point{ 17673439, 3000000 }, Point{ 18035980, 2303556 }, Point{ 18336441, 1578177 }, Point{ 18572539, 829368 }, Point{ 18750748, 0 }, Point{ 19758422, 0 }, Point{ 19727293, 236479 }, Point{ 19538467, 1088188 }, Point{ 19276136, 1920196 }, 
+            Point{ 18942292, 2726179 }, Point{ 18539460, 3499999 }, Point{ 18070731, 4235755 }, Point{ 17539650, 4927877 }, Point{ 16950279, 5571067 }, Point{ 16307090, 6160437 }, Point{ 15614974, 6691519 }, Point{ 14879209, 7160248 }, Point{ 14105392, 7563079 }, 
+            Point{ 13299407, 7896927 }, Point{ 12467399, 8159255 }, Point{ 11615691, 8348082 }, Point{ 10750769, 8461952 }, Point{ 9879211, 8500000 }, Point{ 9007652, 8461952 }, Point{ 8142729, 8348082 }, Point{ 7291022, 8159255 }, Point{ 6459015, 7896927 },
+            Point{ 5653029, 7563079 }, Point{ 4879210, 7160247 }, Point{ 4143447, 6691519 }, Point{ 3451331, 6160437 }, Point{ 2808141, 5571066 }, Point{ 2218773, 4927878 }, Point{ 1687689, 4235755 }, Point{ 1218962, 3499999 }, Point{ 827499, 2748020 }, 
+            Point{ 482284, 1920196 }, Point{ 219954, 1088186 }, Point{ 31126, 236479 }, Point{ 0, 0 }, Point{ 1005754, 0 }
         } };
 
-        WHEN("creating the medial axis"){
+        WHEN("creating the medial axis") {
             Polylines res;
             expolygon.medial_axis(scale_(1.324888), scale_(0.25), &res);
 
-            THEN("medial axis of a semicircumference is a single line"){
+            THEN("medial axis of a semicircumference is a single line") {
                 REQUIRE(res.size() == 1);
             }
-            THEN("all medial axis segments of a semicircumference have the same orientation (but the 2 end points)"){
+            THEN("all medial axis segments of a semicircumference have the same orientation (but the 2 end points)") {
                 Lines lines = res[0].lines();
                 double min_angle = 1, max_angle = -1;
                 //std::cout << "first angle=" << lines[0].ccw(lines[1].b) << "\n";
-                for (int idx = 1; idx < lines.size()-1; idx++){
+                for (int idx = 1; idx < lines.size() - 1; idx++) {
                     double angle = lines[idx - 1].ccw(lines[idx].b);
                     if (std::abs(angle) - EPSILON < 0) angle = 0;
                     //if (angle < 0) std::cout << unscale_(lines[idx - 1].a.x()) << ":" << unscale_(lines[idx - 1].a.y()) << " -> " << unscale_(lines[idx - 1].b.x()) << ":" << unscale_(lines[idx - 1].b.y()) << " -> " << unscale_(lines[idx].b.x()) << ":" << unscale_(lines[idx].b.y()) << "\n";
-                    std::cout << "angle=" << 180*lines[idx].a.ccw_angle(lines[idx-1].a, lines[idx].b)/PI << "\n";
+                    std::cout << "angle=" << 180 * lines[idx].a.ccw_angle(lines[idx - 1].a, lines[idx].b) / PI << "\n";
                     min_angle = std::min(min_angle, angle);
                     max_angle = std::max(max_angle, angle);
                 }
@@ -122,6 +129,28 @@ SCENARIO("thin walls: ")
             }
         }
     }
+    
+
+    GIVEN("round with large and very small distance between points"){
+        ExPolygon expolygon;
+        expolygon.contour = Slic3r::Polygon{ Points{
+            Point::new_scale(15.181601,-2.389639), Point::new_scale(15.112616,-1.320034), Point::new_scale(14.024491,-0.644338), Point::new_scale(13.978982,-0.624495), Point::new_scale(9.993299,0.855584), Point::new_scale(9.941970,0.871195), Point::new_scale(5.796743,1.872643),
+            Point::new_scale(5.743826,1.882168), Point::new_scale(1.509170,2.386464), Point::new_scale(1.455460,2.389639), Point::new_scale(-2.809359,2.389639), Point::new_scale(-2.862805,2.386464), Point::new_scale(-7.097726,1.882168), Point::new_scale(-7.150378,1.872643), Point::new_scale(-11.286344,0.873576),
+            Point::new_scale(-11.335028,0.858759), Point::new_scale(-14.348632,-0.237938), Point::new_scale(-14.360538,-0.242436), Point::new_scale(-15.181601,-0.737570), Point::new_scale(-15.171309,-2.388509)
+        } };
+        expolygon.holes.push_back(Slic3r::Polygon{ Points{
+            Point::new_scale( -11.023311,-1.034226 ), Point::new_scale( -6.920984,-0.042941 ), Point::new_scale( -2.768613,0.463207 ), Point::new_scale( 1.414714,0.463207 ), Point::new_scale( 5.567085,-0.042941 ), Point::new_scale( 9.627910,-1.047563 )
+            } });
+
+        WHEN("creating the medial axis"){
+            Polylines res;
+            expolygon.medial_axis(scale_(2.5), scale_(0.5), &res);
+
+           THEN("medial axis of it is two line"){
+                REQUIRE(res.size() == 2);
+            }
+        }
+    }
 
     GIVEN("french cross")
     {