diff options
Diffstat (limited to 'xs/src/libslic3r/Geometry.cpp')
-rw-r--r-- | xs/src/libslic3r/Geometry.cpp | 87 |
1 files changed, 52 insertions, 35 deletions
diff --git a/xs/src/libslic3r/Geometry.cpp b/xs/src/libslic3r/Geometry.cpp index d4528e864..6d864f631 100644 --- a/xs/src/libslic3r/Geometry.cpp +++ b/xs/src/libslic3r/Geometry.cpp @@ -324,7 +324,7 @@ MedialAxis::build(ThickPolylines* polylines) if (edge->is_secondary() || edge->is_infinite()) continue; // don't re-validate twins - if (seen_edges.find(&*edge) != seen_edges.end()) continue; + if (seen_edges.find(&*edge) != seen_edges.end()) continue; // TODO: is this needed? seen_edges.insert(&*edge); seen_edges.insert(edge->twin()); @@ -445,49 +445,66 @@ MedialAxis::validate_edge(const VD::edge_type* edge) } // retrieve the original line segments which generated the edge we're checking - const VD::cell_type* cell1 = edge->cell(); - const VD::cell_type* cell2 = edge->twin()->cell(); - const Line &segment1 = this->retrieve_segment(cell1); - const Line &segment2 = this->retrieve_segment(cell2); + const VD::cell_type* cell_l = edge->cell(); + const VD::cell_type* cell_r = edge->twin()->cell(); + const Line &segment_l = this->retrieve_segment(cell_l); + const Line &segment_r = this->retrieve_segment(cell_r); - /* Calculate thickness of the section at both the endpoints of this edge. - Our Voronoi edge is part of a CCW sequence going around its Voronoi cell - (segment1). This edge's twin goes around segment2. Thus, segment2 is - oriented in the same direction as our main edge, and segment1 is oriented + /* + SVG svg("edge.svg"); + svg.draw(*this->expolygon); + svg.draw(line); + svg.draw(segment_l, "red"); + svg.draw(segment_r, "blue"); + svg.Close(); + */ + + /* Calculate thickness of the cross-section at both the endpoints of this edge. + Our Voronoi edge is part of a CCW sequence going around its Voronoi cell + located on the left side. (segment_l). + This edge's twin goes around segment_r. Thus, segment_r is + oriented in the same direction as our main edge, and segment_l is oriented in the same direction as our twin edge. - We used to only consider the (half-)distances to segment2, and that works - whenever segment1 and segment2 are almost specular and facing. However, + We used to only consider the (half-)distances to segment_r, and that works + whenever segment_l and segment_r are almost specular and facing. However, at curves they are staggered and they only face for a very little length - (such visibility actually coincides with our very short edge). This is why - we calculate w0 and w1 this way. - When cell1 or cell2 don't refer to the segment but only to an endpoint, we + (our very short edge represents such visibility). + Both w0 and w1 can be calculated either towards cell_l or cell_r with equal + results by Voronoi definition. + When cell_l or cell_r don't refer to the segment but only to an endpoint, we calculate the distance to that endpoint instead. */ - coordf_t w0 = cell2->contains_segment() - ? line.a.perp_distance_to(segment2)*2 - : line.a.distance_to(this->retrieve_endpoint(cell2))*2; + coordf_t w0 = cell_r->contains_segment() + ? line.a.distance_to(segment_r)*2 + : line.a.distance_to(this->retrieve_endpoint(cell_r))*2; - coordf_t w1 = cell1->contains_segment() - ? line.b.perp_distance_to(segment1)*2 - : line.b.distance_to(this->retrieve_endpoint(cell1))*2; + coordf_t w1 = cell_l->contains_segment() + ? line.b.distance_to(segment_l)*2 + : line.b.distance_to(this->retrieve_endpoint(cell_l))*2; - // if this edge is the centerline for a very thin area, we might want to skip it - // in case the area is too thin - if (w0 < SCALED_EPSILON || w1 < SCALED_EPSILON) { - if (cell1->contains_segment() && cell2->contains_segment()) { - // calculate the relative angle between the two boundary segments - double angle = fabs(segment2.orientation() - segment1.orientation()); + if (cell_l->contains_segment() && cell_r->contains_segment()) { + // calculate the relative angle between the two boundary segments + double angle = fabs(segment_r.orientation() - segment_l.orientation()); + if (angle > PI) angle = 2*PI - angle; + assert(angle >= 0 && angle <= PI); + + // fabs(angle) ranges from 0 (collinear, same direction) to PI (collinear, opposite direction) + // we're interested only in segments close to the second case (facing segments) + // so we allow some tolerance. + // this filter ensures that we're dealing with a narrow/oriented area (longer than thick) + // we don't run it on edges not generated by two segments (thus generated by one segment + // and the endpoint of another segment), since their orientation would not be meaningful + if (PI - angle > PI/8) { + // angle is not narrow enough - // fabs(angle) ranges from 0 (collinear, same direction) to PI (collinear, opposite direction) - // we're interested only in segments close to the second case (facing segments) - // so we allow some tolerance. - // this filter ensures that we're dealing with a narrow/oriented area (longer than thick) - // we don't run it on edges not generated by two segments (thus generated by one segment - // and the endpoint of another segment), since their orientation would not be meaningful - if (fabs(angle - PI) > PI/5) return false; - } else { - return false; + // only apply this filter to segments that are not too short otherwise their + // angle could possibly be not meaningful + if (w0 < SCALED_EPSILON || w1 < SCALED_EPSILON || line.length() >= this->min_width) + return false; } + } else { + if (w0 < SCALED_EPSILON || w1 < SCALED_EPSILON) + return false; } if (w0 < this->min_width && w1 < this->min_width) |