mirror of
https://github.com/jhasse/poly2tri.git
synced 2024-11-05 22:09:52 +01:00
19ec7c78a1
This is from the case I originally got to trigger the problem. We could probably boil it down to something smaller (by temporarily reverting the Orient2d change to make sure the failure still occurs) but this doesn't seem too bloated for a unit test as-is.
154 lines
4.4 KiB
C++
154 lines
4.4 KiB
C++
#if !defined(_WIN32) && !defined(BOOST_TEST_DYN_LINK)
|
|
#define BOOST_TEST_DYN_LINK
|
|
#endif
|
|
#define BOOST_TEST_MODULE Poly2triTest
|
|
|
|
#include <poly2tri/poly2tri.h>
|
|
|
|
#include <boost/filesystem/path.hpp>
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <iterator>
|
|
#include <stdexcept>
|
|
|
|
BOOST_AUTO_TEST_CASE(BasicTest)
|
|
{
|
|
std::vector<p2t::Point*> polyline{
|
|
new p2t::Point(0, 0),
|
|
new p2t::Point(1, 0),
|
|
new p2t::Point(1, 1),
|
|
};
|
|
p2t::CDT cdt{ polyline };
|
|
BOOST_CHECK_NO_THROW(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<p2t::Point*> 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 };
|
|
BOOST_CHECK_NO_THROW(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(NarrowQuadTest)
|
|
{
|
|
// Very narrow quad that used to demonstrate a failure case during
|
|
// triangulation
|
|
std::vector<p2t::Point*> polyline {
|
|
new p2t::Point(0.0, 0.0),
|
|
new p2t::Point(1.0e-05, 0.0),
|
|
new p2t::Point(1.1e-04, 3.0e-07),
|
|
new p2t::Point(1.0e-04, 3.0e-07)
|
|
};
|
|
p2t::CDT cdt{ polyline };
|
|
BOOST_CHECK_NO_THROW(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(ConcaveBoundaryTest)
|
|
{
|
|
// Concave-by-less-than-epsilon boundaries used to potentially fail
|
|
// during triangulation
|
|
const double eps = 1e-15; // This gave EdgeEvent - null triangle
|
|
std::vector<p2t::Point*> polyline {
|
|
new p2t::Point(0,0),
|
|
new p2t::Point(0.5,eps),
|
|
new p2t::Point(1,0),
|
|
new p2t::Point(1-eps,0.836541),
|
|
new p2t::Point(1,2),
|
|
new p2t::Point(.46,1.46+eps),
|
|
new p2t::Point(0,1),
|
|
new p2t::Point(eps,0.5)
|
|
};
|
|
|
|
const double r2o4 = std::sqrt(2.)/4;
|
|
std::vector<p2t::Point*> hole {
|
|
new p2t::Point(0.5+r2o4,0.5),
|
|
new p2t::Point(0.5,0.5+r2o4),
|
|
new p2t::Point(0.5-r2o4,0.5),
|
|
new p2t::Point(0.5-eps,0.5-r2o4)
|
|
};
|
|
|
|
std::vector<p2t::Point> interior_points
|
|
{{0.21,0.79},{0.21,0.21},{0.79,0.21}};
|
|
|
|
p2t::CDT cdt{ polyline };
|
|
cdt.AddHole(hole);
|
|
|
|
for (auto & p : interior_points)
|
|
cdt.AddPoint(&p);
|
|
|
|
BOOST_CHECK_NO_THROW(cdt.Triangulate());
|
|
const auto result = cdt.GetTriangles();
|
|
BOOST_REQUIRE_EQUAL(result.size(), 18);
|
|
BOOST_CHECK(p2t::IsDelaunay(result));
|
|
for (const auto p : polyline) {
|
|
delete p;
|
|
}
|
|
for (const auto p : hole) {
|
|
delete p;
|
|
}
|
|
}
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(TestbedFilesTest)
|
|
{
|
|
for (const auto& filename : { "custom.dat", "diamond.dat", "star.dat", "test.dat" }) {
|
|
std::vector<p2t::Point*> polyline;
|
|
// Load pointset from file
|
|
// Parse and tokenize data file
|
|
std::string line;
|
|
#ifndef P2T_BASE_DIR
|
|
const auto basedir = boost::filesystem::path(__FILE__).remove_filename().parent_path();
|
|
#else
|
|
const auto basedir = boost::filesystem::path(P2T_BASE_DIR);
|
|
#endif
|
|
const auto datafile = basedir / boost::filesystem::path("testbed/data") / boost::filesystem::path(filename);
|
|
std::ifstream myfile(datafile.string());
|
|
BOOST_REQUIRE(myfile.is_open());
|
|
while (!myfile.eof()) {
|
|
getline(myfile, line);
|
|
if (line.empty()) {
|
|
break;
|
|
}
|
|
std::istringstream iss(line);
|
|
std::vector<std::string> tokens;
|
|
copy(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>(),
|
|
std::back_inserter<std::vector<std::string>>(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 };
|
|
BOOST_CHECK_NO_THROW(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;
|
|
}
|
|
}
|
|
}
|