-
Notifications
You must be signed in to change notification settings - Fork 52
Valid Solid shells cannot be converted to CGAL polyhedra #225
Description
Many valid Solids contain "pinched" or self-touching shells where the existing algorithm to convert a TriangulatedSurface to a CGAL polyhedron produces a non-manifold point. Since CGAL's combinatorial maps cannot represent non-manifold points, this causes construction to fail.
These problem geometries can easily be produced as algorithm results; the corefinement code will solve this by duplicating the pinch vertices so as to hide the pinch from the combinatorial map. Once recomposed, these Geometries cannot be decomposed again without triggering the problem.
Here are three test cases which demonstrate the problem. The problem geometry is the same in all tests; in the third test it is produced from inputs to difference3D, but the same geometry can be produced directly from WKT, as demonstrated in the first two tests.
BOOST_AUTO_TEST_SUITE( SFCGAL_algorithm_GL3D_514_toPolyhedron_3 )
// Most direct GL3D-514 test: invoke toPolyhedron_3 directly on a problem geometry.
BOOST_AUTO_TEST_CASE( GL3D514test_toPolyhedron_3 /*, *boost::unit_test::disabled() */ )
{
std::cout << "GL3D514test_toPolyhedron_3" << std::endl;
std::auto_ptr<SFCGAL::Geometry> tin = SFCGAL::io::readWkt("TIN(((0.00000 2.00000 0.00000,-1.00000 2.00000 1.00000,1.00000 2.00000 1.00000,0.00000 2.00000 0.00000)),"
"((1.00000 2.00000 1.00000,1.00000 2.00000 -1.00000,0.00000 2.00000 0.00000,1.00000 2.00000 1.00000)),"
"((-1.00000 2.00000 1.00000,0.00000 1.00000 1.00000,1.00000 2.00000 1.00000,-1.00000 2.00000 1.00000)),"
"((0.00000 2.00000 0.00000,-1.00000 2.00000 -1.00000,-1.00000 2.00000 1.00000,0.00000 2.00000 0.00000)),"
"((1.00000 2.00000 -1.00000,-1.00000 2.00000 -1.00000,0.00000 2.00000 0.00000,1.00000 2.00000 -1.00000)),"
"((1.00000 2.00000 1.00000,1.00000 1.00000 0.00000,1.00000 2.00000 -1.00000,1.00000 2.00000 1.00000)),"
"((0.00000 1.00000 1.00000,1.00000 0.00000 1.00000,1.00000 2.00000 1.00000,0.00000 1.00000 1.00000)),"
"((-1.00000 2.00000 1.00000,-0.20000 0.80000 1.00000,0.00000 1.00000 1.00000,-1.00000 2.00000 1.00000)),"
"((-1.00000 2.00000 -1.00000,-1.00000 1.00000 0.00000,-1.00000 2.00000 1.00000,-1.00000 2.00000 -1.00000)),"
"((1.00000 2.00000 -1.00000,0.00000 1.00000 -1.00000,-1.00000 2.00000 -1.00000,1.00000 2.00000 -1.00000)),"
"((1.00000 1.00000 0.00000,1.00000 0.80000 -0.20000,1.00000 2.00000 -1.00000,1.00000 1.00000 0.00000)),"
"((1.00000 2.00000 1.00000,1.00000 0.00000 1.00000,1.00000 1.00000 0.00000,1.00000 2.00000 1.00000)),"
"((0.00000 1.00000 1.00000,1.00000 1.00000 0.00000,1.00000 0.00000 1.00000,0.00000 1.00000 1.00000)),"
"((-0.20000 0.80000 1.00000,-1.00000 0.80000 0.20000,0.00000 1.00000 1.00000,-0.20000 0.80000 1.00000)),"
"((-1.00000 2.00000 1.00000,-1.00000 0.00000 1.00000,-0.20000 0.80000 1.00000,-1.00000 2.00000 1.00000)),"
"((-1.00000 1.00000 0.00000,-1.00000 0.80000 0.20000,-1.00000 2.00000 1.00000,-1.00000 1.00000 0.00000)),"
"((-1.00000 2.00000 -1.00000,-1.00000 0.00000 -1.00000,-1.00000 1.00000 0.00000,-1.00000 2.00000 -1.00000)),"
"((0.00000 1.00000 -1.00000,-1.00000 0.00000 -1.00000,-1.00000 2.00000 -1.00000,0.00000 1.00000 -1.00000)),"
"((1.00000 2.00000 -1.00000,0.20000 0.80000 -1.00000,0.00000 1.00000 -1.00000,1.00000 2.00000 -1.00000)),"
"((1.00000 0.80000 -0.20000,1.00000 0.00000 -1.00000,1.00000 2.00000 -1.00000,1.00000 0.80000 -0.20000)),"
"((1.00000 1.00000 0.00000,0.00000 1.00000 -1.00000,1.00000 0.80000 -0.20000,1.00000 1.00000 0.00000)),"
"((0.00000 1.00000 1.00000,0.00000 2.00000 0.00000,1.00000 1.00000 0.00000,0.00000 1.00000 1.00000)),"
"((-1.00000 0.80000 0.20000,-1.00000 1.00000 0.00000,0.00000 1.00000 1.00000,-1.00000 0.80000 0.20000)),"
"((-0.20000 0.80000 1.00000,-1.00000 0.00000 1.00000,-1.00000 0.80000 0.20000,-0.20000 0.80000 1.00000)),"
"((-1.00000 2.00000 1.00000,-1.00000 0.80000 0.20000,-1.00000 0.00000 1.00000,-1.00000 2.00000 1.00000)),"
"((-1.00000 0.00000 -1.00000,0.00000 1.00000 -1.00000,-1.00000 1.00000 0.00000,-1.00000 0.00000 -1.00000)),"
"((0.20000 0.80000 -1.00000,1.00000 0.80000 -0.20000,0.00000 1.00000 -1.00000,0.20000 0.80000 -1.00000)),"
"((1.00000 2.00000 -1.00000,1.00000 0.00000 -1.00000,0.20000 0.80000 -1.00000,1.00000 2.00000 -1.00000)),"
"((1.00000 0.80000 -0.20000,0.20000 0.80000 -1.00000,1.00000 0.00000 -1.00000,1.00000 0.80000 -0.20000)),"
"((1.00000 1.00000 0.00000,0.00000 2.00000 0.00000,0.00000 1.00000 -1.00000,1.00000 1.00000 0.00000)),"
"((0.00000 1.00000 1.00000,-1.00000 1.00000 0.00000,0.00000 2.00000 0.00000,0.00000 1.00000 1.00000)),"
"((0.00000 1.00000 -1.00000,0.00000 2.00000 0.00000,-1.00000 1.00000 0.00000,0.00000 1.00000 -1.00000)))");
std::cout << "Conversion 1" << std::endl;
std::auto_ptr< CGAL::Polyhedron_3<SFCGAL::Kernel> > tin_cgal_1 = tin->as<SFCGAL::TriangulatedSurface>().toPolyhedron_3<SFCGAL::Kernel, CGAL::Polyhedron_3<SFCGAL::Kernel> >();
std::cout << "Conversion 2" << std::endl;
std::auto_ptr< SFCGAL::detail::MarkedPolyhedron > tin_cgal_2 = tin->as<SFCGAL::TriangulatedSurface>().toPolyhedron_3<SFCGAL::Kernel, SFCGAL::detail::MarkedPolyhedron >();
std::cout << "GL3D514test_toPolyhedron_3 succeeded" << std::endl;
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE( SFCGAL_algorithm_GL3D_514_decompose )
// Test that starts with the same shape as a Solid, and winds up making the same call as GL3D514test_toPolyhedron_3
BOOST_AUTO_TEST_CASE( GL3D514test_decompose /*, *boost::unit_test::disabled() */ )
{
std::cout << "GL3D514test_decompose" << std::endl;
std::auto_ptr<SFCGAL::Geometry> g0 = SFCGAL::io::readWkt("SOLID(("
"((0.00000 2.00000 0.00000,-1.00000 2.00000 1.00000,1.00000 2.00000 1.00000,0.00000 2.00000 0.00000)),"
"((1.00000 2.00000 1.00000,1.00000 2.00000 -1.00000,0.00000 2.00000 0.00000,1.00000 2.00000 1.00000)),"
"((-1.00000 2.00000 1.00000,0.00000 1.00000 1.00000,1.00000 2.00000 1.00000,-1.00000 2.00000 1.00000)),"
"((0.00000 2.00000 0.00000,-1.00000 2.00000 -1.00000,-1.00000 2.00000 1.00000,0.00000 2.00000 0.00000)),"
"((1.00000 2.00000 -1.00000,-1.00000 2.00000 -1.00000,0.00000 2.00000 0.00000,1.00000 2.00000 -1.00000)),"
"((1.00000 2.00000 1.00000,1.00000 1.00000 0.00000,1.00000 2.00000 -1.00000,1.00000 2.00000 1.00000)),"
"((0.00000 1.00000 1.00000,1.00000 0.00000 1.00000,1.00000 2.00000 1.00000,0.00000 1.00000 1.00000)),"
"((-1.00000 2.00000 1.00000,-0.20000 0.80000 1.00000,0.00000 1.00000 1.00000,-1.00000 2.00000 1.00000)),"
"((-1.00000 2.00000 -1.00000,-1.00000 1.00000 0.00000,-1.00000 2.00000 1.00000,-1.00000 2.00000 -1.00000)),"
"((1.00000 2.00000 -1.00000,0.00000 1.00000 -1.00000,-1.00000 2.00000 -1.00000,1.00000 2.00000 -1.00000)),"
"((1.00000 1.00000 0.00000,1.00000 0.80000 -0.20000,1.00000 2.00000 -1.00000,1.00000 1.00000 0.00000)),"
"((1.00000 2.00000 1.00000,1.00000 0.00000 1.00000,1.00000 1.00000 0.00000,1.00000 2.00000 1.00000)),"
"((0.00000 1.00000 1.00000,1.00000 1.00000 0.00000,1.00000 0.00000 1.00000,0.00000 1.00000 1.00000)),"
"((-0.20000 0.80000 1.00000,-1.00000 0.80000 0.20000,0.00000 1.00000 1.00000,-0.20000 0.80000 1.00000)),"
"((-1.00000 2.00000 1.00000,-1.00000 0.00000 1.00000,-0.20000 0.80000 1.00000,-1.00000 2.00000 1.00000)),"
"((-1.00000 1.00000 0.00000,-1.00000 0.80000 0.20000,-1.00000 2.00000 1.00000,-1.00000 1.00000 0.00000)),"
"((-1.00000 2.00000 -1.00000,-1.00000 0.00000 -1.00000,-1.00000 1.00000 0.00000,-1.00000 2.00000 -1.00000)),"
"((0.00000 1.00000 -1.00000,-1.00000 0.00000 -1.00000,-1.00000 2.00000 -1.00000,0.00000 1.00000 -1.00000)),"
"((1.00000 2.00000 -1.00000,0.20000 0.80000 -1.00000,0.00000 1.00000 -1.00000,1.00000 2.00000 -1.00000)),"
"((1.00000 0.80000 -0.20000,1.00000 0.00000 -1.00000,1.00000 2.00000 -1.00000,1.00000 0.80000 -0.20000)),"
"((1.00000 1.00000 0.00000,0.00000 1.00000 -1.00000,1.00000 0.80000 -0.20000,1.00000 1.00000 0.00000)),"
"((0.00000 1.00000 1.00000,0.00000 2.00000 0.00000,1.00000 1.00000 0.00000,0.00000 1.00000 1.00000)),"
"((-1.00000 0.80000 0.20000,-1.00000 1.00000 0.00000,0.00000 1.00000 1.00000,-1.00000 0.80000 0.20000)),"
"((-0.20000 0.80000 1.00000,-1.00000 0.00000 1.00000,-1.00000 0.80000 0.20000,-0.20000 0.80000 1.00000)),"
"((-1.00000 2.00000 1.00000,-1.00000 0.80000 0.20000,-1.00000 0.00000 1.00000,-1.00000 2.00000 1.00000)),"
"((-1.00000 0.00000 -1.00000,0.00000 1.00000 -1.00000,-1.00000 1.00000 0.00000,-1.00000 0.00000 -1.00000)),"
"((0.20000 0.80000 -1.00000,1.00000 0.80000 -0.20000,0.00000 1.00000 -1.00000,0.20000 0.80000 -1.00000)),"
"((1.00000 2.00000 -1.00000,1.00000 0.00000 -1.00000,0.20000 0.80000 -1.00000,1.00000 2.00000 -1.00000)),"
"((1.00000 0.80000 -0.20000,0.20000 0.80000 -1.00000,1.00000 0.00000 -1.00000,1.00000 0.80000 -0.20000)),"
"((1.00000 1.00000 0.00000,0.00000 2.00000 0.00000,0.00000 1.00000 -1.00000,1.00000 1.00000 0.00000)),"
"((0.00000 1.00000 1.00000,-1.00000 1.00000 0.00000,0.00000 2.00000 0.00000,0.00000 1.00000 1.00000)),"
"((0.00000 1.00000 -1.00000,0.00000 2.00000 0.00000,-1.00000 1.00000 0.00000,0.00000 1.00000 -1.00000))))");
// The Solid is correctly considered valid.
// That can be verified by uncommenting these lines.
//std::cout << "Checking validity" << std::endl;
//SFCGAL::SFCGAL_ASSERT_GEOMETRY_VALIDITY( *g0 );
std::cout << "decomposing g0" << std::endl;
SFCGAL::detail::GeometrySet<3> gs0( *g0 );
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE( SFCGAL_algorithm_GL3D_514_full )
// Full test case that demonstrates how the situation can arise.
// The difference algorithm produces correct output which includes the problem geometry.
// (Note that the above may require a fix to corefinement_operations.h for a separate issue, that might not be in the public code yet.)
// Then an attempt will be made to decompose it in GeometrySet.filterCovered, which will make a decompose call as above.
// By inspecting intermediate geometries in this test, you can see how CGAL represents the problem geometry when returning it from an algorithm;
// the problem vertex is duplicated to hide the non-manifold point from the underlying combinatorial map.
// Below the test an example of the CGAL output is given.
BOOST_AUTO_TEST_CASE( GL3D514test_full /*, *boost::unit_test::disabled() */ )
{
std::cout << "GL3D514test_full" << std::endl;
std::auto_ptr<SFCGAL::Geometry> g1 = SFCGAL::io::readWkt("SOLID Z(("
"(( 1.00000 2.00000 1.00000, 1.00000 -1.00000 1.00000, 1.00000 -1.00000 -1.00000, 1.00000 2.00000 -1.00000, 1.00000 2.00000 1.00000)),"
"(( 1.00000 2.00000 1.00000, 1.00000 2.00000 -1.00000,-1.00000 2.00000 -1.00000,-1.00000 2.00000 1.00000, 1.00000 2.00000 1.00000)),"
"((-1.00000 2.00000 -1.00000,-1.00000 -1.00000 -1.00000,-1.00000 -1.00000 1.00000,-1.00000 2.00000 1.00000,-1.00000 2.00000 -1.00000)),"
"(( 1.00000 -1.00000 1.00000,-1.00000 -1.00000 1.00000,-1.00000 -1.00000 -1.00000, 1.00000 -1.00000 -1.00000, 1.00000 -1.00000 1.00000)),"
"(( 1.00000 2.00000 -1.00000, 1.00000 -1.00000 -1.00000,-1.00000 -1.00000 -1.00000,-1.00000 2.00000 -1.00000, 1.00000 2.00000 -1.00000)),"
"(( 1.00000 2.00000 1.00000,-1.00000 2.00000 1.00000,-1.00000 -1.00000 1.00000, 1.00000 -1.00000 1.00000, 1.00000 2.00000 1.00000))"
"))");
std::auto_ptr<SFCGAL::Geometry> g2 = SFCGAL::io::readWkt("SOLID Z(("
"((0.00000 2.00000 0.00000,2.00000 0.00000 0.00000,0.00000 0.00000 -2.00000,0.00000 2.00000 0.00000)),"
"((0.00000 2.00000 0.00000,0.00000 0.00000 2.00000,2.00000 0.00000 0.00000,0.00000 2.00000 0.00000)),"
"((0.00000 2.00000 0.00000,-2.00000 0.00000 0.00000,0.00000 0.00000 2.00000,0.00000 2.00000 0.00000)),"
"((0.00000 2.00000 0.00000,0.00000 0.00000 -2.00000,-2.00000 0.00000 0.00000,0.00000 2.00000 0.00000)),"
"((0.00000 -2.00000 0.00000,0.00000 0.00000 -2.00000,2.00000 0.00000 0.00000,0.00000 -2.00000 0.00000)),"
"((0.00000 -2.00000 0.00000,2.00000 0.00000 0.00000,0.00000 0.00000 2.00000,0.00000 -2.00000 0.00000)),"
"((0.00000 -2.00000 0.00000,0.00000 0.00000 2.00000,-2.00000 0.00000 0.00000,0.00000 -2.00000 0.00000)),"
"((0.00000 -2.00000 0.00000,-2.00000 0.00000 0.00000,0.00000 0.00000 -2.00000,0.00000 -2.00000 0.00000))"
"))");
std::auto_ptr<SFCGAL::Geometry> diff1 = SFCGAL::algorithm::difference3D( *g1, *g2, SFCGAL::algorithm::NoValidityCheck() );
std::auto_ptr<SFCGAL::Geometry> diff2 = SFCGAL::algorithm::difference3D( *g2, *g1, SFCGAL::algorithm::NoValidityCheck() );
BOOST_CHECK( SFCGAL::algorithm::isValid(*diff1) );
BOOST_CHECK( SFCGAL::algorithm::isValid(*diff2) );
BOOST_CHECK( diff1->is<SFCGAL::MultiSolid>() );
BOOST_CHECK( diff2->is<SFCGAL::MultiSolid>() );
BOOST_CHECK( diff1->as<SFCGAL::MultiSolid>().numGeometries() == 5 );
BOOST_CHECK( diff2->as<SFCGAL::MultiSolid>().numGeometries() == 5 );
}
/*
This shows how CGAL represents the shape (taken from some formatted log output).
Note the duplicate of the vertex at (0,2,0).
<line>... Import_volume_as_polyhedron operator()... </line>
<line>... Adding vertex: -1, 0, -1... </line>
<line>... Adding vertex: 0, 1, -1... </line>
<line>... Adding vertex: -1, 2, -1... </line>
<line>... Adding vertex: -1, 1, 0... </line>
<line>... Adding vertex: 1, 2, -1... </line>
<line>... Adding vertex: 0, 2, 0... </line>
<line>... Adding vertex: 0.2, 0.8, -1... </line>
<line>... Adding vertex: 0, 2, 0... </line>
<line>... Adding vertex: -1, 2, 1... </line>
<line>... Adding vertex: 0, 1, 1... </line>
<line>... Adding vertex: 1, 1, 0... </line>
<line>... Adding vertex: 1, 0.8, -0.2... </line>
<line>... Adding vertex: 1, 0, -1... </line>
<line>... Adding vertex: 1, 2, 1... </line>
<line>... Adding vertex: -1, 0.8, 0.2... </line>
<line>... Adding vertex: -1, 0, 1... </line>
<line>... Adding vertex: -0.2, 0.8, 1... </line>
<line>... Adding vertex: 1, 0, 1... </line>
<line>... Adding facet: 0, 2, 1... </line>
<line>... Adding facet: 1, 3, 0... </line>
<line>... Adding facet: 2, 4, 1... </line>
<line>... Adding facet: 0, 3, 2... </line>
<line>... Adding facet: 1, 5, 3... </line>
<line>... Adding facet: 4, 6, 1... </line>
<line>... Adding facet: 2, 7, 4... </line>
<line>... Adding facet: 3, 8, 2... </line>
<line>... Adding facet: 5, 9, 3... </line>
<line>... Adding facet: 1, 10, 5... </line>
<line>... Adding facet: 6, 11, 1... </line>
<line>... Adding facet: 4, 12, 6... </line>
<line>... Adding facet: 7, 13, 4... </line>
<line>... Adding facet: 2, 8, 7... </line>
<line>... Adding facet: 3, 14, 8... </line>
<line>... Adding facet: 9, 14, 3... </line>
<line>... Adding facet: 5, 10, 9... </line>
<line>... Adding facet: 1, 11, 10... </line>
<line>... Adding facet: 6, 12, 11... </line>
<line>... Adding facet: 4, 11, 12... </line>
<line>... Adding facet: 13, 10, 4... </line>
<line>... Adding facet: 7, 8, 13... </line>
<line>... Adding facet: 14, 15, 8... </line>
<line>... Adding facet: 9, 16, 14... </line>
<line>... Adding facet: 10, 17, 9... </line>
<line>... Adding facet: 11, 4, 10... </line>
<line>... Adding facet: 13, 17, 10... </line>
<line>... Adding facet: 8, 9, 13... </line>
<line>... Adding facet: 15, 16, 8... </line>
<line>... Adding facet: 14, 16, 15... </line>
<line>... Adding facet: 9, 8, 16... </line>
<line>... Adding facet: 17, 13, 9... </line>
<line>... Import_volume_as_polyhedron operator(): done... </line>
*/
BOOST_AUTO_TEST_SUITE_END()