Fixed a bug in EdgeGrid for horizontal or vertical lines ending at the grid lines.

This commit is contained in:
bubnikv 2016-10-17 18:06:38 +02:00
parent c0956dbd34
commit 26349b30c5
2 changed files with 315 additions and 13 deletions

View File

@ -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<size_t, size_t> &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<size_t, size_t> &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<const int INCX, const int INCY>
struct PropagateDanielssonSingleStep {
PropagateDanielssonSingleStep(float *aL, unsigned char *asigns, size_t astride, coord_t aresolution) :

View File

@ -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<const MultiPoint&>(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<std::pair<size_t, size_t> > m_cell_data;
struct Cell {
Cell() : begin(0), end(0) {}
size_t begin;
size_t end;
};
// Full grid of cells.
std::vector<Cell> m_cells;