mirror of
https://github.com/jhasse/poly2tri.git
synced 2024-12-02 02:03:30 +01:00
Merge pull request #43 from AndriyAndreyev/stability_fixes
Stability fixes
This commit is contained in:
commit
81612cb108
@ -262,6 +262,35 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// True if HoleAngle exceeds 90 degrees.
|
// True if HoleAngle exceeds 90 degrees.
|
||||||
|
// LargeHole_DontFill checks if the advancing front has a large hole.
|
||||||
|
// A "Large hole" is a triangle formed by a sequence of points in the advancing
|
||||||
|
// front where three neighbor points form a triangle.
|
||||||
|
// And angle between left-top, bottom, and right-top points is more than 90 degrees.
|
||||||
|
// The first part of the algorithm reviews only three neighbor points, e.g. named A, B, C.
|
||||||
|
// Additional part of this logic reviews a sequence of 5 points -
|
||||||
|
// additionally reviews one point before and one after the sequence of three (A, B, C),
|
||||||
|
// e.g. named X and Y.
|
||||||
|
// In this case, angles are XBC and ABY and this if angles are negative or more
|
||||||
|
// than 90 degrees LargeHole_DontFill returns true.
|
||||||
|
// But there is a configuration when ABC has a negative angle but XBC or ABY is less
|
||||||
|
// than 90 degrees and positive.
|
||||||
|
// Then function LargeHole_DontFill return false and initiates filling.
|
||||||
|
// This filling creates a triangle ABC and adds it to the advancing front.
|
||||||
|
// But in the case when angle ABC is negative this triangle goes inside the advancing front
|
||||||
|
// and can intersect previously created triangles.
|
||||||
|
// This triangle leads to making wrong advancing front and problems in triangulation in the future.
|
||||||
|
// Looks like such a triangle should not be created.
|
||||||
|
// The simplest way to check and fix it is to check an angle ABC.
|
||||||
|
// If it is negative LargeHole_DontFill should return true and
|
||||||
|
// not initiate creating the ABC triangle in the advancing front.
|
||||||
|
// X______A Y
|
||||||
|
// \ /
|
||||||
|
// \ /
|
||||||
|
// \ B /
|
||||||
|
// | /
|
||||||
|
// | /
|
||||||
|
// |/
|
||||||
|
// C
|
||||||
bool Sweep::LargeHole_DontFill(const Node* node) const {
|
bool Sweep::LargeHole_DontFill(const Node* node) const {
|
||||||
|
|
||||||
const Node* nextNode = node->next;
|
const Node* nextNode = node->next;
|
||||||
@ -269,6 +298,9 @@ bool Sweep::LargeHole_DontFill(const Node* node) const {
|
|||||||
if (!AngleExceeds90Degrees(node->point, nextNode->point, prevNode->point))
|
if (!AngleExceeds90Degrees(node->point, nextNode->point, prevNode->point))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (AngleIsNegative(node->point, nextNode->point, prevNode->point))
|
||||||
|
return true;
|
||||||
|
|
||||||
// Check additional points on front.
|
// Check additional points on front.
|
||||||
const Node* next2Node = nextNode->next;
|
const Node* next2Node = nextNode->next;
|
||||||
// "..Plus.." because only want angles on same side as point being added.
|
// "..Plus.." because only want angles on same side as point being added.
|
||||||
@ -283,6 +315,11 @@ bool Sweep::LargeHole_DontFill(const Node* node) const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sweep::AngleIsNegative(const Point* origin, const Point* pa, const Point* pb) const {
|
||||||
|
const double angle = Angle(origin, pa, pb);
|
||||||
|
return angle < 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool Sweep::AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const {
|
bool Sweep::AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const {
|
||||||
const double angle = Angle(origin, pa, pb);
|
const double angle = Angle(origin, pa, pb);
|
||||||
return ((angle > PI_div2) || (angle < -PI_div2));
|
return ((angle > PI_div2) || (angle < -PI_div2));
|
||||||
|
@ -171,6 +171,7 @@ private:
|
|||||||
// Decision-making about when to Fill hole.
|
// Decision-making about when to Fill hole.
|
||||||
// Contributed by ToolmakerSteve2
|
// Contributed by ToolmakerSteve2
|
||||||
bool LargeHole_DontFill(const Node* node) const;
|
bool LargeHole_DontFill(const Node* node) const;
|
||||||
|
bool AngleIsNegative(const Point* origin, const Point* pa, const Point* pb) const;
|
||||||
bool AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const;
|
bool AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const;
|
||||||
bool AngleExceedsPlus90DegreesOrIsNegative(const Point* origin, const Point* pa, const Point* pb) const;
|
bool AngleExceedsPlus90DegreesOrIsNegative(const Point* origin, const Point* pa, const Point* pb) const;
|
||||||
double Angle(const Point* origin, const Point* pa, const Point* pb) const;
|
double Angle(const Point* origin, const Point* pa, const Point* pb) const;
|
||||||
|
14
testbed/data/stalactite.dat
Normal file
14
testbed/data/stalactite.dat
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
450 2250
|
||||||
|
450 1750
|
||||||
|
400 1700
|
||||||
|
350 1650
|
||||||
|
350 500
|
||||||
|
1050 1700
|
||||||
|
HOLE
|
||||||
|
980 1636
|
||||||
|
950 1600
|
||||||
|
650 1230
|
||||||
|
625 1247
|
||||||
|
600 1250
|
||||||
|
591 1350
|
||||||
|
550 2050
|
@ -188,6 +188,41 @@ BOOST_AUTO_TEST_CASE(PolygonTest03)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(PolygonTest04)
|
||||||
|
{
|
||||||
|
std::vector<p2t::Point*> polyline {
|
||||||
|
new p2t::Point(450, 2250),
|
||||||
|
new p2t::Point(450, 1750),
|
||||||
|
new p2t::Point(400, 1700),
|
||||||
|
new p2t::Point(350, 1650),
|
||||||
|
new p2t::Point(350, 500),
|
||||||
|
new p2t::Point(1050, 1700)
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<p2t::Point*> hole {
|
||||||
|
new p2t::Point(980, 1636),
|
||||||
|
new p2t::Point(950, 1600),
|
||||||
|
new p2t::Point(650, 1230),
|
||||||
|
new p2t::Point(625, 1247),
|
||||||
|
new p2t::Point(600, 1250),
|
||||||
|
new p2t::Point(591, 1350),
|
||||||
|
new p2t::Point(550, 2050)
|
||||||
|
};
|
||||||
|
|
||||||
|
p2t::CDT cdt{ polyline };
|
||||||
|
cdt.AddHole(hole);
|
||||||
|
|
||||||
|
BOOST_CHECK_NO_THROW(cdt.Triangulate());
|
||||||
|
const auto result = cdt.GetTriangles();
|
||||||
|
BOOST_REQUIRE_EQUAL(result.size(), 13);
|
||||||
|
for (const auto p : polyline) {
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
for (const auto p : hole) {
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(TestbedFilesTest)
|
BOOST_AUTO_TEST_CASE(TestbedFilesTest)
|
||||||
{
|
{
|
||||||
for (const auto& filename : { "custom.dat", "diamond.dat", "star.dat", "test.dat" }) {
|
for (const auto& filename : { "custom.dat", "diamond.dat", "star.dat", "test.dat" }) {
|
||||||
|
Loading…
Reference in New Issue
Block a user