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

This commit is contained in:
supermerill 2019-09-23 22:20:53 +02:00
commit a4572696e7
5 changed files with 132 additions and 33 deletions

View File

@ -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);
}
}

View File

@ -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,9 +644,15 @@ 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);
if (!polyline.points.empty()) {
polyline.reverse();
this->extends_line(polyline, anchors, this->min_width);
}
if (polyline.points.empty()) {
pp.erase(pp.begin() + i);
--i;
}
}
}
void
@ -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)
{
@ -1495,6 +1538,27 @@ MedialAxis::build(ThickPolylines &polylines_out)
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);
//std::cout << "concatThickPolylines\n";
@ -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;

View File

@ -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.

View File

@ -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++;

View File

@ -88,28 +88,35 @@ 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);
}
@ -123,6 +130,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")
{
ExPolygon expolygon;