Further implementation of FillRectilinear3.
This commit is contained in:
parent
137aab9631
commit
812a2c7cbd
5 changed files with 237 additions and 213 deletions
|
@ -27,10 +27,6 @@
|
|||
// We want our version of assert.
|
||||
#include "../libslic3r.h"
|
||||
|
||||
#ifndef myassert
|
||||
#define myassert assert
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// 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);
|
||||
if (pa.y > pb.y)
|
||||
std::swap(pa.y, pb.y);
|
||||
myassert(px.x >= pa.x && px.x <= pb.x);
|
||||
myassert(px.y >= pa.y && px.y <= pb.y);
|
||||
assert(px.x >= pa.x && px.x <= pb.x);
|
||||
assert(px.y >= pa.y && px.y <= pb.y);
|
||||
}
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
const Point *pPrev = &p1;
|
||||
|
@ -288,9 +284,9 @@ public:
|
|||
// for the infill pattern, don't cut the corners.
|
||||
// default miterLimt = 3
|
||||
//double mitterLimit = 10.;
|
||||
myassert(aoffset1 < 0);
|
||||
myassert(aoffset2 < 0);
|
||||
myassert(aoffset2 < aoffset1);
|
||||
assert(aoffset1 < 0);
|
||||
assert(aoffset2 < 0);
|
||||
assert(aoffset2 < aoffset1);
|
||||
bool sticks_removed = remove_sticks(polygons_src);
|
||||
// if (sticks_removed) printf("Sticks removed!\n");
|
||||
polygons_outer = offset(polygons_src, aoffset1,
|
||||
|
@ -311,7 +307,7 @@ public:
|
|||
polygons_ccw.assign(n_contours, false);
|
||||
for (size_t i = 0; i < n_contours; ++ i) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -406,23 +402,23 @@ static inline int intersection_on_prev_next_vertical_line(
|
|||
if (itsct.iContour == itsct2.iContour && itsct.type == itsct2.type) {
|
||||
/*
|
||||
if (itsct.is_low()) {
|
||||
myassert(itsct.type == SegmentIntersection::INNER_LOW);
|
||||
myassert(iIntersection > 0);
|
||||
myassert(il.intersections[iIntersection-1].type == SegmentIntersection::OUTER_LOW);
|
||||
myassert(i > 0);
|
||||
assert(itsct.type == SegmentIntersection::INNER_LOW);
|
||||
assert(iIntersection > 0);
|
||||
assert(il.intersections[iIntersection-1].type == SegmentIntersection::OUTER_LOW);
|
||||
assert(i > 0);
|
||||
if (il2.intersections[i-1].is_inner())
|
||||
// Take only the lowest inner intersection point.
|
||||
continue;
|
||||
myassert(il2.intersections[i-1].type == SegmentIntersection::OUTER_LOW);
|
||||
assert(il2.intersections[i-1].type == SegmentIntersection::OUTER_LOW);
|
||||
} else {
|
||||
myassert(itsct.type == SegmentIntersection::INNER_HIGH);
|
||||
myassert(iIntersection+1 < il.intersections.size());
|
||||
myassert(il.intersections[iIntersection+1].type == SegmentIntersection::OUTER_HIGH);
|
||||
myassert(i+1 < il2.intersections.size());
|
||||
assert(itsct.type == SegmentIntersection::INNER_HIGH);
|
||||
assert(iIntersection+1 < il.intersections.size());
|
||||
assert(il.intersections[iIntersection+1].type == SegmentIntersection::OUTER_HIGH);
|
||||
assert(i+1 < il2.intersections.size());
|
||||
if (il2.intersections[i+1].is_inner())
|
||||
// Take only the highest inner intersection point.
|
||||
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.
|
||||
|
@ -487,21 +483,21 @@ static inline IntersectionTypeOtherVLine intersection_type_on_prev_next_vertical
|
|||
// iVertical line multiple times before reaching iIntersectionOther.
|
||||
if (iIntersectionOther == -1)
|
||||
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 SegmentIntersection &itsct_this = il_this.intersections[iIntersection];
|
||||
const SegmentedIntersectionLine &il_other = segs[dir_is_next ? (iVerticalLine+1) : (iVerticalLine-1)];
|
||||
const SegmentIntersection &itsct_other = il_other.intersections[iIntersectionOther];
|
||||
myassert(itsct_other.is_inner());
|
||||
myassert(iIntersectionOther > 0);
|
||||
myassert(iIntersectionOther + 1 < il_other.intersections.size());
|
||||
assert(itsct_other.is_inner());
|
||||
assert(iIntersectionOther > 0);
|
||||
assert(iIntersectionOther + 1 < il_other.intersections.size());
|
||||
// Is iIntersectionOther at the boundary of a vertical segment?
|
||||
const SegmentIntersection &itsct_other2 = il_other.intersections[itsct_other.is_low() ? iIntersectionOther - 1 : iIntersectionOther + 1];
|
||||
if (itsct_other2.is_inner())
|
||||
// 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.
|
||||
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)
|
||||
// This perimeter segment was already 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 Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||
// const bool ccw = poly_with_offset.is_contour_ccw(iInnerContour);
|
||||
myassert(itsct.type == itsct2.type);
|
||||
myassert(itsct.iContour == itsct2.iContour);
|
||||
myassert(itsct.is_inner());
|
||||
assert(itsct.type == itsct2.type);
|
||||
assert(itsct.iContour == itsct2.iContour);
|
||||
assert(itsct.is_inner());
|
||||
const bool forward = itsct.is_low() == dir_is_next;
|
||||
|
||||
Point p1(il.pos, itsct.pos());
|
||||
|
@ -605,9 +601,9 @@ static inline void emit_perimeter_prev_next_segment(
|
|||
size_t iVerticalLineOther = iVerticalLine;
|
||||
if (dir_is_next) {
|
||||
++ iVerticalLineOther;
|
||||
myassert(iVerticalLineOther < segs.size());
|
||||
assert(iVerticalLineOther < segs.size());
|
||||
} else {
|
||||
myassert(iVerticalLineOther > 0);
|
||||
assert(iVerticalLineOther > 0);
|
||||
-- iVerticalLineOther;
|
||||
}
|
||||
|
||||
|
@ -617,9 +613,9 @@ static inline void emit_perimeter_prev_next_segment(
|
|||
const SegmentIntersection &itsct2 = il2.intersections[iIntersection2];
|
||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||
// const bool ccw = poly_with_offset.is_contour_ccw(iInnerContour);
|
||||
myassert(itsct.type == itsct2.type);
|
||||
myassert(itsct.iContour == itsct2.iContour);
|
||||
myassert(itsct.is_inner());
|
||||
assert(itsct.type == itsct2.type);
|
||||
assert(itsct.iContour == itsct2.iContour);
|
||||
assert(itsct.is_inner());
|
||||
const bool forward = itsct.is_low() == dir_is_next;
|
||||
// Do not append the first point.
|
||||
// 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 &itsct2 = il.intersections[iIntersection2];
|
||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||
myassert(itsct.is_inner());
|
||||
myassert(itsct2.is_inner());
|
||||
myassert(itsct.type != itsct2.type);
|
||||
myassert(itsct.iContour == iInnerContour);
|
||||
myassert(itsct.iContour == itsct2.iContour);
|
||||
assert(itsct.is_inner());
|
||||
assert(itsct2.is_inner());
|
||||
assert(itsct.type != itsct2.type);
|
||||
assert(itsct.iContour == iInnerContour);
|
||||
assert(itsct.iContour == itsct2.iContour);
|
||||
Point p1(il.pos, itsct.pos());
|
||||
Point p2(il.pos, itsct2.pos());
|
||||
return forward ?
|
||||
|
@ -673,11 +669,11 @@ static inline void emit_perimeter_segment_on_vertical_line(
|
|||
const SegmentIntersection &itsct = il.intersections[iIntersection];
|
||||
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||
myassert(itsct.is_inner());
|
||||
myassert(itsct2.is_inner());
|
||||
myassert(itsct.type != itsct2.type);
|
||||
myassert(itsct.iContour == iInnerContour);
|
||||
myassert(itsct.iContour == itsct2.iContour);
|
||||
assert(itsct.is_inner());
|
||||
assert(itsct2.is_inner());
|
||||
assert(itsct.type != itsct2.type);
|
||||
assert(itsct.iContour == iInnerContour);
|
||||
assert(itsct.iContour == itsct2.iContour);
|
||||
// Do not append the first point.
|
||||
// out.points.push_back(Point(il.pos, itsct.pos));
|
||||
if (forward)
|
||||
|
@ -700,10 +696,10 @@ static inline float measure_outer_contour_slab(
|
|||
const SegmentIntersection &itsct = il.intersections[i_vline];
|
||||
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
||||
const Polygon &poly = poly_with_offset.contour((itsct.iContour);
|
||||
myassert(itsct.is_outer());
|
||||
myassert(itsct2.is_outer());
|
||||
myassert(itsct.type != itsct2.type);
|
||||
myassert(itsct.iContour == itsct2.iContour);
|
||||
assert(itsct.is_outer());
|
||||
assert(itsct2.is_outer());
|
||||
assert(itsct.type != itsct2.type);
|
||||
assert(itsct.iContour == itsct2.iContour);
|
||||
if (! itsct.is_outer() || ! itsct2.is_outer() || itsct.type == itsct2.type || itsct.iContour != itsct2.iContour)
|
||||
// Error, return zero area.
|
||||
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.
|
||||
// const float INFILL_OVERLAP_OVER_SPACING = 0.3f;
|
||||
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
|
||||
std::pair<float, Point> rotate_vector = this->_infill_direction(surface);
|
||||
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);
|
||||
|
||||
// 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)
|
||||
// No vertical line intersects this segment.
|
||||
continue;
|
||||
myassert(il >= 0 && il < segs.size());
|
||||
myassert(ir >= 0 && ir < segs.size());
|
||||
assert(il >= 0 && il < segs.size());
|
||||
assert(ir >= 0 && ir < segs.size());
|
||||
for (int i = il; i <= ir; ++ i) {
|
||||
coord_t this_x = segs[i].pos;
|
||||
assert(this_x == i * line_spacing + x0);
|
||||
SegmentIntersection is;
|
||||
is.iContour = iContour;
|
||||
is.iSegment = iSegment;
|
||||
myassert(l <= this_x);
|
||||
myassert(r >= this_x);
|
||||
assert(l <= this_x);
|
||||
assert(r >= this_x);
|
||||
// Calculate the intersection position in y axis. x is known.
|
||||
if (p1.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_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'.
|
||||
is.pos_p *= int64_t(p2.y - p1.y);
|
||||
is.pos_p += p1.y * int64_t(is.pos_q);
|
||||
}
|
||||
// +-1 to take rounding into account.
|
||||
myassert(is.pos() + 1 >= std::min(p1.y, p2.y));
|
||||
myassert(is.pos() <= std::max(p1.y, p2.y) + 1);
|
||||
assert(is.pos() + 1 >= std::min(p1.y, p2.y));
|
||||
assert(is.pos() <= std::max(p1.y, p2.y) + 1);
|
||||
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.
|
||||
size_t iSegment2 = sil.intersections[j-1].iSegment;
|
||||
size_t iPrev2 = ((iSegment2 == 0) ? contour.size() : iSegment2) - 1;
|
||||
myassert(iSegment == iPrev2 || iSegment2 == iPrev);
|
||||
assert(iSegment == iPrev2 || iSegment2 == iPrev);
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
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)
|
||||
|
@ -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) {
|
||||
const SegmentedIntersectionLine &seg = segs[i_vline2];
|
||||
if (! seg.intersections.empty()) {
|
||||
myassert(seg.intersections.size() > 1);
|
||||
assert(seg.intersections.size() > 1);
|
||||
// Even number of intersections with the loops.
|
||||
myassert((seg.intersections.size() & 1) == 0);
|
||||
myassert(seg.intersections.front().type == SegmentIntersection::OUTER_LOW);
|
||||
assert((seg.intersections.size() & 1) == 0);
|
||||
assert(seg.intersections.front().type == SegmentIntersection::OUTER_LOW);
|
||||
for (size_t i = 0; i < seg.intersections.size(); ++ i) {
|
||||
const SegmentIntersection &intrsctn = seg.intersections[i];
|
||||
if (intrsctn.is_outer()) {
|
||||
myassert(intrsctn.is_low() || i > 0);
|
||||
assert(intrsctn.is_low() || i > 0);
|
||||
bool consumed = intrsctn.is_low() ?
|
||||
intrsctn.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 try_connect = false;
|
||||
if (going_up) {
|
||||
myassert(! intrsctn->consumed_vertical_up);
|
||||
myassert(i_intersection + 1 < seg.intersections.size());
|
||||
assert(! intrsctn->consumed_vertical_up);
|
||||
assert(i_intersection + 1 < seg.intersections.size());
|
||||
// Step back to the beginning of the vertical segment to mark it as consumed.
|
||||
if (intrsctn->is_inner()) {
|
||||
myassert(i_intersection > 0);
|
||||
assert(i_intersection > 0);
|
||||
-- intrsctn;
|
||||
-- i_intersection;
|
||||
}
|
||||
|
@ -1117,25 +1113,25 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||
intrsctn->consumed_vertical_up = true;
|
||||
++ intrsctn;
|
||||
++ i_intersection;
|
||||
myassert(i_intersection < seg.intersections.size());
|
||||
assert(i_intersection < seg.intersections.size());
|
||||
} while (intrsctn->type != SegmentIntersection::OUTER_HIGH);
|
||||
if ((intrsctn - 1)->is_inner()) {
|
||||
// Step back.
|
||||
-- intrsctn;
|
||||
-- i_intersection;
|
||||
myassert(intrsctn->type == SegmentIntersection::INNER_HIGH);
|
||||
assert(intrsctn->type == SegmentIntersection::INNER_HIGH);
|
||||
try_connect = true;
|
||||
}
|
||||
} else {
|
||||
// Going down.
|
||||
myassert(intrsctn->is_high());
|
||||
myassert(i_intersection > 0);
|
||||
myassert(! (intrsctn - 1)->consumed_vertical_up);
|
||||
assert(intrsctn->is_high());
|
||||
assert(i_intersection > 0);
|
||||
assert(! (intrsctn - 1)->consumed_vertical_up);
|
||||
// Consume the complete vertical segment up to the outer contour.
|
||||
if (intrsctn->is_inner())
|
||||
intrsctn->consumed_vertical_up = true;
|
||||
do {
|
||||
myassert(i_intersection > 0);
|
||||
assert(i_intersection > 0);
|
||||
-- intrsctn;
|
||||
-- i_intersection;
|
||||
intrsctn->consumed_vertical_up = true;
|
||||
|
@ -1144,7 +1140,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
|||
// Step back.
|
||||
++ intrsctn;
|
||||
++ i_intersection;
|
||||
myassert(intrsctn->type == SegmentIntersection::INNER_LOW);
|
||||
assert(intrsctn->type == SegmentIntersection::INNER_LOW);
|
||||
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) ?
|
||||
(distNext < distPrev) :
|
||||
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);
|
||||
if (skip) {
|
||||
// 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,
|
||||
// reset the current vertical line to pick a new starting point in the next round.
|
||||
myassert(intrsctn->is_outer());
|
||||
myassert(intrsctn->is_high() == going_up);
|
||||
assert(intrsctn->is_outer());
|
||||
assert(intrsctn->is_high() == going_up);
|
||||
pointLast = Point(seg.pos, intrsctn->pos());
|
||||
polyline_current->points.push_back(pointLast);
|
||||
// Handle duplicate points and zero length segments.
|
||||
polyline_current->remove_duplicate_points();
|
||||
myassert(! polyline_current->has_duplicate_points());
|
||||
assert(! polyline_current->has_duplicate_points());
|
||||
// Handle nearly zero length edges.
|
||||
if (polyline_current->points.size() <= 1 ||
|
||||
(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) {
|
||||
// No need to translate, the absolute position is irrelevant.
|
||||
// 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);
|
||||
//FIXME rather simplify the paths to avoid very short edges?
|
||||
//myassert(! it->has_duplicate_points());
|
||||
//assert(! it->has_duplicate_points());
|
||||
it->remove_duplicate_points();
|
||||
}
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
// Verify, that there are no duplicate points in the sequence.
|
||||
for (Polyline &polyline : polylines_out)
|
||||
myassert(! polyline.has_duplicate_points());
|
||||
assert(! polyline.has_duplicate_points());
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
|
||||
return true;
|
||||
|
|
|
@ -15,23 +15,18 @@
|
|||
|
||||
#include "FillRectilinear3.hpp"
|
||||
|
||||
// #define SLIC3R_DEBUG
|
||||
#define SLIC3R_DEBUG
|
||||
|
||||
// Make assert active if SLIC3R_DEBUG
|
||||
#ifdef SLIC3R_DEBUG
|
||||
#undef NDEBUG
|
||||
#define DEBUG
|
||||
#define _DEBUG
|
||||
#include "SVG.hpp"
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
|
||||
// We want our version of assert.
|
||||
#include "../libslic3r.h"
|
||||
|
||||
#ifndef myassert
|
||||
#define myassert assert
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace FillRectilinear3_Internal {
|
||||
|
@ -55,9 +50,9 @@ public:
|
|||
// for the infill pattern, don't cut the corners.
|
||||
// default miterLimt = 3
|
||||
//double mitterLimit = 10.;
|
||||
myassert(aoffset1 < 0);
|
||||
myassert(aoffset2 < 0);
|
||||
myassert(aoffset2 < aoffset1);
|
||||
assert(aoffset1 < 0);
|
||||
assert(aoffset2 < 0);
|
||||
assert(aoffset2 < aoffset1);
|
||||
// bool sticks_removed = remove_sticks(polygons_src);
|
||||
// if (sticks_removed) printf("Sticks removed!\n");
|
||||
polygons_outer = offset(polygons_src, aoffset1,
|
||||
|
@ -78,7 +73,7 @@ public:
|
|||
polygons_ccw.assign(n_contours, false);
|
||||
for (size_t i = 0; i < n_contours; ++ i) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +176,8 @@ public:
|
|||
int ordering_along_line(const SegmentIntersection &other) const;
|
||||
|
||||
// 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; }
|
||||
|
||||
//FIXME legacy code, suporting the old graph traversal algorithm. Please remove.
|
||||
|
@ -200,7 +196,7 @@ public:
|
|||
// Index of this vertical intersection line.
|
||||
size_t idx;
|
||||
// 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.
|
||||
Point pos;
|
||||
// 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.
|
||||
const Polygon &poly = this->expoly_with_offset->contour(this->iContour);
|
||||
// 30 bits + 1 signum bit.
|
||||
const Point &seg_start = poly.points[this->iSegment];
|
||||
const Point &seg_end = poly.points[(this->iSegment + 1) % poly.points.size()];
|
||||
const Point &seg_start = poly.points[(this->iSegment == 0) ? poly.points.size() - 1 : this->iSegment - 1];
|
||||
const Point &seg_end = poly.points[this->iSegment];
|
||||
// Point, vector of the segment.
|
||||
const Pointf p1 = convert_to<Pointf>(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
|
||||
const Polygon &poly_a = this->expoly_with_offset->contour(this->iContour);
|
||||
// 30 bits + 1 signum bit.
|
||||
const Point &seg_start_a = poly_a.points[this->iSegment];
|
||||
const Point &seg_end_a = poly_a.points[(this->iSegment + 1) % poly_a.points.size()];
|
||||
const Point vec_a = seg_end_a - seg_start_a;
|
||||
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];
|
||||
|
||||
// Segment of other
|
||||
const Polygon &poly_b = this->expoly_with_offset->contour(other.iContour);
|
||||
// 30 bits + 1 signum bit.
|
||||
const Point &seg_start_b = poly_b.points[other.iSegment];
|
||||
const Point &seg_end_b = poly_b.points[(other.iSegment + 1) % poly_b.points.size()];
|
||||
const Point vec_b = seg_end_b - seg_start_b;
|
||||
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];
|
||||
|
||||
if (this->iContour == other.iContour) {
|
||||
if ((this->iSegment + 1) % poly_a.points.size() == other.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) {
|
||||
// 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 {
|
||||
// General case.
|
||||
}
|
||||
}
|
||||
|
||||
// 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_end = signum(cross(vec_b, seg_end_a - seg_start_b));
|
||||
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.
|
||||
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_end2 = signum(cross(vec_a, seg_end_b - seg_start_a));
|
||||
int side2 = side_start2 * side_end2;
|
||||
//if (side == 0 && side2 == 0)
|
||||
// The segments share one of their end points.
|
||||
if (side2 > 0)
|
||||
// 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;
|
||||
|
||||
if (side == 0 && side2 == 0)
|
||||
// The segments share one of their end points.
|
||||
return 0;
|
||||
return signum(cross(this->line->dir, vec_a)) * side_start2;
|
||||
|
||||
// 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),
|
||||
// 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.
|
||||
int64_t denom1 = cross(vec_a, this->line->dir);
|
||||
int64_t denom2 = cross(vec_b, this->line->dir);
|
||||
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);
|
||||
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);
|
||||
assert(denom1 != 0);
|
||||
int64_t denom1 = cross(this->line->dir, vec_a);
|
||||
int64_t denom2 = cross(this->line->dir, vec_b);
|
||||
Point vx_a = seg_start_a - this->line->pos;
|
||||
Point vx_b = seg_start_b - this->line->pos;
|
||||
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);
|
||||
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,
|
||||
// the following class holds the hatching lines of each of the hatching directions.
|
||||
class InfillHatchingSingleDirection
|
||||
|
@ -353,12 +375,12 @@ static bool prepare_infill_hatching_segments(
|
|||
InfillHatchingSingleDirection &out)
|
||||
{
|
||||
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.
|
||||
out.direction.rotate(out.angle + 0.5 * M_PI);
|
||||
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);
|
||||
|
||||
// Bounding box around the source contour, aligned with out.angle.
|
||||
|
@ -409,18 +431,18 @@ static bool prepare_infill_hatching_segments(
|
|||
// For each contour
|
||||
// Allocate storage for the segments.
|
||||
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) {
|
||||
auto &seg = out.segs[i];
|
||||
seg.idx = i;
|
||||
seg.x = x0 + coord_t(i) * line_spacing;
|
||||
seg.pos = Point(seg.x, bounding_box.min.y);
|
||||
seg.pos.rotate(out.angle);
|
||||
// seg.x = x0 + coord_t(i) * line_spacing;
|
||||
coord_t x = x0 + coord_t(i) * line_spacing;
|
||||
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;
|
||||
}
|
||||
|
||||
#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) {
|
||||
const Points &contour = poly_with_offset.contour(iContour).points;
|
||||
if (contour.size() < 2)
|
||||
|
@ -440,60 +462,58 @@ static bool prepare_infill_hatching_segments(
|
|||
// Always orient the input segment consistently towards the hatching direction.
|
||||
std::swap(pl, pr);
|
||||
// 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 r = (coord_t)ceil (cos_a * pr->x - sin_a * pr->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 + SCALED_EPSILON);
|
||||
assert(l < r - SCALED_EPSILON);
|
||||
// il, ir are the left / right indices of vertical lines intersecting a segment
|
||||
int il = (l - x0) / line_spacing;
|
||||
il = std::max(int(0), il);
|
||||
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;
|
||||
int il = std::max<int>(0, (l - x0 + line_spacing) / line_spacing);
|
||||
int ir = std::min<int>(int(out.segs.size()) - 1, (r - x0) / line_spacing);
|
||||
// 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.
|
||||
while (il <= ir && Int128::orient(out.segs[il].pos, out.segs[il].pos + out.direction, *pl) < 0)
|
||||
++ il;
|
||||
while (il <= ir && Int128::orient(out.segs[ir].pos, out.segs[ir].pos + out.direction, *pr) > 0)
|
||||
-- ir;
|
||||
if (il > ir)
|
||||
// No vertical line intersects this segment.
|
||||
continue;
|
||||
// Here it is ensured, that
|
||||
// 1) out.seg is not parallel to (pl, pr)
|
||||
// 2) all lines from il to ir intersect <pl, pr>.
|
||||
myassert(il >= 0 && il < out.segs.size());
|
||||
myassert(ir >= 0 && ir < out.segs.size());
|
||||
assert(il >= 0 && ir < int(out.segs.size()));
|
||||
for (int i = il; i <= ir; ++ i) {
|
||||
myassert(out.segs[i].x == i * line_spacing + x0);
|
||||
myassert(l <= out.segs[i].x);
|
||||
myassert(r >= out.segs[i].x);
|
||||
// assert(out.segs[i].x == i * line_spacing + x0);
|
||||
// assert(l <= out.segs[i].x);
|
||||
// assert(r >= out.segs[i].x);
|
||||
SegmentIntersection is;
|
||||
is.line = &out.segs[i];
|
||||
is.expoly_with_offset = &poly_with_offset;
|
||||
is.iContour = iContour;
|
||||
is.iSegment = iSegment;
|
||||
is.iSegment = iSegment;
|
||||
// Test whether the calculated intersection point falls into the bounding box of the input segment.
|
||||
// +-1 to take rounding into account.
|
||||
myassert(is.pos().x + 1 >= std::min(pl->x, pr->x));
|
||||
myassert(is.pos().y + 1 >= std::min(pl->y, pr->y));
|
||||
myassert(is.pos().x <= std::max(pl->x, pr->x) + 1);
|
||||
myassert(is.pos().y <= std::max(pl->y, pr->y) + 1);
|
||||
assert(Int128::orient(out.segs[i].pos, out.segs[i].pos + out.direction, *pl) >= 0);
|
||||
assert(Int128::orient(out.segs[i].pos, out.segs[i].pos + out.direction, *pr) <= 0);
|
||||
assert(is.pos().x + 1 >= std::min(pl->x, pr->x));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Sort the intersections along their segments, specify the intersection types.
|
||||
for (size_t i_seg = 0; i_seg < out.segs.size(); ++ i_seg) {
|
||||
SegmentedIntersectionLine &sil = out.segs[i_seg];
|
||||
// Sort the intersection points using exact rational arithmetic.
|
||||
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.
|
||||
// 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.
|
||||
|
@ -507,7 +527,7 @@ static bool prepare_infill_hatching_segments(
|
|||
const Points &contour = poly_with_offset.contour(iContour).points;
|
||||
size_t iSegment = sil.intersections[i].iSegment;
|
||||
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;
|
||||
sil.intersections[i].type = poly_with_offset.is_contour_outer(iContour) ?
|
||||
(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.
|
||||
size_t iSegment2 = sil.intersections[j-1].iSegment;
|
||||
size_t iPrev2 = ((iSegment2 == 0) ? contour.size() : iSegment2) - 1;
|
||||
myassert(iSegment == iPrev2 || iSegment2 == iPrev);
|
||||
assert(iSegment == iPrev2 || iSegment2 == iPrev);
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
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)
|
||||
|
@ -643,8 +663,8 @@ static inline coordf_t segment_length(const Polygon &poly, size_t seg1, const Po
|
|||
std::swap(pa.x, pb.x);
|
||||
if (pa.y > pb.y)
|
||||
std::swap(pa.y, pb.y);
|
||||
myassert(px.x >= pa.x && px.x <= pb.x);
|
||||
myassert(px.y >= pa.y && px.y <= pb.y);
|
||||
assert(px.x >= pa.x && px.x <= pb.x);
|
||||
assert(px.y >= pa.y && px.y <= pb.y);
|
||||
}
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
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.is_low()) {
|
||||
myassert(itsct.type == SegmentIntersection::INNER_LOW);
|
||||
myassert(iIntersection > 0);
|
||||
myassert(il.intersections[iIntersection-1].type == SegmentIntersection::OUTER_LOW);
|
||||
myassert(i > 0);
|
||||
assert(itsct.type == SegmentIntersection::INNER_LOW);
|
||||
assert(iIntersection > 0);
|
||||
assert(il.intersections[iIntersection-1].type == SegmentIntersection::OUTER_LOW);
|
||||
assert(i > 0);
|
||||
if (il2.intersections[i-1].is_inner())
|
||||
// Take only the lowest inner intersection point.
|
||||
continue;
|
||||
myassert(il2.intersections[i-1].type == SegmentIntersection::OUTER_LOW);
|
||||
assert(il2.intersections[i-1].type == SegmentIntersection::OUTER_LOW);
|
||||
} else {
|
||||
myassert(itsct.type == SegmentIntersection::INNER_HIGH);
|
||||
myassert(iIntersection+1 < il.intersections.size());
|
||||
myassert(il.intersections[iIntersection+1].type == SegmentIntersection::OUTER_HIGH);
|
||||
myassert(i+1 < il2.intersections.size());
|
||||
assert(itsct.type == SegmentIntersection::INNER_HIGH);
|
||||
assert(iIntersection+1 < il.intersections.size());
|
||||
assert(il.intersections[iIntersection+1].type == SegmentIntersection::OUTER_HIGH);
|
||||
assert(i+1 < il2.intersections.size());
|
||||
if (il2.intersections[i+1].is_inner())
|
||||
// Take only the highest inner intersection point.
|
||||
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.
|
||||
|
@ -831,21 +851,21 @@ static inline IntersectionTypeOtherVLine intersection_type_on_prev_next_vertical
|
|||
// iVertical line multiple times before reaching iIntersectionOther.
|
||||
if (iIntersectionOther == -1)
|
||||
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 SegmentIntersection &itsct_this = il_this.intersections[iIntersection];
|
||||
const SegmentedIntersectionLine &il_other = segs[dir_is_next ? (iVerticalLine+1) : (iVerticalLine-1)];
|
||||
const SegmentIntersection &itsct_other = il_other.intersections[iIntersectionOther];
|
||||
myassert(itsct_other.is_inner());
|
||||
myassert(iIntersectionOther > 0);
|
||||
myassert(iIntersectionOther + 1 < il_other.intersections.size());
|
||||
assert(itsct_other.is_inner());
|
||||
assert(iIntersectionOther > 0);
|
||||
assert(iIntersectionOther + 1 < il_other.intersections.size());
|
||||
// Is iIntersectionOther at the boundary of a vertical segment?
|
||||
const SegmentIntersection &itsct_other2 = il_other.intersections[itsct_other.is_low() ? iIntersectionOther - 1 : iIntersectionOther + 1];
|
||||
if (itsct_other2.is_inner())
|
||||
// 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.
|
||||
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)
|
||||
// This perimeter segment was already 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 Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||
// const bool ccw = poly_with_offset.is_contour_ccw(iInnerContour);
|
||||
myassert(itsct.type == itsct2.type);
|
||||
myassert(itsct.iContour == itsct2.iContour);
|
||||
myassert(itsct.is_inner());
|
||||
assert(itsct.type == itsct2.type);
|
||||
assert(itsct.iContour == itsct2.iContour);
|
||||
assert(itsct.is_inner());
|
||||
const bool forward = itsct.is_low() == dir_is_next;
|
||||
|
||||
Point p1 = itsct.pos();
|
||||
|
@ -949,9 +969,9 @@ static inline void emit_perimeter_prev_next_segment(
|
|||
size_t iVerticalLineOther = iVerticalLine;
|
||||
if (dir_is_next) {
|
||||
++ iVerticalLineOther;
|
||||
myassert(iVerticalLineOther < segs.size());
|
||||
assert(iVerticalLineOther < segs.size());
|
||||
} else {
|
||||
myassert(iVerticalLineOther > 0);
|
||||
assert(iVerticalLineOther > 0);
|
||||
-- iVerticalLineOther;
|
||||
}
|
||||
|
||||
|
@ -961,9 +981,9 @@ static inline void emit_perimeter_prev_next_segment(
|
|||
const SegmentIntersection &itsct2 = il2.intersections[iIntersection2];
|
||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||
// const bool ccw = poly_with_offset.is_contour_ccw(iInnerContour);
|
||||
myassert(itsct.type == itsct2.type);
|
||||
myassert(itsct.iContour == itsct2.iContour);
|
||||
myassert(itsct.is_inner());
|
||||
assert(itsct.type == itsct2.type);
|
||||
assert(itsct.iContour == itsct2.iContour);
|
||||
assert(itsct.is_inner());
|
||||
const bool forward = itsct.is_low() == dir_is_next;
|
||||
// Do not append the first point.
|
||||
// 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 &itsct2 = il.intersections[iIntersection2];
|
||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||
myassert(itsct.is_inner());
|
||||
myassert(itsct2.is_inner());
|
||||
myassert(itsct.type != itsct2.type);
|
||||
myassert(itsct.iContour == iInnerContour);
|
||||
myassert(itsct.iContour == itsct2.iContour);
|
||||
assert(itsct.is_inner());
|
||||
assert(itsct2.is_inner());
|
||||
assert(itsct.type != itsct2.type);
|
||||
assert(itsct.iContour == iInnerContour);
|
||||
assert(itsct.iContour == itsct2.iContour);
|
||||
return forward ?
|
||||
segment_length(poly, itsct .iSegment, itsct.pos(), itsct2.iSegment, itsct2.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 &itsct2 = il.intersections[iIntersection2];
|
||||
const Polygon &poly = poly_with_offset.contour(iInnerContour);
|
||||
myassert(itsct.is_inner());
|
||||
myassert(itsct2.is_inner());
|
||||
myassert(itsct.type != itsct2.type);
|
||||
myassert(itsct.iContour == iInnerContour);
|
||||
myassert(itsct.iContour == itsct2.iContour);
|
||||
assert(itsct.is_inner());
|
||||
assert(itsct2.is_inner());
|
||||
assert(itsct.type != itsct2.type);
|
||||
assert(itsct.iContour == iInnerContour);
|
||||
assert(itsct.iContour == itsct2.iContour);
|
||||
// Do not append the first point.
|
||||
// out.points.push_back(Point(il.pos, itsct.pos));
|
||||
if (forward)
|
||||
|
@ -1042,10 +1062,10 @@ static inline float measure_outer_contour_slab(
|
|||
const SegmentIntersection &itsct = il.intersections[i_vline];
|
||||
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
|
||||
const Polygon &poly = poly_with_offset.contour((itsct.iContour);
|
||||
myassert(itsct.is_outer());
|
||||
myassert(itsct2.is_outer());
|
||||
myassert(itsct.type != itsct2.type);
|
||||
myassert(itsct.iContour == itsct2.iContour);
|
||||
assert(itsct.is_outer());
|
||||
assert(itsct2.is_outer());
|
||||
assert(itsct.type != itsct2.type);
|
||||
assert(itsct.iContour == itsct2.iContour);
|
||||
if (! itsct.is_outer() || ! itsct2.is_outer() || itsct.type == itsct2.type || itsct.iContour != itsct2.iContour)
|
||||
// Error, return zero area.
|
||||
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) {
|
||||
const SegmentedIntersectionLine &seg = segs[i_vline2];
|
||||
if (! seg.intersections.empty()) {
|
||||
myassert(seg.intersections.size() > 1);
|
||||
assert(seg.intersections.size() > 1);
|
||||
// Even number of intersections with the loops.
|
||||
myassert((seg.intersections.size() & 1) == 0);
|
||||
myassert(seg.intersections.front().type == SegmentIntersection::OUTER_LOW);
|
||||
assert((seg.intersections.size() & 1) == 0);
|
||||
assert(seg.intersections.front().type == SegmentIntersection::OUTER_LOW);
|
||||
for (size_t i = 0; i < seg.intersections.size(); ++ i) {
|
||||
const SegmentIntersection &intrsctn = seg.intersections[i];
|
||||
if (intrsctn.is_outer()) {
|
||||
myassert(intrsctn.is_low() || i > 0);
|
||||
assert(intrsctn.is_low() || i > 0);
|
||||
bool consumed = intrsctn.is_low() ?
|
||||
intrsctn.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 try_connect = false;
|
||||
if (going_up) {
|
||||
myassert(! intrsctn->consumed_vertical_up);
|
||||
myassert(i_intersection + 1 < seg.intersections.size());
|
||||
assert(! intrsctn->consumed_vertical_up);
|
||||
assert(i_intersection + 1 < seg.intersections.size());
|
||||
// Step back to the beginning of the vertical segment to mark it as consumed.
|
||||
if (intrsctn->is_inner()) {
|
||||
myassert(i_intersection > 0);
|
||||
assert(i_intersection > 0);
|
||||
-- intrsctn;
|
||||
-- i_intersection;
|
||||
}
|
||||
|
@ -1218,25 +1238,25 @@ static bool fill_hatching_segments_legacy(
|
|||
intrsctn->consumed_vertical_up = true;
|
||||
++ intrsctn;
|
||||
++ i_intersection;
|
||||
myassert(i_intersection < seg.intersections.size());
|
||||
assert(i_intersection < seg.intersections.size());
|
||||
} while (intrsctn->type != SegmentIntersection::OUTER_HIGH);
|
||||
if ((intrsctn - 1)->is_inner()) {
|
||||
// Step back.
|
||||
-- intrsctn;
|
||||
-- i_intersection;
|
||||
myassert(intrsctn->type == SegmentIntersection::INNER_HIGH);
|
||||
assert(intrsctn->type == SegmentIntersection::INNER_HIGH);
|
||||
try_connect = true;
|
||||
}
|
||||
} else {
|
||||
// Going down.
|
||||
myassert(intrsctn->is_high());
|
||||
myassert(i_intersection > 0);
|
||||
myassert(! (intrsctn - 1)->consumed_vertical_up);
|
||||
assert(intrsctn->is_high());
|
||||
assert(i_intersection > 0);
|
||||
assert(! (intrsctn - 1)->consumed_vertical_up);
|
||||
// Consume the complete vertical segment up to the outer contour.
|
||||
if (intrsctn->is_inner())
|
||||
intrsctn->consumed_vertical_up = true;
|
||||
do {
|
||||
myassert(i_intersection > 0);
|
||||
assert(i_intersection > 0);
|
||||
-- intrsctn;
|
||||
-- i_intersection;
|
||||
intrsctn->consumed_vertical_up = true;
|
||||
|
@ -1245,7 +1265,7 @@ static bool fill_hatching_segments_legacy(
|
|||
// Step back.
|
||||
++ intrsctn;
|
||||
++ i_intersection;
|
||||
myassert(intrsctn->type == SegmentIntersection::INNER_LOW);
|
||||
assert(intrsctn->type == SegmentIntersection::INNER_LOW);
|
||||
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) ?
|
||||
(distNext < distPrev) :
|
||||
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);
|
||||
if (skip) {
|
||||
// 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,
|
||||
// reset the current vertical line to pick a new starting point in the next round.
|
||||
myassert(intrsctn->is_outer());
|
||||
myassert(intrsctn->is_high() == going_up);
|
||||
assert(intrsctn->is_outer());
|
||||
assert(intrsctn->is_high() == going_up);
|
||||
pointLast = intrsctn->pos();
|
||||
polyline_current->points.push_back(pointLast);
|
||||
// Handle duplicate points and zero length segments.
|
||||
polyline_current->remove_duplicate_points();
|
||||
myassert(! polyline_current->has_duplicate_points());
|
||||
assert(! polyline_current->has_duplicate_points());
|
||||
// Handle nearly zero length edges.
|
||||
if (polyline_current->points.size() <= 1 ||
|
||||
(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) {
|
||||
// No need to translate, the absolute position is irrelevant.
|
||||
// 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);
|
||||
//FIXME rather simplify the paths to avoid very short edges?
|
||||
//myassert(! it->has_duplicate_points());
|
||||
//assert(! it->has_duplicate_points());
|
||||
it->remove_duplicate_points();
|
||||
}
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
// Verify, that there are no duplicate points in the sequence.
|
||||
for (Polyline &polyline : polylines_out)
|
||||
myassert(! polyline.has_duplicate_points());
|
||||
assert(! polyline.has_duplicate_points());
|
||||
#endif /* SLIC3R_DEBUG */
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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.
|
||||
FillRectilinear3_Internal::ExPolygonWithOffset poly_with_offset(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef slic3r_FillRectilinear2_hpp_
|
||||
#define slic3r_FillRectilinear2_hpp_
|
||||
#ifndef slic3r_FillRectilinear3_hpp_
|
||||
#define slic3r_FillRectilinear3_hpp_
|
||||
|
||||
#include "../libslic3r.h"
|
||||
|
||||
|
@ -80,4 +80,4 @@ protected:
|
|||
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif // slic3r_FillRectilinear2_hpp_
|
||||
#endif // slic3r_FillRectilinear3_hpp_
|
||||
|
|
|
@ -286,7 +286,7 @@ public:
|
|||
if (std::abs(det) > err)
|
||||
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,
|
||||
|
@ -297,4 +297,11 @@ public:
|
|||
Slic3r::Vector v2(p3 - p1);
|
||||
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*(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 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.
|
||||
struct PointHash {
|
||||
|
|
Loading…
Reference in a new issue