From 26349b30c5ea31a457fcad18e8c8a14353db9582 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 17 Oct 2016 18:06:38 +0200 Subject: [PATCH] Fixed a bug in EdgeGrid for horizontal or vertical lines ending at the grid lines. --- xs/src/libslic3r/EdgeGrid.cpp | 301 +++++++++++++++++++++++++++++++++- xs/src/libslic3r/EdgeGrid.hpp | 27 ++- 2 files changed, 315 insertions(+), 13 deletions(-) diff --git a/xs/src/libslic3r/EdgeGrid.cpp b/xs/src/libslic3r/EdgeGrid.cpp index 54cda9f8c..496089b24 100644 --- a/xs/src/libslic3r/EdgeGrid.cpp +++ b/xs/src/libslic3r/EdgeGrid.cpp @@ -158,6 +158,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) if (p1.x < p2.x) { int64_t ex = int64_t((ix + 1)*m_resolution - p1.x) * int64_t(dy); if (p1.y < p2.y) { + // x positive, y positive int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx); do { assert(ix <= ixb && iy <= iyb); @@ -182,6 +183,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) } while (ix != ixb || iy != iyb); } else { + // x positive, y non positive int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx); do { assert(ix <= ixb && iy >= iyb); @@ -202,6 +204,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) else { int64_t ex = int64_t(p1.x - ix*m_resolution) * int64_t(dy); if (p1.y < p2.y) { + // x non positive, y positive int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx); do { assert(ix >= ixb && iy <= iyb); @@ -220,6 +223,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) } while (ix != ixb || iy != iyb); } else { + // x non positive, y non positive int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx); do { assert(ix >= ixb && iy >= iyb); @@ -229,10 +233,17 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) ix -= 1; } else if (ex == ey) { - ex = int64_t(dy) * m_resolution; - ey = int64_t(dx) * m_resolution; - ix -= 1; - iy -= 1; + // The lower edge of a grid cell belongs to the cell. + // Handle the case where the ray may cross the lower left corner of a cell in a general case, + // or a left or lower edge in a degenerate case (horizontal or vertical line). + if (dx > 0) { + ex = int64_t(dy) * m_resolution; + ix -= 1; + } + if (dy > 0) { + ey = int64_t(dx) * m_resolution; + iy -= 1; + } } else { assert(ex > ey); @@ -291,6 +302,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) if (p1.x < p2.x) { int64_t ex = int64_t((ix + 1)*m_resolution - p1.x) * int64_t(dy); if (p1.y < p2.y) { + // x positive, y positive int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx); do { assert(ix <= ixb && iy <= iyb); @@ -315,6 +327,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) } while (ix != ixb || iy != iyb); } else { + // x positive, y non positive int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx); do { assert(ix <= ixb && iy >= iyb); @@ -335,6 +348,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) else { int64_t ex = int64_t(p1.x - ix*m_resolution) * int64_t(dy); if (p1.y < p2.y) { + // x non positive, y positive int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx); do { assert(ix >= ixb && iy <= iyb); @@ -353,6 +367,7 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) } while (ix != ixb || iy != iyb); } else { + // x non positive, y non positive int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx); do { assert(ix >= ixb && iy >= iyb); @@ -362,10 +377,17 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) ix -= 1; } else if (ex == ey) { - ex = int64_t(dy) * m_resolution; - ey = int64_t(dx) * m_resolution; - ix -= 1; - iy -= 1; + // The lower edge of a grid cell belongs to the cell. + // Handle the case where the ray may cross the lower left corner of a cell in a general case, + // or a left or lower edge in a degenerate case (horizontal or vertical line). + if (dx > 0) { + ex = int64_t(dy) * m_resolution; + ix -= 1; + } + if (dy > 0) { + ey = int64_t(dx) * m_resolution; + iy -= 1; + } } else { assert(ex > ey); @@ -381,6 +403,269 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution) } } +#if 0 +// Divide, round to a grid coordinate. +// Divide x/y, round down. y is expected to be positive. +static inline coord_t div_floor(coord_t x, coord_t y) +{ + assert(y > 0); + return ((x < 0) ? (x - y + 1) : x) / y; +} + +// Walk the polyline, test whether any lines of this polyline does not intersect +// any line stored into the grid. +bool EdgeGrid::Grid::intersect(const MultiPoint &polyline, bool closed) +{ + size_t n = polyline.points.size(); + if (closed) + ++ n; + for (size_t i = 0; i < n; ++ i) { + size_t j = i + 1; + if (j == polyline.points.size()) + j = 0; + Point p1src = polyline.points[i]; + Point p2src = polyline.points[j]; + Point p1 = p1src; + Point p2 = p2src; + // Discretize the line segment p1, p2. + p1.x -= m_bbox.min.x; + p1.y -= m_bbox.min.y; + p2.x -= m_bbox.min.x; + p2.y -= m_bbox.min.y; + // Get the cells of the end points. + coord_t ix = div_floor(p1.x, m_resolution); + coord_t iy = div_floor(p1.y, m_resolution); + coord_t ixb = div_floor(p2.x, m_resolution); + coord_t iyb = div_floor(p2.y, m_resolution); +// assert(ix >= 0 && ix < m_cols); +// assert(iy >= 0 && iy < m_rows); +// assert(ixb >= 0 && ixb < m_cols); +// assert(iyb >= 0 && iyb < m_rows); + // Account for the end points. + if (line_cell_intersect(p1src, p2src, m_cells[iy*m_cols + ix])) + return true; + if (ix == ixb && iy == iyb) + // Both ends fall into the same cell. + continue; + // Raster the centeral part of the line. + coord_t dx = std::abs(p2.x - p1.x); + coord_t dy = std::abs(p2.y - p1.y); + if (p1.x < p2.x) { + int64_t ex = int64_t((ix + 1)*m_resolution - p1.x) * int64_t(dy); + if (p1.y < p2.y) { + int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx); + do { + assert(ix <= ixb && iy <= iyb); + if (ex < ey) { + ey -= ex; + ex = int64_t(dy) * m_resolution; + ix += 1; + } + else if (ex == ey) { + ex = int64_t(dy) * m_resolution; + ey = int64_t(dx) * m_resolution; + ix += 1; + iy += 1; + } + else { + assert(ex > ey); + ex -= ey; + ey = int64_t(dx) * m_resolution; + iy += 1; + } + if (line_cell_intersect(p1src, p2src, m_cells[iy*m_cols + ix])) + return true; + } while (ix != ixb || iy != iyb); + } + else { + int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx); + do { + assert(ix <= ixb && iy >= iyb); + if (ex <= ey) { + ey -= ex; + ex = int64_t(dy) * m_resolution; + ix += 1; + } + else { + ex -= ey; + ey = int64_t(dx) * m_resolution; + iy -= 1; + } + if (line_cell_intersect(p1src, p2src, m_cells[iy*m_cols + ix])) + return true; + } while (ix != ixb || iy != iyb); + } + } + else { + int64_t ex = int64_t(p1.x - ix*m_resolution) * int64_t(dy); + if (p1.y < p2.y) { + int64_t ey = int64_t((iy + 1)*m_resolution - p1.y) * int64_t(dx); + do { + assert(ix >= ixb && iy <= iyb); + if (ex < ey) { + ey -= ex; + ex = int64_t(dy) * m_resolution; + ix -= 1; + } + else { + assert(ex >= ey); + ex -= ey; + ey = int64_t(dx) * m_resolution; + iy += 1; + } + if (line_cell_intersect(p1src, p2src, m_cells[iy*m_cols + ix])) + return true; + } while (ix != ixb || iy != iyb); + } + else { + int64_t ey = int64_t(p1.y - iy*m_resolution) * int64_t(dx); + do { + assert(ix >= ixb && iy >= iyb); + if (ex < ey) { + ey -= ex; + ex = int64_t(dy) * m_resolution; + ix -= 1; + } + else if (ex == ey) { + if (dx > 0) { + ex = int64_t(dy) * m_resolution; + ix -= 1; + } + if (dy > 0) { + ey = int64_t(dx) * m_resolution; + iy -= 1; + } + } + else { + assert(ex > ey); + ex -= ey; + ey = int64_t(dx) * m_resolution; + iy -= 1; + } + if (line_cell_intersect(p1src, p2src, m_cells[iy*m_cols + ix])) + return true; + } while (ix != ixb || iy != iyb); + } + } + } + return false; +} + +bool EdgeGrid::Grid::line_cell_intersect(const Point &p1a, const Point &p2a, const Cell &cell) +{ + BoundingBox bbox(p1a, p1a); + bbox.merge(p2a); + int64_t va_x = p2a.x - p1a.x; + int64_t va_y = p2a.y - p1a.y; + for (size_t i = cell.begin; i != cell.end; ++ i) { + const std::pair &cell_data = m_cell_data[i]; + // Contour indexed by the ith line of this cell. + const Slic3r::Points &contour = *m_contours[cell_data.first]; + // Point indices in contour indexed by the ith line of this cell. + size_t idx1 = cell_data.second; + size_t idx2 = idx1 + 1; + if (idx2 == contour.size()) + idx2 = 0; + // The points of the ith line of this cell and its bounding box. + const Point &p1b = contour[idx1]; + const Point &p2b = contour[idx2]; + BoundingBox bbox2(p1b, p1b); + bbox2.merge(p2b); + // Do the bounding boxes intersect? + if (! bbox.overlap(bbox2)) + continue; + // Now intersect the two line segments using exact arithmetics. + int64_t w1_x = p1b.x - p1a.x; + int64_t w1_y = p1b.y - p1a.y; + int64_t w2_x = p2b.x - p1a.x; + int64_t w2_y = p2b.y - p1a.y; + int64_t side1 = va_x * w1_y - va_y * w1_x; + int64_t side2 = va_x * w2_y - va_y * w2_x; + if (side1 == side2 && side1 != 0) + // The line segments don't intersect. + continue; + w1_x = p1a.x - p1b.x; + w1_y = p1a.y - p1b.y; + w2_x = p2a.x - p1b.x; + w2_y = p2a.y - p1b.y; + int64_t vb_x = p2b.x - p1b.x; + int64_t vb_y = p2b.y - p1b.y; + side1 = vb_x * w1_y - vb_y * w1_x; + side2 = vb_x * w2_y - vb_y * w2_x; + if (side1 == side2 && side1 != 0) + // The line segments don't intersect. + continue; + // The line segments intersect. + return true; + } + // The line segment (p1a, p2a) does not intersect any of the line segments inside this cell. + return false; +} + +// Test, whether a point is inside a contour. +bool EdgeGrid::Grid::inside(const Point &pt_src) +{ + Point p = pt_src; + p.x -= m_bbox.min.x; + p.y -= m_bbox.min.y; + // Get the cell of the point. + if (p.x < 0 || p.y < 0) + return false; + coord_t ix = p.x / m_resolution; + coord_t iy = p.y / m_resolution; + if (ix >= this->m_cols || iy >= this->m_rows) + return false; + + size_t i_closest = (size_t)-1; + bool inside = false; + + { + // Hit in the first cell? + const Cell &cell = m_cells[iy * m_cols + ix]; + for (size_t i = cell.begin; i != cell.end; ++ i) { + const std::pair &cell_data = m_cell_data[i]; + // Contour indexed by the ith line of this cell. + const Slic3r::Points &contour = *m_contours[cell_data.first]; + // Point indices in contour indexed by the ith line of this cell. + size_t idx1 = cell_data.second; + size_t idx2 = idx1 + 1; + if (idx2 == contour.size()) + idx2 = 0; + const Point &p1 = contour[idx1]; + const Point &p2 = contour[idx2]; + if (p1.y < p2.y) { + if (p.y < p1.y || p.y > p2.y) + continue; + //FIXME finish this! + int64_t vx = 0;// pt_src + //FIXME finish this! + int64_t det = 0; + } else if (p1.y != p2.y) { + assert(p1.y > p2.y); + if (p.y < p2.y || p.y > p1.y) + continue; + } else { + assert(p1.y == p2.y); + if (p1.y == p.y) { + if (p.x >= p1.x && p.x <= p2.x) + // On the segment. + return true; + // Before or after the segment. + size_t idx0 = idx1 - 1; + size_t idx2 = idx1 + 1; + if (idx0 == (size_t)-1) + idx0 = contour.size() - 1; + if (idx2 == contour.size()) + idx2 = 0; + } + } + } + } + + //FIXME This code follows only a single direction. Better to follow the direction closest to the bounding box. +} +#endif + template struct PropagateDanielssonSingleStep { PropagateDanielssonSingleStep(float *aL, unsigned char *asigns, size_t astride, coord_t aresolution) : diff --git a/xs/src/libslic3r/EdgeGrid.hpp b/xs/src/libslic3r/EdgeGrid.hpp index 959165866..626a430cd 100644 --- a/xs/src/libslic3r/EdgeGrid.hpp +++ b/xs/src/libslic3r/EdgeGrid.hpp @@ -22,6 +22,19 @@ struct Grid void create(const ExPolygons &expolygons, coord_t resolution); void create(const ExPolygonCollection &expolygons, coord_t resolution); +#if 0 + // Test, whether the edges inside the grid intersect with the polygons provided. + bool intersect(const MultiPoint &polyline, bool closed); + bool intersect(const Polygon &polygon) { return intersect(static_cast(polygon), true); } + bool intersect(const Polygons &polygons) { for (size_t i = 0; i < polygons.size(); ++ i) if (intersect(polygons[i])) return true; return false; } + bool intersect(const ExPolygon &expoly) { if (intersect(expoly.contour)) return true; for (size_t i = 0; i < expoly.holes.size(); ++ i) if (intersect(expoly.holes[i])) return true; return false; } + bool intersect(const ExPolygons &expolygons) { for (size_t i = 0; i < expolygons.size(); ++ i) if (intersect(expolygons[i])) return true; return false; } + bool intersect(const ExPolygonCollection &expolygons) { return intersect(expolygons.expolygons); } + + // Test, whether a point is inside a contour. + bool inside(const Point &pt); +#endif + // Fill in a rough m_signed_distance_field from the edge grid. // The rough SDF is used by signed_distance() for distances outside of the search_radius. void calculate_sdf(); @@ -42,7 +55,16 @@ struct Grid const size_t cols() const { return m_cols; } protected: + struct Cell { + Cell() : begin(0), end(0) {} + size_t begin; + size_t end; + }; + void create_from_m_contours(coord_t resolution); +#if 0 + bool line_cell_intersect(const Point &p1, const Point &p2, const Cell &cell); +#endif // Bounding box around the contours. BoundingBox m_bbox; @@ -59,11 +81,6 @@ protected: // Referencing a contour and a line segment of m_contours. std::vector > m_cell_data; - struct Cell { - Cell() : begin(0), end(0) {} - size_t begin; - size_t end; - }; // Full grid of cells. std::vector m_cells;