diff --git a/poly2tri/common/shapes.cc b/poly2tri/common/shapes.cc index e7130a5..e3a7a05 100644 --- a/poly2tri/common/shapes.cc +++ b/poly2tri/common/shapes.cc @@ -389,4 +389,21 @@ bool Triangle::IsCounterClockwise() const 0; } +bool IsDelaunay(const std::vector& triangles) +{ + for (const auto triangle : triangles) { + for (const auto other : triangles) { + if (triangle == other) { + continue; + } + for (int i = 0; i < 3; ++i) { + if (triangle->CircumcicleContains(*other->GetPoint(i))) { + return false; + } + } + } + } + return true; +} + } diff --git a/poly2tri/common/shapes.h b/poly2tri/common/shapes.h index 272aefd..f329c7f 100644 --- a/poly2tri/common/shapes.h +++ b/poly2tri/common/shapes.h @@ -324,6 +324,9 @@ inline void Triangle::IsInterior(bool b) interior_ = b; } +/// Is this set a valid delaunay triangulation? +bool IsDelaunay(const std::vector&); + } #endif diff --git a/unittest/main.cpp b/unittest/main.cpp index d247ae9..c47f0a5 100644 --- a/unittest/main.cpp +++ b/unittest/main.cpp @@ -2,18 +2,75 @@ #define BOOST_TEST_MODULE Poly2triTest #include #include +#include #include -BOOST_AUTO_TEST_CASE(BasicTest) { - std::vector polyline{ - new p2t::Point(0, 0), new p2t::Point(1, 0), new p2t::Point(1, 1), - }; - p2t::CDT cdt{polyline}; - cdt.Triangulate(); - const auto result = cdt.GetTriangles(); - assert(result.size() == 1); - BOOST_CHECK_EQUAL(*result[0]->GetPoint(0), *polyline[0]); - BOOST_CHECK_EQUAL(*result[0]->GetPoint(1), *polyline[1]); - BOOST_CHECK_EQUAL(*result[0]->GetPoint(2), *polyline[2]); - result[0]->DebugPrint(); +BOOST_AUTO_TEST_CASE(BasicTest) +{ + std::vector polyline{ + new p2t::Point(0, 0), + new p2t::Point(1, 0), + new p2t::Point(1, 1), + }; + p2t::CDT cdt{ polyline }; + cdt.Triangulate(); + const auto result = cdt.GetTriangles(); + BOOST_REQUIRE_EQUAL(result.size(), 1); + BOOST_CHECK_EQUAL(*result[0]->GetPoint(0), *polyline[0]); + BOOST_CHECK_EQUAL(*result[0]->GetPoint(1), *polyline[1]); + BOOST_CHECK_EQUAL(*result[0]->GetPoint(2), *polyline[2]); + BOOST_CHECK(p2t::IsDelaunay(result)); + for (const auto p : polyline) { + delete p; + } +} + +BOOST_AUTO_TEST_CASE(QuadTest) +{ + std::vector polyline{ new p2t::Point(0, 0), new p2t::Point(0, 1), + new p2t::Point(1, 1), new p2t::Point(1, 0) }; + p2t::CDT cdt{ polyline }; + cdt.Triangulate(); + const auto result = cdt.GetTriangles(); + BOOST_REQUIRE_EQUAL(result.size(), 2); + BOOST_CHECK(p2t::IsDelaunay(result)); + for (const auto p : polyline) { + delete p; + } +} + +BOOST_AUTO_TEST_CASE(TestbedFilesTest) +{ + for (const auto& filename : { "custom.dat", "diamond.dat", "star.dat", "test.dat" }) { + std::vector polyline; + // Load pointset from file + // Parse and tokenize data file + std::string line; + std::ifstream myfile(std::string("../testbed/data/") + filename); + if (!myfile.is_open()) { + myfile.open(std::string("testbed/data/") + filename); + } + BOOST_REQUIRE(myfile.is_open()); + while (!myfile.eof()) { + getline(myfile, line); + if (line.empty()) { + break; + } + std::istringstream iss(line); + std::vector tokens; + copy(std::istream_iterator(iss), std::istream_iterator(), + std::back_inserter>(tokens)); + double x = std::stod(tokens[0]); + double y = std::stod(tokens[1]); + polyline.push_back(new p2t::Point(x, y)); + } + p2t::CDT cdt{ polyline }; + cdt.Triangulate(); + const auto result = cdt.GetTriangles(); + BOOST_REQUIRE(result.size() * 3 > polyline.size()); + BOOST_CHECK_MESSAGE(p2t::IsDelaunay(result), filename + std::to_string(polyline.size())); + for (const auto p : polyline) { + delete p; + } + } }