Further implementation of FillRectilinear3.
This commit is contained in:
parent
137aab9631
commit
812a2c7cbd
5 changed files with 237 additions and 213 deletions
xs/src/libslic3r
|
@ -27,10 +27,6 @@
|
||||||
// We want our version of assert.
|
// We want our version of assert.
|
||||||
#include "../libslic3r.h"
|
#include "../libslic3r.h"
|
||||||
|
|
||||||
#ifndef myassert
|
|
||||||
#define myassert assert
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
// Having a segment of a closed polygon, calculate its Euclidian length.
|
// Having a segment of a closed polygon, calculate its Euclidian length.
|
||||||
|
@ -50,8 +46,8 @@ static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Po
|
||||||
std::swap(pa.x, pb.x);
|
std::swap(pa.x, pb.x);
|
||||||
if (pa.y > pb.y)
|
if (pa.y > pb.y)
|
||||||
std::swap(pa.y, pb.y);
|
std::swap(pa.y, pb.y);
|
||||||
myassert(px.x >= pa.x && px.x <= pb.x);
|
assert(px.x >= pa.x && px.x <= pb.x);
|
||||||
myassert(px.y >= pa.y && px.y <= pb.y);
|
assert(px.y >= pa.y && px.y <= pb.y);
|
||||||
}
|
}
|
||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
const Point *pPrev = &p1;
|
const Point *pPrev = &p1;
|
||||||
|
@ -288,9 +284,9 @@ public:
|
||||||
// for the infill pattern, don't cut the corners.
|
// for the infill pattern, don't cut the corners.
|
||||||
// default miterLimt = 3
|
// default miterLimt = 3
|
||||||
//double mitterLimit = 10.;
|
//double mitterLimit = 10.;
|
||||||
myassert(aoffset1 < 0);
|
assert(aoffset1 < 0);
|
||||||
myassert(aoffset2 < 0);
|
assert(aoffset2 < 0);
|
||||||
myassert(aoffset2 < aoffset1);
|
assert(aoffset2 < aoffset1);
|
||||||
bool sticks_removed = remove_sticks(polygons_src);
|
bool sticks_removed = remove_sticks(polygons_src);
|
||||||
// if (sticks_removed) printf("Sticks removed!\n");
|
// if (sticks_removed) printf("Sticks removed!\n");
|
||||||
polygons_outer = offset(polygons_src, aoffset1,
|
polygons_outer = offset(polygons_src, aoffset1,
|
||||||
|
@ -311,7 +307,7 @@ public:
|
||||||
polygons_ccw.assign(n_contours, false);
|
polygons_ccw.assign(n_contours, false);
|
||||||
for (size_t i = 0; i < n_contours; ++ i) {
|
for (size_t i = 0; i < n_contours; ++ i) {
|
||||||
contour(i).remove_duplicate_points();
|
contour(i).remove_duplicate_points();
|
||||||
myassert(! contour(i).has_duplicate_points());
|
assert(! contour(i).has_duplicate_points());
|
||||||
polygons_ccw[i] = Slic3r::Geometry::is_ccw(contour(i));
|
polygons_ccw[i] = Slic3r::Geometry::is_ccw(contour(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -406,23 +402,23 @@ static inline int intersection_on_prev_next_vertical_line(
|
||||||
if (itsct.iContour == itsct2.iContour && itsct.type == itsct2.type) {
|
if (itsct.iContour == itsct2.iContour && itsct.type == itsct2.type) {
|
||||||
/*
|
/*
|
||||||
if (itsct.is_low()) {
|
if (itsct.is_low()) {
|
||||||
myassert(itsct.type == SegmentIntersection::INNER_LOW);
|
assert(itsct.type == SegmentIntersection::INNER_LOW);
|
||||||
myassert(iIntersection > 0);
|
assert(iIntersection > 0);
|
||||||
myassert(il.intersections[iIntersection-1].type == SegmentIntersection::OUTER_LOW);
|
assert(il.intersections[iIntersection-1].type == SegmentIntersection::OUTER_LOW);
|
||||||
myassert(i > 0);
|
assert(i > 0);
|
||||||
if (il2.intersections[i-1].is_inner())
|
if (il2.intersections[i-1].is_inner())
|
||||||
// Take only the lowest inner intersection point.
|
// Take only the lowest inner intersection point.
|
||||||
continue;
|
continue;
|
||||||
myassert(il2.intersections[i-1].type == SegmentIntersection::OUTER_LOW);
|
assert(il2.intersections[i-1].type == SegmentIntersection::OUTER_LOW);
|
||||||
} else {
|
} else {
|
||||||
myassert(itsct.type == SegmentIntersection::INNER_HIGH);
|
assert(itsct.type == SegmentIntersection::INNER_HIGH);
|
||||||
myassert(iIntersection+1 < il.intersections.size());
|
assert(iIntersection+1 < il.intersections.size());
|
||||||
myassert(il.intersections[iIntersection+1].type == SegmentIntersection::OUTER_HIGH);
|
assert(il.intersections[iIntersection+1].type == SegmentIntersection::OUTER_HIGH);
|
||||||
myassert(i+1 < il2.intersections.size());
|
assert(i+1 < il2.intersections.size());
|
||||||
if (il2.intersections[i+1].is_inner())
|
if (il2.intersections[i+1].is_inner())
|
||||||
// Take only the highest inner intersection point.
|
// Take only the highest inner intersection point.
|
||||||
continue;
|
continue;
|
||||||
myassert(il2.intersections[i+1].type == SegmentIntersection::OUTER_HIGH);
|
assert(il2.intersections[i+1].type == SegmentIntersection::OUTER_HIGH);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
// The intersection points lie on the same contour and have the same orientation.
|
// The intersection points lie on the same contour and have the same orientation.
|
||||||
|
@ -487,21 +483,21 @@ static inline IntersectionTypeOtherVLine intersection_type_on_prev_next_vertical
|
||||||
// iVertical line multiple times before reaching iIntersectionOther.
|
// iVertical line multiple times before reaching iIntersectionOther.
|
||||||
if (iIntersectionOther == -1)
|
if (iIntersectionOther == -1)
|
||||||
return INTERSECTION_TYPE_OTHER_VLINE_UNDEFINED;
|
return INTERSECTION_TYPE_OTHER_VLINE_UNDEFINED;
|
||||||
myassert(dir_is_next ? (iVerticalLine + 1 < segs.size()) : (iVerticalLine > 0));
|
assert(dir_is_next ? (iVerticalLine + 1 < segs.size()) : (iVerticalLine > 0));
|
||||||
const SegmentedIntersectionLine &il_this = segs[iVerticalLine];
|
const SegmentedIntersectionLine &il_this = segs[iVerticalLine];
|
||||||
const SegmentIntersection &itsct_this = il_this.intersections[iIntersection];
|
const SegmentIntersection &itsct_this = il_this.intersections[iIntersection];
|
||||||
const SegmentedIntersectionLine &il_other = segs[dir_is_next ? (iVerticalLine+1) : (iVerticalLine-1)];
|
const SegmentedIntersectionLine &il_other = segs[dir_is_next ? (iVerticalLine+1) : (iVerticalLine-1)];
|
||||||
const SegmentIntersection &itsct_other = il_other.intersections[iIntersectionOther];
|
const SegmentIntersection &itsct_other = il_other.intersections[iIntersectionOther];
|
||||||
myassert(itsct_other.is_inner());
|
assert(itsct_other.is_inner());
|
||||||
myassert(iIntersectionOther > 0);
|
assert(iIntersectionOther > 0);
|
||||||
myassert(iIntersectionOther + 1 < il_other.intersections.size());
|
assert(iIntersectionOther + 1 < il_other.intersections.size());
|
||||||
// Is iIntersectionOther at the boundary of a vertical segment?
|
// Is iIntersectionOther at the boundary of a vertical segment?
|
||||||
const SegmentIntersection &itsct_other2 = il_other.intersections[itsct_other.is_low() ? iIntersectionOther - 1 : iIntersectionOther + 1];
|
const SegmentIntersection &itsct_other2 = il_other.intersections[itsct_other.is_low() ? iIntersectionOther - 1 : iIntersectionOther + 1];
|
||||||
if (itsct_other2.is_inner())
|
if (itsct_other2.is_inner())
|
||||||
// Cannot follow a perimeter segment into the middle of another vertical segment.
|
// Cannot follow a perimeter segment into the middle of another vertical segment.
|
||||||
// Only perimeter segments connecting to the end of a vertical segment are followed.
|
// Only perimeter segments connecting to the end of a vertical segment are followed.
|
||||||
return INTERSECTION_TYPE_OTHER_VLINE_INNER;
|
return INTERSECTION_TYPE_OTHER_VLINE_INNER;
|
||||||
myassert(itsct_other.is_low() == itsct_other2.is_low());
|
assert(itsct_other.is_low() == itsct_other2.is_low());
|
||||||
if (dir_is_next ? itsct_this.consumed_perimeter_right : itsct_other.consumed_perimeter_right)
|
if (dir_is_next ? itsct_this.consumed_perimeter_right : itsct_other.consumed_perimeter_right)
|
||||||
// This perimeter segment was already consumed.
|
// This perimeter segment was already consumed.
|
||||||
return INTERSECTION_TYPE_OTHER_VLINE_CONSUMED;
|
return INTERSECTION_TYPE_OTHER_VLINE_CONSUMED;
|
||||||
|
@ -555,9 +551,9 @@ static inline coordf_t measure_perimeter_prev_next_segment_length(
|
||||||
const SegmentIntersection &itsct2 = il2.intersections[iIntersection2];
|
const SegmentIntersection &itsct2 = il2.intersections[iIntersection2];
|
||||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||||
// const bool ccw = poly_with_offset.is_contour_ccw(iInnerContour);
|
// const bool ccw = poly_with_offset.is_contour_ccw(iInnerContour);
|
||||||
myassert(itsct.type == itsct2.type);
|
assert(itsct.type == itsct2.type);
|
||||||
myassert(itsct.iContour == itsct2.iContour);
|
assert(itsct.iContour == itsct2.iContour);
|
||||||
myassert(itsct.is_inner());
|
assert(itsct.is_inner());
|
||||||
const bool forward = itsct.is_low() == dir_is_next;
|
const bool forward = itsct.is_low() == dir_is_next;
|
||||||
|
|
||||||
Point p1(il.pos, itsct.pos());
|
Point p1(il.pos, itsct.pos());
|
||||||
|
@ -605,9 +601,9 @@ static inline void emit_perimeter_prev_next_segment(
|
||||||
size_t iVerticalLineOther = iVerticalLine;
|
size_t iVerticalLineOther = iVerticalLine;
|
||||||
if (dir_is_next) {
|
if (dir_is_next) {
|
||||||
++ iVerticalLineOther;
|
++ iVerticalLineOther;
|
||||||
myassert(iVerticalLineOther < segs.size());
|
assert(iVerticalLineOther < segs.size());
|
||||||
} else {
|
} else {
|
||||||
myassert(iVerticalLineOther > 0);
|
assert(iVerticalLineOther > 0);
|
||||||
-- iVerticalLineOther;
|
-- iVerticalLineOther;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -617,9 +613,9 @@ static inline void emit_perimeter_prev_next_segment(
|
||||||
const SegmentIntersection &itsct2 = il2.intersections[iIntersection2];
|
const SegmentIntersection &itsct2 = il2.intersections[iIntersection2];
|
||||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||||
// const bool ccw = poly_with_offset.is_contour_ccw(iInnerContour);
|
// const bool ccw = poly_with_offset.is_contour_ccw(iInnerContour);
|
||||||
myassert(itsct.type == itsct2.type);
|
assert(itsct.type == itsct2.type);
|
||||||
myassert(itsct.iContour == itsct2.iContour);
|
assert(itsct.iContour == itsct2.iContour);
|
||||||
myassert(itsct.is_inner());
|
assert(itsct.is_inner());
|
||||||
const bool forward = itsct.is_low() == dir_is_next;
|
const bool forward = itsct.is_low() == dir_is_next;
|
||||||
// Do not append the first point.
|
// Do not append the first point.
|
||||||
// out.points.push_back(Point(il.pos, itsct.pos));
|
// out.points.push_back(Point(il.pos, itsct.pos));
|
||||||
|
@ -644,11 +640,11 @@ static inline coordf_t measure_perimeter_segment_on_vertical_line_length(
|
||||||
const SegmentIntersection &itsct = il.intersections[iIntersection];
|
const SegmentIntersection &itsct = il.intersections[iIntersection];
|
||||||
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
||||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||||
myassert(itsct.is_inner());
|
assert(itsct.is_inner());
|
||||||
myassert(itsct2.is_inner());
|
assert(itsct2.is_inner());
|
||||||
myassert(itsct.type != itsct2.type);
|
assert(itsct.type != itsct2.type);
|
||||||
myassert(itsct.iContour == iInnerContour);
|
assert(itsct.iContour == iInnerContour);
|
||||||
myassert(itsct.iContour == itsct2.iContour);
|
assert(itsct.iContour == itsct2.iContour);
|
||||||
Point p1(il.pos, itsct.pos());
|
Point p1(il.pos, itsct.pos());
|
||||||
Point p2(il.pos, itsct2.pos());
|
Point p2(il.pos, itsct2.pos());
|
||||||
return forward ?
|
return forward ?
|
||||||
|
@ -673,11 +669,11 @@ static inline void emit_perimeter_segment_on_vertical_line(
|
||||||
const SegmentIntersection &itsct = il.intersections[iIntersection];
|
const SegmentIntersection &itsct = il.intersections[iIntersection];
|
||||||
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
||||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||||
myassert(itsct.is_inner());
|
assert(itsct.is_inner());
|
||||||
myassert(itsct2.is_inner());
|
assert(itsct2.is_inner());
|
||||||
myassert(itsct.type != itsct2.type);
|
assert(itsct.type != itsct2.type);
|
||||||
myassert(itsct.iContour == iInnerContour);
|
assert(itsct.iContour == iInnerContour);
|
||||||
myassert(itsct.iContour == itsct2.iContour);
|
assert(itsct.iContour == itsct2.iContour);
|
||||||
// Do not append the first point.
|
// Do not append the first point.
|
||||||
// out.points.push_back(Point(il.pos, itsct.pos));
|
// out.points.push_back(Point(il.pos, itsct.pos));
|
||||||
if (forward)
|
if (forward)
|
||||||
|
@ -700,10 +696,10 @@ static inline float measure_outer_contour_slab(
|
||||||
const SegmentIntersection &itsct = il.intersections[i_vline];
|
const SegmentIntersection &itsct = il.intersections[i_vline];
|
||||||
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
||||||
const Polygon &poly = poly_with_offset.contour((itsct.iContour);
|
const Polygon &poly = poly_with_offset.contour((itsct.iContour);
|
||||||
myassert(itsct.is_outer());
|
assert(itsct.is_outer());
|
||||||
myassert(itsct2.is_outer());
|
assert(itsct2.is_outer());
|
||||||
myassert(itsct.type != itsct2.type);
|
assert(itsct.type != itsct2.type);
|
||||||
myassert(itsct.iContour == itsct2.iContour);
|
assert(itsct.iContour == itsct2.iContour);
|
||||||
if (! itsct.is_outer() || ! itsct2.is_outer() || itsct.type == itsct2.type || itsct.iContour != itsct2.iContour)
|
if (! itsct.is_outer() || ! itsct2.is_outer() || itsct.type == itsct2.type || itsct.iContour != itsct2.iContour)
|
||||||
// Error, return zero area.
|
// Error, return zero area.
|
||||||
return 0.f;
|
return 0.f;
|
||||||
|
@ -770,13 +766,13 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
||||||
// Shrink the input polygon a bit first to not push the infill lines out of the perimeters.
|
// Shrink the input polygon a bit first to not push the infill lines out of the perimeters.
|
||||||
// const float INFILL_OVERLAP_OVER_SPACING = 0.3f;
|
// const float INFILL_OVERLAP_OVER_SPACING = 0.3f;
|
||||||
const float INFILL_OVERLAP_OVER_SPACING = 0.45f;
|
const float INFILL_OVERLAP_OVER_SPACING = 0.45f;
|
||||||
myassert(INFILL_OVERLAP_OVER_SPACING > 0 && INFILL_OVERLAP_OVER_SPACING < 0.5f);
|
assert(INFILL_OVERLAP_OVER_SPACING > 0 && INFILL_OVERLAP_OVER_SPACING < 0.5f);
|
||||||
|
|
||||||
// Rotate polygons so that we can work with vertical lines here
|
// Rotate polygons so that we can work with vertical lines here
|
||||||
std::pair<float, Point> rotate_vector = this->_infill_direction(surface);
|
std::pair<float, Point> rotate_vector = this->_infill_direction(surface);
|
||||||
rotate_vector.first += angleBase;
|
rotate_vector.first += angleBase;
|
||||||
|
|
||||||
myassert(params.density > 0.0001f && params.density <= 1.f);
|
assert(params.density > 0.0001f && params.density <= 1.f);
|
||||||
coord_t line_spacing = coord_t(scale_(this->spacing) / params.density);
|
coord_t line_spacing = coord_t(scale_(this->spacing) / params.density);
|
||||||
|
|
||||||
// On the polygons of poly_with_offset, the infill lines will be connected.
|
// On the polygons of poly_with_offset, the infill lines will be connected.
|
||||||
|
@ -862,16 +858,16 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
||||||
if (il > ir)
|
if (il > ir)
|
||||||
// No vertical line intersects this segment.
|
// No vertical line intersects this segment.
|
||||||
continue;
|
continue;
|
||||||
myassert(il >= 0 && il < segs.size());
|
assert(il >= 0 && il < segs.size());
|
||||||
myassert(ir >= 0 && ir < segs.size());
|
assert(ir >= 0 && ir < segs.size());
|
||||||
for (int i = il; i <= ir; ++ i) {
|
for (int i = il; i <= ir; ++ i) {
|
||||||
coord_t this_x = segs[i].pos;
|
coord_t this_x = segs[i].pos;
|
||||||
assert(this_x == i * line_spacing + x0);
|
assert(this_x == i * line_spacing + x0);
|
||||||
SegmentIntersection is;
|
SegmentIntersection is;
|
||||||
is.iContour = iContour;
|
is.iContour = iContour;
|
||||||
is.iSegment = iSegment;
|
is.iSegment = iSegment;
|
||||||
myassert(l <= this_x);
|
assert(l <= this_x);
|
||||||
myassert(r >= this_x);
|
assert(r >= this_x);
|
||||||
// Calculate the intersection position in y axis. x is known.
|
// Calculate the intersection position in y axis. x is known.
|
||||||
if (p1.x == this_x) {
|
if (p1.x == this_x) {
|
||||||
if (p2.x == this_x) {
|
if (p2.x == this_x) {
|
||||||
|
@ -892,14 +888,14 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
||||||
is.pos_p = p1.x - this_x;
|
is.pos_p = p1.x - this_x;
|
||||||
is.pos_q = p1.x - p2.x;
|
is.pos_q = p1.x - p2.x;
|
||||||
}
|
}
|
||||||
myassert(is.pos_p >= 0 && is.pos_p <= is.pos_q);
|
assert(is.pos_p >= 0 && is.pos_p <= is.pos_q);
|
||||||
// Make an intersection point from the 't'.
|
// Make an intersection point from the 't'.
|
||||||
is.pos_p *= int64_t(p2.y - p1.y);
|
is.pos_p *= int64_t(p2.y - p1.y);
|
||||||
is.pos_p += p1.y * int64_t(is.pos_q);
|
is.pos_p += p1.y * int64_t(is.pos_q);
|
||||||
}
|
}
|
||||||
// +-1 to take rounding into account.
|
// +-1 to take rounding into account.
|
||||||
myassert(is.pos() + 1 >= std::min(p1.y, p2.y));
|
assert(is.pos() + 1 >= std::min(p1.y, p2.y));
|
||||||
myassert(is.pos() <= std::max(p1.y, p2.y) + 1);
|
assert(is.pos() <= std::max(p1.y, p2.y) + 1);
|
||||||
segs[i].intersections.push_back(is);
|
segs[i].intersections.push_back(is);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -936,7 +932,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
||||||
// Verify that the segments of sil.intersections[i] and sil.intersections[j-1] are adjoint.
|
// Verify that the segments of sil.intersections[i] and sil.intersections[j-1] are adjoint.
|
||||||
size_t iSegment2 = sil.intersections[j-1].iSegment;
|
size_t iSegment2 = sil.intersections[j-1].iSegment;
|
||||||
size_t iPrev2 = ((iSegment2 == 0) ? contour.size() : iSegment2) - 1;
|
size_t iPrev2 = ((iSegment2 == 0) ? contour.size() : iSegment2) - 1;
|
||||||
myassert(iSegment == iPrev2 || iSegment2 == iPrev);
|
assert(iSegment == iPrev2 || iSegment2 == iPrev);
|
||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
if (sil.intersections[i].type == sil.intersections[j-1].type) {
|
if (sil.intersections[i].type == sil.intersections[j-1].type) {
|
||||||
// Two successive segments of the same direction (both to the right or both to the left)
|
// Two successive segments of the same direction (both to the right or both to the left)
|
||||||
|
@ -1058,14 +1054,14 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
||||||
for (size_t i_vline2 = 0; i_vline2 < segs.size(); ++ i_vline2) {
|
for (size_t i_vline2 = 0; i_vline2 < segs.size(); ++ i_vline2) {
|
||||||
const SegmentedIntersectionLine &seg = segs[i_vline2];
|
const SegmentedIntersectionLine &seg = segs[i_vline2];
|
||||||
if (! seg.intersections.empty()) {
|
if (! seg.intersections.empty()) {
|
||||||
myassert(seg.intersections.size() > 1);
|
assert(seg.intersections.size() > 1);
|
||||||
// Even number of intersections with the loops.
|
// Even number of intersections with the loops.
|
||||||
myassert((seg.intersections.size() & 1) == 0);
|
assert((seg.intersections.size() & 1) == 0);
|
||||||
myassert(seg.intersections.front().type == SegmentIntersection::OUTER_LOW);
|
assert(seg.intersections.front().type == SegmentIntersection::OUTER_LOW);
|
||||||
for (size_t i = 0; i < seg.intersections.size(); ++ i) {
|
for (size_t i = 0; i < seg.intersections.size(); ++ i) {
|
||||||
const SegmentIntersection &intrsctn = seg.intersections[i];
|
const SegmentIntersection &intrsctn = seg.intersections[i];
|
||||||
if (intrsctn.is_outer()) {
|
if (intrsctn.is_outer()) {
|
||||||
myassert(intrsctn.is_low() || i > 0);
|
assert(intrsctn.is_low() || i > 0);
|
||||||
bool consumed = intrsctn.is_low() ?
|
bool consumed = intrsctn.is_low() ?
|
||||||
intrsctn.consumed_vertical_up :
|
intrsctn.consumed_vertical_up :
|
||||||
seg.intersections[i-1].consumed_vertical_up;
|
seg.intersections[i-1].consumed_vertical_up;
|
||||||
|
@ -1104,11 +1100,11 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
||||||
bool going_up = intrsctn->is_low();
|
bool going_up = intrsctn->is_low();
|
||||||
bool try_connect = false;
|
bool try_connect = false;
|
||||||
if (going_up) {
|
if (going_up) {
|
||||||
myassert(! intrsctn->consumed_vertical_up);
|
assert(! intrsctn->consumed_vertical_up);
|
||||||
myassert(i_intersection + 1 < seg.intersections.size());
|
assert(i_intersection + 1 < seg.intersections.size());
|
||||||
// Step back to the beginning of the vertical segment to mark it as consumed.
|
// Step back to the beginning of the vertical segment to mark it as consumed.
|
||||||
if (intrsctn->is_inner()) {
|
if (intrsctn->is_inner()) {
|
||||||
myassert(i_intersection > 0);
|
assert(i_intersection > 0);
|
||||||
-- intrsctn;
|
-- intrsctn;
|
||||||
-- i_intersection;
|
-- i_intersection;
|
||||||
}
|
}
|
||||||
|
@ -1117,25 +1113,25 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
||||||
intrsctn->consumed_vertical_up = true;
|
intrsctn->consumed_vertical_up = true;
|
||||||
++ intrsctn;
|
++ intrsctn;
|
||||||
++ i_intersection;
|
++ i_intersection;
|
||||||
myassert(i_intersection < seg.intersections.size());
|
assert(i_intersection < seg.intersections.size());
|
||||||
} while (intrsctn->type != SegmentIntersection::OUTER_HIGH);
|
} while (intrsctn->type != SegmentIntersection::OUTER_HIGH);
|
||||||
if ((intrsctn - 1)->is_inner()) {
|
if ((intrsctn - 1)->is_inner()) {
|
||||||
// Step back.
|
// Step back.
|
||||||
-- intrsctn;
|
-- intrsctn;
|
||||||
-- i_intersection;
|
-- i_intersection;
|
||||||
myassert(intrsctn->type == SegmentIntersection::INNER_HIGH);
|
assert(intrsctn->type == SegmentIntersection::INNER_HIGH);
|
||||||
try_connect = true;
|
try_connect = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Going down.
|
// Going down.
|
||||||
myassert(intrsctn->is_high());
|
assert(intrsctn->is_high());
|
||||||
myassert(i_intersection > 0);
|
assert(i_intersection > 0);
|
||||||
myassert(! (intrsctn - 1)->consumed_vertical_up);
|
assert(! (intrsctn - 1)->consumed_vertical_up);
|
||||||
// Consume the complete vertical segment up to the outer contour.
|
// Consume the complete vertical segment up to the outer contour.
|
||||||
if (intrsctn->is_inner())
|
if (intrsctn->is_inner())
|
||||||
intrsctn->consumed_vertical_up = true;
|
intrsctn->consumed_vertical_up = true;
|
||||||
do {
|
do {
|
||||||
myassert(i_intersection > 0);
|
assert(i_intersection > 0);
|
||||||
-- intrsctn;
|
-- intrsctn;
|
||||||
-- i_intersection;
|
-- i_intersection;
|
||||||
intrsctn->consumed_vertical_up = true;
|
intrsctn->consumed_vertical_up = true;
|
||||||
|
@ -1144,7 +1140,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
||||||
// Step back.
|
// Step back.
|
||||||
++ intrsctn;
|
++ intrsctn;
|
||||||
++ i_intersection;
|
++ i_intersection;
|
||||||
myassert(intrsctn->type == SegmentIntersection::INNER_LOW);
|
assert(intrsctn->type == SegmentIntersection::INNER_LOW);
|
||||||
try_connect = true;
|
try_connect = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1239,7 +1235,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
||||||
bool take_next = (intrsctn_type_prev == INTERSECTION_TYPE_OTHER_VLINE_OK && intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK) ?
|
bool take_next = (intrsctn_type_prev == INTERSECTION_TYPE_OTHER_VLINE_OK && intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK) ?
|
||||||
(distNext < distPrev) :
|
(distNext < distPrev) :
|
||||||
intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK;
|
intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK;
|
||||||
myassert(intrsctn->is_inner());
|
assert(intrsctn->is_inner());
|
||||||
bool skip = params.dont_connect || (link_max_length > 0 && (take_next ? distNext : distPrev) > link_max_length);
|
bool skip = params.dont_connect || (link_max_length > 0 && (take_next ? distNext : distPrev) > link_max_length);
|
||||||
if (skip) {
|
if (skip) {
|
||||||
// Just skip the connecting contour and start a new path.
|
// Just skip the connecting contour and start a new path.
|
||||||
|
@ -1350,13 +1346,13 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
||||||
|
|
||||||
// Finish the current vertical line,
|
// Finish the current vertical line,
|
||||||
// reset the current vertical line to pick a new starting point in the next round.
|
// reset the current vertical line to pick a new starting point in the next round.
|
||||||
myassert(intrsctn->is_outer());
|
assert(intrsctn->is_outer());
|
||||||
myassert(intrsctn->is_high() == going_up);
|
assert(intrsctn->is_high() == going_up);
|
||||||
pointLast = Point(seg.pos, intrsctn->pos());
|
pointLast = Point(seg.pos, intrsctn->pos());
|
||||||
polyline_current->points.push_back(pointLast);
|
polyline_current->points.push_back(pointLast);
|
||||||
// Handle duplicate points and zero length segments.
|
// Handle duplicate points and zero length segments.
|
||||||
polyline_current->remove_duplicate_points();
|
polyline_current->remove_duplicate_points();
|
||||||
myassert(! polyline_current->has_duplicate_points());
|
assert(! polyline_current->has_duplicate_points());
|
||||||
// Handle nearly zero length edges.
|
// Handle nearly zero length edges.
|
||||||
if (polyline_current->points.size() <= 1 ||
|
if (polyline_current->points.size() <= 1 ||
|
||||||
(polyline_current->points.size() == 2 &&
|
(polyline_current->points.size() == 2 &&
|
||||||
|
@ -1388,17 +1384,17 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
||||||
for (Polylines::iterator it = polylines_out.begin() + n_polylines_out_initial; it != polylines_out.end(); ++ it) {
|
for (Polylines::iterator it = polylines_out.begin() + n_polylines_out_initial; it != polylines_out.end(); ++ it) {
|
||||||
// No need to translate, the absolute position is irrelevant.
|
// No need to translate, the absolute position is irrelevant.
|
||||||
// it->translate(- rotate_vector.second.x, - rotate_vector.second.y);
|
// it->translate(- rotate_vector.second.x, - rotate_vector.second.y);
|
||||||
myassert(! it->has_duplicate_points());
|
assert(! it->has_duplicate_points());
|
||||||
it->rotate(rotate_vector.first);
|
it->rotate(rotate_vector.first);
|
||||||
//FIXME rather simplify the paths to avoid very short edges?
|
//FIXME rather simplify the paths to avoid very short edges?
|
||||||
//myassert(! it->has_duplicate_points());
|
//assert(! it->has_duplicate_points());
|
||||||
it->remove_duplicate_points();
|
it->remove_duplicate_points();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
// Verify, that there are no duplicate points in the sequence.
|
// Verify, that there are no duplicate points in the sequence.
|
||||||
for (Polyline &polyline : polylines_out)
|
for (Polyline &polyline : polylines_out)
|
||||||
myassert(! polyline.has_duplicate_points());
|
assert(! polyline.has_duplicate_points());
|
||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -15,23 +15,18 @@
|
||||||
|
|
||||||
#include "FillRectilinear3.hpp"
|
#include "FillRectilinear3.hpp"
|
||||||
|
|
||||||
// #define SLIC3R_DEBUG
|
#define SLIC3R_DEBUG
|
||||||
|
|
||||||
// Make assert active if SLIC3R_DEBUG
|
// Make assert active if SLIC3R_DEBUG
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
|
#define DEBUG
|
||||||
|
#define _DEBUG
|
||||||
#include "SVG.hpp"
|
#include "SVG.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
// We want our version of assert.
|
|
||||||
#include "../libslic3r.h"
|
|
||||||
|
|
||||||
#ifndef myassert
|
|
||||||
#define myassert assert
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
namespace FillRectilinear3_Internal {
|
namespace FillRectilinear3_Internal {
|
||||||
|
@ -55,9 +50,9 @@ public:
|
||||||
// for the infill pattern, don't cut the corners.
|
// for the infill pattern, don't cut the corners.
|
||||||
// default miterLimt = 3
|
// default miterLimt = 3
|
||||||
//double mitterLimit = 10.;
|
//double mitterLimit = 10.;
|
||||||
myassert(aoffset1 < 0);
|
assert(aoffset1 < 0);
|
||||||
myassert(aoffset2 < 0);
|
assert(aoffset2 < 0);
|
||||||
myassert(aoffset2 < aoffset1);
|
assert(aoffset2 < aoffset1);
|
||||||
// bool sticks_removed = remove_sticks(polygons_src);
|
// bool sticks_removed = remove_sticks(polygons_src);
|
||||||
// if (sticks_removed) printf("Sticks removed!\n");
|
// if (sticks_removed) printf("Sticks removed!\n");
|
||||||
polygons_outer = offset(polygons_src, aoffset1,
|
polygons_outer = offset(polygons_src, aoffset1,
|
||||||
|
@ -78,7 +73,7 @@ public:
|
||||||
polygons_ccw.assign(n_contours, false);
|
polygons_ccw.assign(n_contours, false);
|
||||||
for (size_t i = 0; i < n_contours; ++ i) {
|
for (size_t i = 0; i < n_contours; ++ i) {
|
||||||
contour(i).remove_duplicate_points();
|
contour(i).remove_duplicate_points();
|
||||||
myassert(! contour(i).has_duplicate_points());
|
assert(! contour(i).has_duplicate_points());
|
||||||
polygons_ccw[i] = Slic3r::Geometry::is_ccw(contour(i));
|
polygons_ccw[i] = Slic3r::Geometry::is_ccw(contour(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +176,8 @@ public:
|
||||||
int ordering_along_line(const SegmentIntersection &other) const;
|
int ordering_along_line(const SegmentIntersection &other) const;
|
||||||
|
|
||||||
// Compare two y intersection points given by rational numbers.
|
// Compare two y intersection points given by rational numbers.
|
||||||
bool operator< (const SegmentIntersection &other) const { return this->ordering_along_line(other) == -1; }
|
bool operator< (const SegmentIntersection &other) const;
|
||||||
|
// { return this->ordering_along_line(other) == -1; }
|
||||||
bool operator==(const SegmentIntersection &other) const { return this->ordering_along_line(other) == 0; }
|
bool operator==(const SegmentIntersection &other) const { return this->ordering_along_line(other) == 0; }
|
||||||
|
|
||||||
//FIXME legacy code, suporting the old graph traversal algorithm. Please remove.
|
//FIXME legacy code, suporting the old graph traversal algorithm. Please remove.
|
||||||
|
@ -200,7 +196,7 @@ public:
|
||||||
// Index of this vertical intersection line.
|
// Index of this vertical intersection line.
|
||||||
size_t idx;
|
size_t idx;
|
||||||
// Position of the line along the X axis of the oriented bounding box.
|
// Position of the line along the X axis of the oriented bounding box.
|
||||||
coord_t x;
|
// coord_t x;
|
||||||
// Position of this vertical intersection line, rotated to the world coordinate system.
|
// Position of this vertical intersection line, rotated to the world coordinate system.
|
||||||
Point pos;
|
Point pos;
|
||||||
// Direction of this vertical intersection line, rotated to the world coordinate system. The direction is not normalized to maintain a sufficient accuracy!
|
// Direction of this vertical intersection line, rotated to the world coordinate system. The direction is not normalized to maintain a sufficient accuracy!
|
||||||
|
@ -218,8 +214,8 @@ Point SegmentIntersection::pos() const
|
||||||
// Get the two rays to be intersected.
|
// Get the two rays to be intersected.
|
||||||
const Polygon &poly = this->expoly_with_offset->contour(this->iContour);
|
const Polygon &poly = this->expoly_with_offset->contour(this->iContour);
|
||||||
// 30 bits + 1 signum bit.
|
// 30 bits + 1 signum bit.
|
||||||
const Point &seg_start = poly.points[this->iSegment];
|
const Point &seg_start = poly.points[(this->iSegment == 0) ? poly.points.size() - 1 : this->iSegment - 1];
|
||||||
const Point &seg_end = poly.points[(this->iSegment + 1) % poly.points.size()];
|
const Point &seg_end = poly.points[this->iSegment];
|
||||||
// Point, vector of the segment.
|
// Point, vector of the segment.
|
||||||
const Pointf p1 = convert_to<Pointf>(seg_start);
|
const Pointf p1 = convert_to<Pointf>(seg_start);
|
||||||
const Pointf v1 = convert_to<Pointf>(seg_end - seg_start);
|
const Pointf v1 = convert_to<Pointf>(seg_end - seg_start);
|
||||||
|
@ -266,28 +262,35 @@ int SegmentIntersection::ordering_along_line(const SegmentIntersection &other) c
|
||||||
// Segment of this
|
// Segment of this
|
||||||
const Polygon &poly_a = this->expoly_with_offset->contour(this->iContour);
|
const Polygon &poly_a = this->expoly_with_offset->contour(this->iContour);
|
||||||
// 30 bits + 1 signum bit.
|
// 30 bits + 1 signum bit.
|
||||||
const Point &seg_start_a = poly_a.points[this->iSegment];
|
const Point &seg_start_a = poly_a.points[(this->iSegment == 0) ? poly_a.points.size() - 1 : this->iSegment - 1];
|
||||||
const Point &seg_end_a = poly_a.points[(this->iSegment + 1) % poly_a.points.size()];
|
const Point &seg_end_a = poly_a.points[this->iSegment];
|
||||||
const Point vec_a = seg_end_a - seg_start_a;
|
|
||||||
|
|
||||||
// Segment of other
|
// Segment of other
|
||||||
const Polygon &poly_b = this->expoly_with_offset->contour(other.iContour);
|
const Polygon &poly_b = this->expoly_with_offset->contour(other.iContour);
|
||||||
// 30 bits + 1 signum bit.
|
// 30 bits + 1 signum bit.
|
||||||
const Point &seg_start_b = poly_b.points[other.iSegment];
|
const Point &seg_start_b = poly_b.points[(other.iSegment == 0) ? poly_b.points.size() - 1 : other.iSegment - 1];
|
||||||
const Point &seg_end_b = poly_b.points[(other.iSegment + 1) % poly_b.points.size()];
|
const Point &seg_end_b = poly_b.points[other.iSegment];
|
||||||
const Point vec_b = seg_end_b - seg_start_b;
|
|
||||||
|
|
||||||
if (this->iContour == other.iContour) {
|
if (this->iContour == other.iContour) {
|
||||||
if ((this->iSegment + 1) % poly_a.points.size() == other.iSegment) {
|
if ((this->iSegment + 1) % poly_a.points.size() == other.iSegment) {
|
||||||
// other.iSegment succeeds this->iSegment
|
// other.iSegment succeeds this->iSegment
|
||||||
|
assert(seg_end_a == seg_start_b);
|
||||||
|
// Avoid calling the 128bit x 128bit multiplication below if this->line intersects the common point.
|
||||||
|
if (cross(this->line->dir, seg_end_b - this->line->pos) == 0)
|
||||||
|
return 0;
|
||||||
} else if ((other.iSegment + 1) % poly_a.points.size() == this->iSegment) {
|
} else if ((other.iSegment + 1) % poly_a.points.size() == this->iSegment) {
|
||||||
// this->iSegment succeeds other.iSegment
|
// this->iSegment succeeds other.iSegment
|
||||||
|
assert(seg_start_a == seg_end_b);
|
||||||
|
// Avoid calling the 128bit x 128bit multiplication below if this->line intersects the common point.
|
||||||
|
if (cross(this->line->dir, seg_start_a - this->line->pos) == 0)
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
// General case.
|
// General case.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// First test, whether both points of one segment are completely in one half-plane of the other line.
|
// First test, whether both points of one segment are completely in one half-plane of the other line.
|
||||||
|
const Point vec_b = seg_end_b - seg_start_b;
|
||||||
int side_start = signum(cross(vec_b, seg_start_a - seg_start_b));
|
int side_start = signum(cross(vec_b, seg_start_a - seg_start_b));
|
||||||
int side_end = signum(cross(vec_b, seg_end_a - seg_start_b));
|
int side_end = signum(cross(vec_b, seg_end_a - seg_start_b));
|
||||||
int side = side_start * side_end;
|
int side = side_start * side_end;
|
||||||
|
@ -295,31 +298,50 @@ int SegmentIntersection::ordering_along_line(const SegmentIntersection &other) c
|
||||||
// This segment is completely inside one half-plane of the other line, therefore the ordering is trivial.
|
// This segment is completely inside one half-plane of the other line, therefore the ordering is trivial.
|
||||||
return signum(cross(vec_b, this->line->dir)) * side_start;
|
return signum(cross(vec_b, this->line->dir)) * side_start;
|
||||||
|
|
||||||
|
const Point vec_a = seg_end_a - seg_start_a;
|
||||||
int side_start2 = signum(cross(vec_a, seg_start_b - seg_start_a));
|
int side_start2 = signum(cross(vec_a, seg_start_b - seg_start_a));
|
||||||
int side_end2 = signum(cross(vec_a, seg_end_b - seg_start_a));
|
int side_end2 = signum(cross(vec_a, seg_end_b - seg_start_a));
|
||||||
int side2 = side_start2 * side_end2;
|
int side2 = side_start2 * side_end2;
|
||||||
|
//if (side == 0 && side2 == 0)
|
||||||
|
// The segments share one of their end points.
|
||||||
if (side2 > 0)
|
if (side2 > 0)
|
||||||
// This segment is completely inside one half-plane of the other line, therefore the ordering is trivial.
|
// This segment is completely inside one half-plane of the other line, therefore the ordering is trivial.
|
||||||
return signum(cross(vec_a, this->line->dir)) * side_start2;
|
return signum(cross(this->line->dir, vec_a)) * side_start2;
|
||||||
|
|
||||||
if (side == 0 && side2 == 0)
|
|
||||||
// The segments share one of their end points.
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// The two segments intersect and they are not sucessive segments of the same contour.
|
// The two segments intersect and they are not sucessive segments of the same contour.
|
||||||
// Ordering of the points depends on the position of the segment intersection (left / right from this->line),
|
// Ordering of the points depends on the position of the segment intersection (left / right from this->line),
|
||||||
// therefore a simple test over the input segment end points is not sufficient.
|
// therefore a simple test over the input segment end points is not sufficient.
|
||||||
|
|
||||||
// Find the parameters of intersection of the two segmetns with this->line.
|
// Find the parameters of intersection of the two segmetns with this->line.
|
||||||
int64_t denom1 = cross(vec_a, this->line->dir);
|
int64_t denom1 = cross(this->line->dir, vec_a);
|
||||||
int64_t denom2 = cross(vec_b, this->line->dir);
|
int64_t denom2 = cross(this->line->dir, vec_b);
|
||||||
int64_t t1_times_denom1 = int64_t(this->line->dir.x) * int64_t(seg_start_a.y - this->line->pos.y) - int64_t(this->line->dir.y) * int64_t(seg_start_a.x - this->line->pos.x);
|
Point vx_a = seg_start_a - this->line->pos;
|
||||||
int64_t t2_times_denom2 = int64_t(this->line->dir.x) * int64_t(seg_start_b.y - this->line->pos.y) - int64_t(this->line->dir.y) * int64_t(seg_start_b.x - this->line->pos.x);
|
Point vx_b = seg_start_b - this->line->pos;
|
||||||
assert(denom1 != 0);
|
int64_t t1_times_denom1 = int64_t(vx_a.x) * int64_t(vec_a.y) - int64_t(vx_a.y) * int64_t(vec_a.x);
|
||||||
|
int64_t t2_times_denom2 = int64_t(vx_b.x) * int64_t(vec_b.y) - int64_t(vx_b.y) * int64_t(vec_b.x);
|
||||||
|
assert(denom1 != 0);
|
||||||
assert(denom2 != 0);
|
assert(denom2 != 0);
|
||||||
return Int128::compare_rationals_filtered(t1_times_denom1, denom1, t2_times_denom2, denom2);
|
return Int128::compare_rationals_filtered(t1_times_denom1, denom1, t2_times_denom2, denom2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compare two y intersection points given by rational numbers.
|
||||||
|
bool SegmentIntersection::operator<(const SegmentIntersection &other) const
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
Point p1 = this->pos();
|
||||||
|
Point p2 = other.pos();
|
||||||
|
int64_t d = dot(this->line->dir, p2 - p1);
|
||||||
|
#endif /* _DEBUG */
|
||||||
|
int ordering = this->ordering_along_line(other);
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if (ordering == -1)
|
||||||
|
assert(d >= - int64_t(SCALED_EPSILON));
|
||||||
|
else if (ordering == 1)
|
||||||
|
assert(d <= int64_t(SCALED_EPSILON));
|
||||||
|
#endif /* _DEBUG */
|
||||||
|
return ordering == -1;
|
||||||
|
}
|
||||||
|
|
||||||
// When doing a rectilinear / grid / triangle / stars / cubic infill,
|
// When doing a rectilinear / grid / triangle / stars / cubic infill,
|
||||||
// the following class holds the hatching lines of each of the hatching directions.
|
// the following class holds the hatching lines of each of the hatching directions.
|
||||||
class InfillHatchingSingleDirection
|
class InfillHatchingSingleDirection
|
||||||
|
@ -353,12 +375,12 @@ static bool prepare_infill_hatching_segments(
|
||||||
InfillHatchingSingleDirection &out)
|
InfillHatchingSingleDirection &out)
|
||||||
{
|
{
|
||||||
out.angle = rotate_vector.first + fill_dir_params.angle;
|
out.angle = rotate_vector.first + fill_dir_params.angle;
|
||||||
out.direction = Point(1000, 0);
|
out.direction = Point(coord_t(scale_(1000)), coord_t(0));
|
||||||
// Hatch along the Y axis of the rotated coordinate system.
|
// Hatch along the Y axis of the rotated coordinate system.
|
||||||
out.direction.rotate(out.angle + 0.5 * M_PI);
|
out.direction.rotate(out.angle + 0.5 * M_PI);
|
||||||
out.segs.clear();
|
out.segs.clear();
|
||||||
|
|
||||||
myassert(params.density > 0.0001f && params.density <= 1.f);
|
assert(params.density > 0.0001f && params.density <= 1.f);
|
||||||
coord_t line_spacing = coord_t(scale_(fill_dir_params.spacing) / params.density);
|
coord_t line_spacing = coord_t(scale_(fill_dir_params.spacing) / params.density);
|
||||||
|
|
||||||
// Bounding box around the source contour, aligned with out.angle.
|
// Bounding box around the source contour, aligned with out.angle.
|
||||||
|
@ -409,18 +431,18 @@ static bool prepare_infill_hatching_segments(
|
||||||
// For each contour
|
// For each contour
|
||||||
// Allocate storage for the segments.
|
// Allocate storage for the segments.
|
||||||
out.segs.assign(n_vlines, SegmentedIntersectionLine());
|
out.segs.assign(n_vlines, SegmentedIntersectionLine());
|
||||||
|
double cos_a = cos(out.angle);
|
||||||
|
double sin_a = sin(out.angle);
|
||||||
for (size_t i = 0; i < n_vlines; ++ i) {
|
for (size_t i = 0; i < n_vlines; ++ i) {
|
||||||
auto &seg = out.segs[i];
|
auto &seg = out.segs[i];
|
||||||
seg.idx = i;
|
seg.idx = i;
|
||||||
seg.x = x0 + coord_t(i) * line_spacing;
|
// seg.x = x0 + coord_t(i) * line_spacing;
|
||||||
seg.pos = Point(seg.x, bounding_box.min.y);
|
coord_t x = x0 + coord_t(i) * line_spacing;
|
||||||
seg.pos.rotate(out.angle);
|
seg.pos.x = coord_t(floor(cos_a * x - sin_a * bounding_box.min.y + 0.5));
|
||||||
|
seg.pos.y = coord_t(floor(cos_a * bounding_box.min.y + sin_a * x + 0.5));
|
||||||
seg.dir = out.direction;
|
seg.dir = out.direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
|
||||||
double cos_a = cos(- out.angle);
|
|
||||||
double sin_a = sin(- out.angle);
|
|
||||||
for (size_t iContour = 0; iContour < poly_with_offset.n_contours; ++ iContour) {
|
for (size_t iContour = 0; iContour < poly_with_offset.n_contours; ++ iContour) {
|
||||||
const Points &contour = poly_with_offset.contour(iContour).points;
|
const Points &contour = poly_with_offset.contour(iContour).points;
|
||||||
if (contour.size() < 2)
|
if (contour.size() < 2)
|
||||||
|
@ -440,60 +462,58 @@ static bool prepare_infill_hatching_segments(
|
||||||
// Always orient the input segment consistently towards the hatching direction.
|
// Always orient the input segment consistently towards the hatching direction.
|
||||||
std::swap(pl, pr);
|
std::swap(pl, pr);
|
||||||
// Which of the equally spaced vertical lines is intersected by this segment?
|
// Which of the equally spaced vertical lines is intersected by this segment?
|
||||||
coord_t l = (coord_t)floor(cos_a * pl->x - sin_a * pl->y - EPSILON);
|
coord_t l = (coord_t)floor(cos_a * pl->x + sin_a * pl->y - SCALED_EPSILON);
|
||||||
coord_t r = (coord_t)ceil (cos_a * pr->x - sin_a * pr->y + EPSILON);
|
coord_t r = (coord_t)ceil (cos_a * pr->x + sin_a * pr->y + SCALED_EPSILON);
|
||||||
|
assert(l < r - SCALED_EPSILON);
|
||||||
// il, ir are the left / right indices of vertical lines intersecting a segment
|
// il, ir are the left / right indices of vertical lines intersecting a segment
|
||||||
int il = (l - x0) / line_spacing;
|
int il = std::max<int>(0, (l - x0 + line_spacing) / line_spacing);
|
||||||
il = std::max(int(0), il);
|
int ir = std::min<int>(int(out.segs.size()) - 1, (r - x0) / line_spacing);
|
||||||
while (il * line_spacing + x0 < l)
|
|
||||||
++ il;
|
|
||||||
int ir = (r - x0 + line_spacing) / line_spacing;
|
|
||||||
while (ir * line_spacing + x0 > r)
|
|
||||||
-- ir;
|
|
||||||
ir = std::min(int(out.segs.size()) - 1, ir);
|
|
||||||
if (il > ir)
|
|
||||||
// No vertical line intersects this segment.
|
|
||||||
continue;
|
|
||||||
// The previous tests were done with floating point arithmetics over an epsilon-extended interval.
|
// The previous tests were done with floating point arithmetics over an epsilon-extended interval.
|
||||||
// Now do the same tests with exact arithmetics over the exact interval.
|
// Now do the same tests with exact arithmetics over the exact interval.
|
||||||
while (il <= ir && Int128::orient(out.segs[il].pos, out.segs[il].pos + out.direction, *pl) < 0)
|
while (il <= ir && Int128::orient(out.segs[il].pos, out.segs[il].pos + out.direction, *pl) < 0)
|
||||||
++ il;
|
++ il;
|
||||||
while (il <= ir && Int128::orient(out.segs[ir].pos, out.segs[ir].pos + out.direction, *pr) > 0)
|
while (il <= ir && Int128::orient(out.segs[ir].pos, out.segs[ir].pos + out.direction, *pr) > 0)
|
||||||
-- ir;
|
-- ir;
|
||||||
if (il > ir)
|
|
||||||
// No vertical line intersects this segment.
|
|
||||||
continue;
|
|
||||||
// Here it is ensured, that
|
// Here it is ensured, that
|
||||||
// 1) out.seg is not parallel to (pl, pr)
|
// 1) out.seg is not parallel to (pl, pr)
|
||||||
// 2) all lines from il to ir intersect <pl, pr>.
|
// 2) all lines from il to ir intersect <pl, pr>.
|
||||||
myassert(il >= 0 && il < out.segs.size());
|
assert(il >= 0 && ir < int(out.segs.size()));
|
||||||
myassert(ir >= 0 && ir < out.segs.size());
|
|
||||||
for (int i = il; i <= ir; ++ i) {
|
for (int i = il; i <= ir; ++ i) {
|
||||||
myassert(out.segs[i].x == i * line_spacing + x0);
|
// assert(out.segs[i].x == i * line_spacing + x0);
|
||||||
myassert(l <= out.segs[i].x);
|
// assert(l <= out.segs[i].x);
|
||||||
myassert(r >= out.segs[i].x);
|
// assert(r >= out.segs[i].x);
|
||||||
SegmentIntersection is;
|
SegmentIntersection is;
|
||||||
is.line = &out.segs[i];
|
is.line = &out.segs[i];
|
||||||
is.expoly_with_offset = &poly_with_offset;
|
is.expoly_with_offset = &poly_with_offset;
|
||||||
is.iContour = iContour;
|
is.iContour = iContour;
|
||||||
is.iSegment = iSegment;
|
is.iSegment = iSegment;
|
||||||
// Test whether the calculated intersection point falls into the bounding box of the input segment.
|
// Test whether the calculated intersection point falls into the bounding box of the input segment.
|
||||||
// +-1 to take rounding into account.
|
// +-1 to take rounding into account.
|
||||||
myassert(is.pos().x + 1 >= std::min(pl->x, pr->x));
|
assert(Int128::orient(out.segs[i].pos, out.segs[i].pos + out.direction, *pl) >= 0);
|
||||||
myassert(is.pos().y + 1 >= std::min(pl->y, pr->y));
|
assert(Int128::orient(out.segs[i].pos, out.segs[i].pos + out.direction, *pr) <= 0);
|
||||||
myassert(is.pos().x <= std::max(pl->x, pr->x) + 1);
|
assert(is.pos().x + 1 >= std::min(pl->x, pr->x));
|
||||||
myassert(is.pos().y <= std::max(pl->y, pr->y) + 1);
|
assert(is.pos().y + 1 >= std::min(pl->y, pr->y));
|
||||||
|
assert(is.pos().x <= std::max(pl->x, pr->x) + 1);
|
||||||
|
assert(is.pos().y <= std::max(pl->y, pr->y) + 1);
|
||||||
out.segs[i].intersections.push_back(is);
|
out.segs[i].intersections.push_back(is);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Sort the intersections along their segments, specify the intersection types.
|
// Sort the intersections along their segments, specify the intersection types.
|
||||||
for (size_t i_seg = 0; i_seg < out.segs.size(); ++ i_seg) {
|
for (size_t i_seg = 0; i_seg < out.segs.size(); ++ i_seg) {
|
||||||
SegmentedIntersectionLine &sil = out.segs[i_seg];
|
SegmentedIntersectionLine &sil = out.segs[i_seg];
|
||||||
// Sort the intersection points using exact rational arithmetic.
|
// Sort the intersection points using exact rational arithmetic.
|
||||||
std::sort(sil.intersections.begin(), sil.intersections.end());
|
std::sort(sil.intersections.begin(), sil.intersections.end());
|
||||||
|
#ifdef _DEBUG
|
||||||
|
// Verify that the intersections are sorted along the haching direction.
|
||||||
|
for (size_t i = 1; i < sil.intersections.size(); ++ i) {
|
||||||
|
Point p1 = sil.intersections[i - 1].pos();
|
||||||
|
Point p2 = sil.intersections[i].pos();
|
||||||
|
int64_t d = dot(sil.dir, p2 - p1);
|
||||||
|
assert(d >= - int64_t(SCALED_EPSILON));
|
||||||
|
}
|
||||||
|
#endif /* _DEBUG */
|
||||||
// Assign the intersection types, remove duplicate or overlapping intersection points.
|
// Assign the intersection types, remove duplicate or overlapping intersection points.
|
||||||
// When a loop vertex touches a vertical line, intersection point is generated for both segments.
|
// When a loop vertex touches a vertical line, intersection point is generated for both segments.
|
||||||
// If such two segments are oriented equally, then one of them is removed.
|
// If such two segments are oriented equally, then one of them is removed.
|
||||||
|
@ -507,7 +527,7 @@ static bool prepare_infill_hatching_segments(
|
||||||
const Points &contour = poly_with_offset.contour(iContour).points;
|
const Points &contour = poly_with_offset.contour(iContour).points;
|
||||||
size_t iSegment = sil.intersections[i].iSegment;
|
size_t iSegment = sil.intersections[i].iSegment;
|
||||||
size_t iPrev = ((iSegment == 0) ? contour.size() : iSegment) - 1;
|
size_t iPrev = ((iSegment == 0) ? contour.size() : iSegment) - 1;
|
||||||
coord_t dir = contour[iSegment].x - contour[iPrev].x;
|
int dir = Int128::cross(contour[iSegment] - contour[iPrev], sil.dir);
|
||||||
bool low = dir > 0;
|
bool low = dir > 0;
|
||||||
sil.intersections[i].type = poly_with_offset.is_contour_outer(iContour) ?
|
sil.intersections[i].type = poly_with_offset.is_contour_outer(iContour) ?
|
||||||
(low ? SegmentIntersection::OUTER_LOW : SegmentIntersection::OUTER_HIGH) :
|
(low ? SegmentIntersection::OUTER_LOW : SegmentIntersection::OUTER_HIGH) :
|
||||||
|
@ -520,7 +540,7 @@ static bool prepare_infill_hatching_segments(
|
||||||
// Verify that the segments of sil.intersections[i] and sil.intersections[j-1] are adjoint.
|
// Verify that the segments of sil.intersections[i] and sil.intersections[j-1] are adjoint.
|
||||||
size_t iSegment2 = sil.intersections[j-1].iSegment;
|
size_t iSegment2 = sil.intersections[j-1].iSegment;
|
||||||
size_t iPrev2 = ((iSegment2 == 0) ? contour.size() : iSegment2) - 1;
|
size_t iPrev2 = ((iSegment2 == 0) ? contour.size() : iSegment2) - 1;
|
||||||
myassert(iSegment == iPrev2 || iSegment2 == iPrev);
|
assert(iSegment == iPrev2 || iSegment2 == iPrev);
|
||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
if (sil.intersections[i].type == sil.intersections[j-1].type) {
|
if (sil.intersections[i].type == sil.intersections[j-1].type) {
|
||||||
// Two successive segments of the same direction (both to the right or both to the left)
|
// Two successive segments of the same direction (both to the right or both to the left)
|
||||||
|
@ -643,8 +663,8 @@ static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Po
|
||||||
std::swap(pa.x, pb.x);
|
std::swap(pa.x, pb.x);
|
||||||
if (pa.y > pb.y)
|
if (pa.y > pb.y)
|
||||||
std::swap(pa.y, pb.y);
|
std::swap(pa.y, pb.y);
|
||||||
myassert(px.x >= pa.x && px.x <= pb.x);
|
assert(px.x >= pa.x && px.x <= pb.x);
|
||||||
myassert(px.y >= pa.y && px.y <= pb.y);
|
assert(px.y >= pa.y && px.y <= pb.y);
|
||||||
}
|
}
|
||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
const Point *pPrev = &p1;
|
const Point *pPrev = &p1;
|
||||||
|
@ -750,23 +770,23 @@ static inline int intersection_on_prev_next_vertical_line(
|
||||||
if (itsct.iContour == itsct2.iContour && itsct.type == itsct2.type) {
|
if (itsct.iContour == itsct2.iContour && itsct.type == itsct2.type) {
|
||||||
/*
|
/*
|
||||||
if (itsct.is_low()) {
|
if (itsct.is_low()) {
|
||||||
myassert(itsct.type == SegmentIntersection::INNER_LOW);
|
assert(itsct.type == SegmentIntersection::INNER_LOW);
|
||||||
myassert(iIntersection > 0);
|
assert(iIntersection > 0);
|
||||||
myassert(il.intersections[iIntersection-1].type == SegmentIntersection::OUTER_LOW);
|
assert(il.intersections[iIntersection-1].type == SegmentIntersection::OUTER_LOW);
|
||||||
myassert(i > 0);
|
assert(i > 0);
|
||||||
if (il2.intersections[i-1].is_inner())
|
if (il2.intersections[i-1].is_inner())
|
||||||
// Take only the lowest inner intersection point.
|
// Take only the lowest inner intersection point.
|
||||||
continue;
|
continue;
|
||||||
myassert(il2.intersections[i-1].type == SegmentIntersection::OUTER_LOW);
|
assert(il2.intersections[i-1].type == SegmentIntersection::OUTER_LOW);
|
||||||
} else {
|
} else {
|
||||||
myassert(itsct.type == SegmentIntersection::INNER_HIGH);
|
assert(itsct.type == SegmentIntersection::INNER_HIGH);
|
||||||
myassert(iIntersection+1 < il.intersections.size());
|
assert(iIntersection+1 < il.intersections.size());
|
||||||
myassert(il.intersections[iIntersection+1].type == SegmentIntersection::OUTER_HIGH);
|
assert(il.intersections[iIntersection+1].type == SegmentIntersection::OUTER_HIGH);
|
||||||
myassert(i+1 < il2.intersections.size());
|
assert(i+1 < il2.intersections.size());
|
||||||
if (il2.intersections[i+1].is_inner())
|
if (il2.intersections[i+1].is_inner())
|
||||||
// Take only the highest inner intersection point.
|
// Take only the highest inner intersection point.
|
||||||
continue;
|
continue;
|
||||||
myassert(il2.intersections[i+1].type == SegmentIntersection::OUTER_HIGH);
|
assert(il2.intersections[i+1].type == SegmentIntersection::OUTER_HIGH);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
// The intersection points lie on the same contour and have the same orientation.
|
// The intersection points lie on the same contour and have the same orientation.
|
||||||
|
@ -831,21 +851,21 @@ static inline IntersectionTypeOtherVLine intersection_type_on_prev_next_vertical
|
||||||
// iVertical line multiple times before reaching iIntersectionOther.
|
// iVertical line multiple times before reaching iIntersectionOther.
|
||||||
if (iIntersectionOther == -1)
|
if (iIntersectionOther == -1)
|
||||||
return INTERSECTION_TYPE_OTHER_VLINE_UNDEFINED;
|
return INTERSECTION_TYPE_OTHER_VLINE_UNDEFINED;
|
||||||
myassert(dir_is_next ? (iVerticalLine + 1 < segs.size()) : (iVerticalLine > 0));
|
assert(dir_is_next ? (iVerticalLine + 1 < segs.size()) : (iVerticalLine > 0));
|
||||||
const SegmentedIntersectionLine &il_this = segs[iVerticalLine];
|
const SegmentedIntersectionLine &il_this = segs[iVerticalLine];
|
||||||
const SegmentIntersection &itsct_this = il_this.intersections[iIntersection];
|
const SegmentIntersection &itsct_this = il_this.intersections[iIntersection];
|
||||||
const SegmentedIntersectionLine &il_other = segs[dir_is_next ? (iVerticalLine+1) : (iVerticalLine-1)];
|
const SegmentedIntersectionLine &il_other = segs[dir_is_next ? (iVerticalLine+1) : (iVerticalLine-1)];
|
||||||
const SegmentIntersection &itsct_other = il_other.intersections[iIntersectionOther];
|
const SegmentIntersection &itsct_other = il_other.intersections[iIntersectionOther];
|
||||||
myassert(itsct_other.is_inner());
|
assert(itsct_other.is_inner());
|
||||||
myassert(iIntersectionOther > 0);
|
assert(iIntersectionOther > 0);
|
||||||
myassert(iIntersectionOther + 1 < il_other.intersections.size());
|
assert(iIntersectionOther + 1 < il_other.intersections.size());
|
||||||
// Is iIntersectionOther at the boundary of a vertical segment?
|
// Is iIntersectionOther at the boundary of a vertical segment?
|
||||||
const SegmentIntersection &itsct_other2 = il_other.intersections[itsct_other.is_low() ? iIntersectionOther - 1 : iIntersectionOther + 1];
|
const SegmentIntersection &itsct_other2 = il_other.intersections[itsct_other.is_low() ? iIntersectionOther - 1 : iIntersectionOther + 1];
|
||||||
if (itsct_other2.is_inner())
|
if (itsct_other2.is_inner())
|
||||||
// Cannot follow a perimeter segment into the middle of another vertical segment.
|
// Cannot follow a perimeter segment into the middle of another vertical segment.
|
||||||
// Only perimeter segments connecting to the end of a vertical segment are followed.
|
// Only perimeter segments connecting to the end of a vertical segment are followed.
|
||||||
return INTERSECTION_TYPE_OTHER_VLINE_INNER;
|
return INTERSECTION_TYPE_OTHER_VLINE_INNER;
|
||||||
myassert(itsct_other.is_low() == itsct_other2.is_low());
|
assert(itsct_other.is_low() == itsct_other2.is_low());
|
||||||
if (dir_is_next ? itsct_this.consumed_perimeter_right : itsct_other.consumed_perimeter_right)
|
if (dir_is_next ? itsct_this.consumed_perimeter_right : itsct_other.consumed_perimeter_right)
|
||||||
// This perimeter segment was already consumed.
|
// This perimeter segment was already consumed.
|
||||||
return INTERSECTION_TYPE_OTHER_VLINE_CONSUMED;
|
return INTERSECTION_TYPE_OTHER_VLINE_CONSUMED;
|
||||||
|
@ -899,9 +919,9 @@ static inline coordf_t measure_perimeter_prev_next_segment_length(
|
||||||
const SegmentIntersection &itsct2 = il2.intersections[iIntersection2];
|
const SegmentIntersection &itsct2 = il2.intersections[iIntersection2];
|
||||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||||
// const bool ccw = poly_with_offset.is_contour_ccw(iInnerContour);
|
// const bool ccw = poly_with_offset.is_contour_ccw(iInnerContour);
|
||||||
myassert(itsct.type == itsct2.type);
|
assert(itsct.type == itsct2.type);
|
||||||
myassert(itsct.iContour == itsct2.iContour);
|
assert(itsct.iContour == itsct2.iContour);
|
||||||
myassert(itsct.is_inner());
|
assert(itsct.is_inner());
|
||||||
const bool forward = itsct.is_low() == dir_is_next;
|
const bool forward = itsct.is_low() == dir_is_next;
|
||||||
|
|
||||||
Point p1 = itsct.pos();
|
Point p1 = itsct.pos();
|
||||||
|
@ -949,9 +969,9 @@ static inline void emit_perimeter_prev_next_segment(
|
||||||
size_t iVerticalLineOther = iVerticalLine;
|
size_t iVerticalLineOther = iVerticalLine;
|
||||||
if (dir_is_next) {
|
if (dir_is_next) {
|
||||||
++ iVerticalLineOther;
|
++ iVerticalLineOther;
|
||||||
myassert(iVerticalLineOther < segs.size());
|
assert(iVerticalLineOther < segs.size());
|
||||||
} else {
|
} else {
|
||||||
myassert(iVerticalLineOther > 0);
|
assert(iVerticalLineOther > 0);
|
||||||
-- iVerticalLineOther;
|
-- iVerticalLineOther;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -961,9 +981,9 @@ static inline void emit_perimeter_prev_next_segment(
|
||||||
const SegmentIntersection &itsct2 = il2.intersections[iIntersection2];
|
const SegmentIntersection &itsct2 = il2.intersections[iIntersection2];
|
||||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||||
// const bool ccw = poly_with_offset.is_contour_ccw(iInnerContour);
|
// const bool ccw = poly_with_offset.is_contour_ccw(iInnerContour);
|
||||||
myassert(itsct.type == itsct2.type);
|
assert(itsct.type == itsct2.type);
|
||||||
myassert(itsct.iContour == itsct2.iContour);
|
assert(itsct.iContour == itsct2.iContour);
|
||||||
myassert(itsct.is_inner());
|
assert(itsct.is_inner());
|
||||||
const bool forward = itsct.is_low() == dir_is_next;
|
const bool forward = itsct.is_low() == dir_is_next;
|
||||||
// Do not append the first point.
|
// Do not append the first point.
|
||||||
// out.points.push_back(Point(il.pos, itsct.pos));
|
// out.points.push_back(Point(il.pos, itsct.pos));
|
||||||
|
@ -988,11 +1008,11 @@ static inline coordf_t measure_perimeter_segment_on_vertical_line_length(
|
||||||
const SegmentIntersection &itsct = il.intersections[iIntersection];
|
const SegmentIntersection &itsct = il.intersections[iIntersection];
|
||||||
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
||||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||||
myassert(itsct.is_inner());
|
assert(itsct.is_inner());
|
||||||
myassert(itsct2.is_inner());
|
assert(itsct2.is_inner());
|
||||||
myassert(itsct.type != itsct2.type);
|
assert(itsct.type != itsct2.type);
|
||||||
myassert(itsct.iContour == iInnerContour);
|
assert(itsct.iContour == iInnerContour);
|
||||||
myassert(itsct.iContour == itsct2.iContour);
|
assert(itsct.iContour == itsct2.iContour);
|
||||||
return forward ?
|
return forward ?
|
||||||
segment_length(poly, itsct .iSegment, itsct.pos(), itsct2.iSegment, itsct2.pos()) :
|
segment_length(poly, itsct .iSegment, itsct.pos(), itsct2.iSegment, itsct2.pos()) :
|
||||||
segment_length(poly, itsct2.iSegment, itsct2.pos(), itsct .iSegment, itsct.pos());
|
segment_length(poly, itsct2.iSegment, itsct2.pos(), itsct .iSegment, itsct.pos());
|
||||||
|
@ -1015,11 +1035,11 @@ static inline void emit_perimeter_segment_on_vertical_line(
|
||||||
const SegmentIntersection &itsct = il.intersections[iIntersection];
|
const SegmentIntersection &itsct = il.intersections[iIntersection];
|
||||||
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
||||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||||
myassert(itsct.is_inner());
|
assert(itsct.is_inner());
|
||||||
myassert(itsct2.is_inner());
|
assert(itsct2.is_inner());
|
||||||
myassert(itsct.type != itsct2.type);
|
assert(itsct.type != itsct2.type);
|
||||||
myassert(itsct.iContour == iInnerContour);
|
assert(itsct.iContour == iInnerContour);
|
||||||
myassert(itsct.iContour == itsct2.iContour);
|
assert(itsct.iContour == itsct2.iContour);
|
||||||
// Do not append the first point.
|
// Do not append the first point.
|
||||||
// out.points.push_back(Point(il.pos, itsct.pos));
|
// out.points.push_back(Point(il.pos, itsct.pos));
|
||||||
if (forward)
|
if (forward)
|
||||||
|
@ -1042,10 +1062,10 @@ static inline float measure_outer_contour_slab(
|
||||||
const SegmentIntersection &itsct = il.intersections[i_vline];
|
const SegmentIntersection &itsct = il.intersections[i_vline];
|
||||||
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
||||||
const Polygon &poly = poly_with_offset.contour((itsct.iContour);
|
const Polygon &poly = poly_with_offset.contour((itsct.iContour);
|
||||||
myassert(itsct.is_outer());
|
assert(itsct.is_outer());
|
||||||
myassert(itsct2.is_outer());
|
assert(itsct2.is_outer());
|
||||||
myassert(itsct.type != itsct2.type);
|
assert(itsct.type != itsct2.type);
|
||||||
myassert(itsct.iContour == itsct2.iContour);
|
assert(itsct.iContour == itsct2.iContour);
|
||||||
if (! itsct.is_outer() || ! itsct2.is_outer() || itsct.type == itsct2.type || itsct.iContour != itsct2.iContour)
|
if (! itsct.is_outer() || ! itsct2.is_outer() || itsct.type == itsct2.type || itsct.iContour != itsct2.iContour)
|
||||||
// Error, return zero area.
|
// Error, return zero area.
|
||||||
return 0.f;
|
return 0.f;
|
||||||
|
@ -1159,14 +1179,14 @@ static bool fill_hatching_segments_legacy(
|
||||||
for (size_t i_vline2 = 0; i_vline2 < segs.size(); ++ i_vline2) {
|
for (size_t i_vline2 = 0; i_vline2 < segs.size(); ++ i_vline2) {
|
||||||
const SegmentedIntersectionLine &seg = segs[i_vline2];
|
const SegmentedIntersectionLine &seg = segs[i_vline2];
|
||||||
if (! seg.intersections.empty()) {
|
if (! seg.intersections.empty()) {
|
||||||
myassert(seg.intersections.size() > 1);
|
assert(seg.intersections.size() > 1);
|
||||||
// Even number of intersections with the loops.
|
// Even number of intersections with the loops.
|
||||||
myassert((seg.intersections.size() & 1) == 0);
|
assert((seg.intersections.size() & 1) == 0);
|
||||||
myassert(seg.intersections.front().type == SegmentIntersection::OUTER_LOW);
|
assert(seg.intersections.front().type == SegmentIntersection::OUTER_LOW);
|
||||||
for (size_t i = 0; i < seg.intersections.size(); ++ i) {
|
for (size_t i = 0; i < seg.intersections.size(); ++ i) {
|
||||||
const SegmentIntersection &intrsctn = seg.intersections[i];
|
const SegmentIntersection &intrsctn = seg.intersections[i];
|
||||||
if (intrsctn.is_outer()) {
|
if (intrsctn.is_outer()) {
|
||||||
myassert(intrsctn.is_low() || i > 0);
|
assert(intrsctn.is_low() || i > 0);
|
||||||
bool consumed = intrsctn.is_low() ?
|
bool consumed = intrsctn.is_low() ?
|
||||||
intrsctn.consumed_vertical_up :
|
intrsctn.consumed_vertical_up :
|
||||||
seg.intersections[i-1].consumed_vertical_up;
|
seg.intersections[i-1].consumed_vertical_up;
|
||||||
|
@ -1205,11 +1225,11 @@ static bool fill_hatching_segments_legacy(
|
||||||
bool going_up = intrsctn->is_low();
|
bool going_up = intrsctn->is_low();
|
||||||
bool try_connect = false;
|
bool try_connect = false;
|
||||||
if (going_up) {
|
if (going_up) {
|
||||||
myassert(! intrsctn->consumed_vertical_up);
|
assert(! intrsctn->consumed_vertical_up);
|
||||||
myassert(i_intersection + 1 < seg.intersections.size());
|
assert(i_intersection + 1 < seg.intersections.size());
|
||||||
// Step back to the beginning of the vertical segment to mark it as consumed.
|
// Step back to the beginning of the vertical segment to mark it as consumed.
|
||||||
if (intrsctn->is_inner()) {
|
if (intrsctn->is_inner()) {
|
||||||
myassert(i_intersection > 0);
|
assert(i_intersection > 0);
|
||||||
-- intrsctn;
|
-- intrsctn;
|
||||||
-- i_intersection;
|
-- i_intersection;
|
||||||
}
|
}
|
||||||
|
@ -1218,25 +1238,25 @@ static bool fill_hatching_segments_legacy(
|
||||||
intrsctn->consumed_vertical_up = true;
|
intrsctn->consumed_vertical_up = true;
|
||||||
++ intrsctn;
|
++ intrsctn;
|
||||||
++ i_intersection;
|
++ i_intersection;
|
||||||
myassert(i_intersection < seg.intersections.size());
|
assert(i_intersection < seg.intersections.size());
|
||||||
} while (intrsctn->type != SegmentIntersection::OUTER_HIGH);
|
} while (intrsctn->type != SegmentIntersection::OUTER_HIGH);
|
||||||
if ((intrsctn - 1)->is_inner()) {
|
if ((intrsctn - 1)->is_inner()) {
|
||||||
// Step back.
|
// Step back.
|
||||||
-- intrsctn;
|
-- intrsctn;
|
||||||
-- i_intersection;
|
-- i_intersection;
|
||||||
myassert(intrsctn->type == SegmentIntersection::INNER_HIGH);
|
assert(intrsctn->type == SegmentIntersection::INNER_HIGH);
|
||||||
try_connect = true;
|
try_connect = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Going down.
|
// Going down.
|
||||||
myassert(intrsctn->is_high());
|
assert(intrsctn->is_high());
|
||||||
myassert(i_intersection > 0);
|
assert(i_intersection > 0);
|
||||||
myassert(! (intrsctn - 1)->consumed_vertical_up);
|
assert(! (intrsctn - 1)->consumed_vertical_up);
|
||||||
// Consume the complete vertical segment up to the outer contour.
|
// Consume the complete vertical segment up to the outer contour.
|
||||||
if (intrsctn->is_inner())
|
if (intrsctn->is_inner())
|
||||||
intrsctn->consumed_vertical_up = true;
|
intrsctn->consumed_vertical_up = true;
|
||||||
do {
|
do {
|
||||||
myassert(i_intersection > 0);
|
assert(i_intersection > 0);
|
||||||
-- intrsctn;
|
-- intrsctn;
|
||||||
-- i_intersection;
|
-- i_intersection;
|
||||||
intrsctn->consumed_vertical_up = true;
|
intrsctn->consumed_vertical_up = true;
|
||||||
|
@ -1245,7 +1265,7 @@ static bool fill_hatching_segments_legacy(
|
||||||
// Step back.
|
// Step back.
|
||||||
++ intrsctn;
|
++ intrsctn;
|
||||||
++ i_intersection;
|
++ i_intersection;
|
||||||
myassert(intrsctn->type == SegmentIntersection::INNER_LOW);
|
assert(intrsctn->type == SegmentIntersection::INNER_LOW);
|
||||||
try_connect = true;
|
try_connect = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1340,7 +1360,7 @@ static bool fill_hatching_segments_legacy(
|
||||||
bool take_next = (intrsctn_type_prev == INTERSECTION_TYPE_OTHER_VLINE_OK && intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK) ?
|
bool take_next = (intrsctn_type_prev == INTERSECTION_TYPE_OTHER_VLINE_OK && intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK) ?
|
||||||
(distNext < distPrev) :
|
(distNext < distPrev) :
|
||||||
intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK;
|
intrsctn_type_next == INTERSECTION_TYPE_OTHER_VLINE_OK;
|
||||||
myassert(intrsctn->is_inner());
|
assert(intrsctn->is_inner());
|
||||||
bool skip = params.dont_connect || (link_max_length > 0 && (take_next ? distNext : distPrev) > link_max_length);
|
bool skip = params.dont_connect || (link_max_length > 0 && (take_next ? distNext : distPrev) > link_max_length);
|
||||||
if (skip) {
|
if (skip) {
|
||||||
// Just skip the connecting contour and start a new path.
|
// Just skip the connecting contour and start a new path.
|
||||||
|
@ -1451,13 +1471,13 @@ static bool fill_hatching_segments_legacy(
|
||||||
|
|
||||||
// Finish the current vertical line,
|
// Finish the current vertical line,
|
||||||
// reset the current vertical line to pick a new starting point in the next round.
|
// reset the current vertical line to pick a new starting point in the next round.
|
||||||
myassert(intrsctn->is_outer());
|
assert(intrsctn->is_outer());
|
||||||
myassert(intrsctn->is_high() == going_up);
|
assert(intrsctn->is_high() == going_up);
|
||||||
pointLast = intrsctn->pos();
|
pointLast = intrsctn->pos();
|
||||||
polyline_current->points.push_back(pointLast);
|
polyline_current->points.push_back(pointLast);
|
||||||
// Handle duplicate points and zero length segments.
|
// Handle duplicate points and zero length segments.
|
||||||
polyline_current->remove_duplicate_points();
|
polyline_current->remove_duplicate_points();
|
||||||
myassert(! polyline_current->has_duplicate_points());
|
assert(! polyline_current->has_duplicate_points());
|
||||||
// Handle nearly zero length edges.
|
// Handle nearly zero length edges.
|
||||||
if (polyline_current->points.size() <= 1 ||
|
if (polyline_current->points.size() <= 1 ||
|
||||||
(polyline_current->points.size() == 2 &&
|
(polyline_current->points.size() == 2 &&
|
||||||
|
@ -1491,17 +1511,17 @@ static bool fill_hatching_segments_legacy(
|
||||||
for (Polylines::iterator it = polylines_out.begin() + n_polylines_out_initial; it != polylines_out.end(); ++ it) {
|
for (Polylines::iterator it = polylines_out.begin() + n_polylines_out_initial; it != polylines_out.end(); ++ it) {
|
||||||
// No need to translate, the absolute position is irrelevant.
|
// No need to translate, the absolute position is irrelevant.
|
||||||
// it->translate(- rotate_vector.second.x, - rotate_vector.second.y);
|
// it->translate(- rotate_vector.second.x, - rotate_vector.second.y);
|
||||||
myassert(! it->has_duplicate_points());
|
assert(! it->has_duplicate_points());
|
||||||
//it->rotate(rotate_vector.first);
|
//it->rotate(rotate_vector.first);
|
||||||
//FIXME rather simplify the paths to avoid very short edges?
|
//FIXME rather simplify the paths to avoid very short edges?
|
||||||
//myassert(! it->has_duplicate_points());
|
//assert(! it->has_duplicate_points());
|
||||||
it->remove_duplicate_points();
|
it->remove_duplicate_points();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
// Verify, that there are no duplicate points in the sequence.
|
// Verify, that there are no duplicate points in the sequence.
|
||||||
for (Polyline &polyline : polylines_out)
|
for (Polyline &polyline : polylines_out)
|
||||||
myassert(! polyline.has_duplicate_points());
|
assert(! polyline.has_duplicate_points());
|
||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1511,10 +1531,10 @@ static bool fill_hatching_segments_legacy(
|
||||||
|
|
||||||
bool FillRectilinear3::fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, std::vector<FillDirParams> &fill_dir_params, Polylines &polylines_out)
|
bool FillRectilinear3::fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, std::vector<FillDirParams> &fill_dir_params, Polylines &polylines_out)
|
||||||
{
|
{
|
||||||
myassert(params.density > 0.0001f && params.density <= 1.f);
|
assert(params.density > 0.0001f && params.density <= 1.f);
|
||||||
|
|
||||||
const float INFILL_OVERLAP_OVER_SPACING = 0.45f;
|
const float INFILL_OVERLAP_OVER_SPACING = 0.45f;
|
||||||
myassert(INFILL_OVERLAP_OVER_SPACING > 0 && INFILL_OVERLAP_OVER_SPACING < 0.5f);
|
assert(INFILL_OVERLAP_OVER_SPACING > 0 && INFILL_OVERLAP_OVER_SPACING < 0.5f);
|
||||||
|
|
||||||
// On the polygons of poly_with_offset, the infill lines will be connected.
|
// On the polygons of poly_with_offset, the infill lines will be connected.
|
||||||
FillRectilinear3_Internal::ExPolygonWithOffset poly_with_offset(
|
FillRectilinear3_Internal::ExPolygonWithOffset poly_with_offset(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef slic3r_FillRectilinear2_hpp_
|
#ifndef slic3r_FillRectilinear3_hpp_
|
||||||
#define slic3r_FillRectilinear2_hpp_
|
#define slic3r_FillRectilinear3_hpp_
|
||||||
|
|
||||||
#include "../libslic3r.h"
|
#include "../libslic3r.h"
|
||||||
|
|
||||||
|
@ -80,4 +80,4 @@ protected:
|
||||||
|
|
||||||
}; // namespace Slic3r
|
}; // namespace Slic3r
|
||||||
|
|
||||||
#endif // slic3r_FillRectilinear2_hpp_
|
#endif // slic3r_FillRectilinear3_hpp_
|
||||||
|
|
|
@ -286,7 +286,7 @@ public:
|
||||||
if (std::abs(det) > err)
|
if (std::abs(det) > err)
|
||||||
return ((det > 0) ? 1 : -1) * invert;
|
return ((det > 0) ? 1 : -1) * invert;
|
||||||
}
|
}
|
||||||
return sign_determinant_2x2(p1, q1, p2, q2);
|
return sign_determinant_2x2(p1, q1, p2, q2) * invert;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exact orientation predicate,
|
// Exact orientation predicate,
|
||||||
|
@ -297,4 +297,11 @@ public:
|
||||||
Slic3r::Vector v2(p3 - p1);
|
Slic3r::Vector v2(p3 - p1);
|
||||||
return sign_determinant_2x2_filtered(v1.x, v1.y, v2.x, v2.y);
|
return sign_determinant_2x2_filtered(v1.x, v1.y, v2.x, v2.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exact orientation predicate,
|
||||||
|
// returns +1: CCW, 0: collinear, -1: CW.
|
||||||
|
static int cross(const Slic3r::Point &v1, const Slic3r::Point &v2)
|
||||||
|
{
|
||||||
|
return sign_determinant_2x2_filtered(v1.x, v1.y, v2.x, v2.y);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -79,6 +79,7 @@ inline Point operator+(const Point& point1, const Point& point2) { return Point(
|
||||||
inline Point operator-(const Point& point1, const Point& point2) { return Point(point1.x - point2.x, point1.y - point2.y); }
|
inline Point operator-(const Point& point1, const Point& point2) { return Point(point1.x - point2.x, point1.y - point2.y); }
|
||||||
inline Point operator*(double scalar, const Point& point2) { return Point(scalar * point2.x, scalar * point2.y); }
|
inline Point operator*(double scalar, const Point& point2) { return Point(scalar * point2.x, scalar * point2.y); }
|
||||||
inline int64_t cross(const Point &v1, const Point &v2) { return int64_t(v1.x) * int64_t(v2.y) - int64_t(v1.y) * int64_t(v2.x); }
|
inline int64_t cross(const Point &v1, const Point &v2) { return int64_t(v1.x) * int64_t(v2.y) - int64_t(v1.y) * int64_t(v2.x); }
|
||||||
|
inline int64_t dot(const Point &v1, const Point &v2) { return int64_t(v1.x) * int64_t(v2.x) + int64_t(v1.y) * int64_t(v2.y); }
|
||||||
|
|
||||||
// To be used by std::unordered_map, std::unordered_multimap and friends.
|
// To be used by std::unordered_map, std::unordered_multimap and friends.
|
||||||
struct PointHash {
|
struct PointHash {
|
||||||
|
|
Loading…
Add table
Reference in a new issue