Further implementation of FillRectilinear3.

This commit is contained in:
bubnikv 2017-07-28 15:47:59 +02:00
parent 137aab9631
commit 812a2c7cbd
5 changed files with 237 additions and 213 deletions

View file

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

View file

@ -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 &params, 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(

View file

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

View file

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

View file

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