Fixes of MutablePolygon
This commit is contained in:
parent
1c2d264570
commit
00295919bf
@ -122,7 +122,7 @@ static bool clip_narrow_corner(
|
|||||||
} else {
|
} else {
|
||||||
assert(backward == Free);
|
assert(backward == Free);
|
||||||
p02 = it0.prev()->cast<int64_t>();
|
p02 = it0.prev()->cast<int64_t>();
|
||||||
if (cross2(p0 - p2, p02 - p2) > 0)
|
if (cross2(p02 - p2, p0 - p2) > 0)
|
||||||
backward = Blocked;
|
backward = Blocked;
|
||||||
else {
|
else {
|
||||||
// New clipping edge lenght.
|
// New clipping edge lenght.
|
||||||
@ -141,14 +141,37 @@ static bool clip_narrow_corner(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(dist2_current <= shortcut_length2);
|
||||||
|
assert(polygon.size() >= 2);
|
||||||
|
assert(polygon.size() == 2 || forward == Blocked || forward == Far);
|
||||||
|
assert(polygon.size() == 2 || backward == Blocked || backward == Far);
|
||||||
|
|
||||||
if (polygon.size() <= 3) {
|
if (polygon.size() <= 3) {
|
||||||
// A hole degenerated to an empty polygon, or a tiny triangle remained.
|
// A hole degenerated to an empty polygon, or a tiny triangle remained.
|
||||||
assert(polygon.size() < 3 || (forward == Blocked && backward == Blocked) || (forward == Far && backward == Far));
|
bool blocked = forward == Blocked || backward == Blocked;
|
||||||
if (polygon.size() < 3 || forward == Far) {
|
assert(polygon.size() < 3 ||
|
||||||
assert(polygon.size() < 3 || dist2_current <= shortcut_length2);
|
// Remaining triangle is CCW oriented. Both sides must be "blocked", but the other side may have not been
|
||||||
|
// updated after the the p02 / p22 became united into a single point.
|
||||||
|
blocked ||
|
||||||
|
// Remaining triangle is concave, however both of its arms are long.
|
||||||
|
(forward == Far && backward == Far));
|
||||||
|
#ifndef _NDEBUG
|
||||||
|
if (polygon.size() == 3) {
|
||||||
|
// Verify that the remaining triangle is CCW or CW.
|
||||||
|
p02 = it0.prev()->cast<int64_t>();
|
||||||
|
p22 = it2.next()->cast<int64_t>();
|
||||||
|
assert(p02 == p22);
|
||||||
|
auto orient1 = cross2(p02 - p2, p0 - p2);
|
||||||
|
auto orient2 = cross2(p2 - p0, p22 - p0);
|
||||||
|
assert(orient1 > 0 == blocked);
|
||||||
|
assert(orient2 > 0 == blocked);
|
||||||
|
}
|
||||||
|
#endif // _NDEBUG
|
||||||
|
if (polygon.size() < 3 || (forward == Far && backward == Far)) {
|
||||||
polygon.clear();
|
polygon.clear();
|
||||||
} else {
|
} else {
|
||||||
// The remaining triangle is CCW oriented, keep it.
|
// The remaining triangle is CCW oriented, keep it.
|
||||||
|
assert(forward == Blocked || backward == Blocked);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -168,7 +191,7 @@ static bool clip_narrow_corner(
|
|||||||
} else if (forward == Blocked || backward == Blocked) {
|
} else if (forward == Blocked || backward == Blocked) {
|
||||||
// One side is far, the other blocked.
|
// One side is far, the other blocked.
|
||||||
assert(forward == Far || backward == Far);
|
assert(forward == Far || backward == Far);
|
||||||
if (backward == Far) {
|
if (forward == Far) {
|
||||||
// Sort, so we will clip the 1st edge.
|
// Sort, so we will clip the 1st edge.
|
||||||
std::swap(p0, p2);
|
std::swap(p0, p2);
|
||||||
std::swap(p02, p22);
|
std::swap(p02, p22);
|
||||||
@ -177,6 +200,10 @@ static bool clip_narrow_corner(
|
|||||||
// Circle intersects a line at two points, however because |p2 - p0| < shortcut_length,
|
// Circle intersects a line at two points, however because |p2 - p0| < shortcut_length,
|
||||||
// only the second intersection is valid. Because |p2 - p02| > shortcut_length, such
|
// only the second intersection is valid. Because |p2 - p02| > shortcut_length, such
|
||||||
// intersection should always be found on (p0, p02).
|
// intersection should always be found on (p0, p02).
|
||||||
|
#ifndef NDEBUG
|
||||||
|
auto dfar2 = (p02 - p2).squaredNorm();
|
||||||
|
assert(dfar2 >= shortcut_length2);
|
||||||
|
#endif // NDEBUG
|
||||||
const Vec2d v = (p02 - p0).cast<double>();
|
const Vec2d v = (p02 - p0).cast<double>();
|
||||||
const Vec2d d = (p0 - p2).cast<double>();
|
const Vec2d d = (p0 - p2).cast<double>();
|
||||||
const double a = v.squaredNorm();
|
const double a = v.squaredNorm();
|
||||||
@ -273,15 +300,17 @@ void smooth_outward(MutablePolygon &polygon, coord_t clip_dist_scaled)
|
|||||||
Point pt_new = p1 + (t * v2d).cast<coord_t>();
|
Point pt_new = p1 + (t * v2d).cast<coord_t>();
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
double d2new = (pt_new - (swap ? p2 : p0)).cast<double>().squaredNorm();
|
double d2new = (pt_new - (swap ? p2 : p0)).cast<double>().squaredNorm();
|
||||||
assert(std::abs(d2new - clip_dist_scaled2) < sqr(10. * SCALED_EPSILON));
|
assert(std::abs(d2new - clip_dist_scaled2) < 1e-5 * clip_dist_scaled2);
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
it2.insert(pt_new);
|
it2.insert(pt_new);
|
||||||
} else {
|
} else {
|
||||||
// Cut the corner with a line perpendicular to the bisector.
|
// Cut the corner with a line perpendicular to the bisector.
|
||||||
double t = sqrt(0.25 * clip_dist_scaled2 / d2);
|
double t = sqrt(0.25 * clip_dist_scaled2 / d2);
|
||||||
|
double t2 = t * lv1 / lv2;
|
||||||
assert(t > 0. && t < 1.);
|
assert(t > 0. && t < 1.);
|
||||||
Point p0 = p1 + (v1d * t).cast<coord_t>();
|
assert(t2 > 0. && t2 < 1.);
|
||||||
Point p2 = p1 + (v2d * (t * lv2 / lv1)).cast<coord_t>();
|
Point p0 = p1 + (v1d * t ).cast<coord_t>();
|
||||||
|
Point p2 = p1 + (v2d * t2).cast<coord_t>();
|
||||||
if (swap)
|
if (swap)
|
||||||
std::swap(p0, p2);
|
std::swap(p0, p2);
|
||||||
it2.insert(p2).insert(p0);
|
it2.insert(p2).insert(p0);
|
||||||
|
@ -85,7 +85,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void advance_front() {
|
void advance_front() {
|
||||||
assert(!this->empty());
|
assert(! this->empty());
|
||||||
if (m_begin == m_end)
|
if (m_begin == m_end)
|
||||||
this->make_empty();
|
this->make_empty();
|
||||||
else
|
else
|
||||||
@ -93,7 +93,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void retract_back() {
|
void retract_back() {
|
||||||
assert(!this->empty());
|
assert(! this->empty());
|
||||||
if (m_begin == m_end)
|
if (m_begin == m_end)
|
||||||
this->make_empty();
|
this->make_empty();
|
||||||
else
|
else
|
||||||
@ -101,13 +101,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
MutablePolygon::iterator remove_front(MutablePolygon::iterator it) {
|
MutablePolygon::iterator remove_front(MutablePolygon::iterator it) {
|
||||||
if (m_begin == it)
|
if (! this->empty() && m_begin == it)
|
||||||
this->advance_front();
|
this->advance_front();
|
||||||
return it.remove();
|
return it.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
MutablePolygon::iterator remove_back(MutablePolygon::iterator it) {
|
MutablePolygon::iterator remove_back(MutablePolygon::iterator it) {
|
||||||
if (m_end == it)
|
if (! this->empty() && m_end == it)
|
||||||
this->retract_back();
|
this->retract_back();
|
||||||
return it.remove();
|
return it.remove();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user