/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010-2012 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * Tesselation_InsideOutsideUnitTest.cpp * * Created on: Dec 28, 2009 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif using namespace std; #include #include #include #include #include #include "Atom/TesselPoint.hpp" #include "CodePatterns/Log.hpp" #include "Helpers/defs.hpp" #include "LinearAlgebra/RealSpaceMatrix.hpp" #include "LinkedCell/PointCloudAdaptor.hpp" #include "Tesselation/BoundaryLineSet.hpp" #include "Tesselation/BoundaryTriangleSet.hpp" #include "Tesselation/CandidateForTesselation.hpp" #include "Tesselation/tesselation.hpp" #include "Tesselation_InsideOutsideUnitTest.hpp" #ifdef HAVE_TESTRUNNER #include "UnitTestMain.hpp" #endif /*HAVE_TESTRUNNER*/ /********************************************** Test classes **************************************/ // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( TesselationInOutsideTest ); /** Creates TesselPoints out of given Vector's. * * @param Vectors given vector with Vector's as positions for TesselPoint's */ void TesselationInOutsideTest::prepareCorners(const std::vector &Vectors) { class TesselPoint *Walker; size_t index = 0; for (std::vector::const_iterator iter = Vectors.begin(); iter != Vectors.end(); ++iter) { Walker = new TesselPoint; Walker->setPosition( *iter ); Walker->setNr(index++); Walker->setName(toString(index)); // yes, name is one higher than index Corners.push_back(Walker); } } /** Prepares Vector's in such a way that the mesh forms a cube. * * @param vectors vector of Vector's to work on * @param factor factor to expand mesh * @param offset offset to translate mesh * @param return vector for concatenation */ std::vector TesselationInOutsideTest::translateAndexpand( VECTORSET(std::vector) Vectors, const double factor, const Vector &offset) const { RealSpaceMatrix M; M.setIdentity(); M *= factor; Vectors.transform(M); Vectors.translate(offset); return Vectors; } /** Prepares Vector's in such a way that the mesh forms a cube. * */ std::vector TesselationInOutsideTest::setupCube() const { std::vector returnVectors; returnVectors.push_back( Vector(0., 0., 0.) ); returnVectors.push_back( Vector(0., 1., 0.) ); returnVectors.push_back( Vector(1., 0., 0.) ); returnVectors.push_back( Vector(1., 1., 0.) ); returnVectors.push_back( Vector(0., 0., 1.) ); returnVectors.push_back( Vector(0., 1., 1.) ); returnVectors.push_back( Vector(1., 0., 1.) ); returnVectors.push_back( Vector(1., 1., 1.) ); return returnVectors; } /** Prepares Vector's in such a way that the mesh forms a sphere. * */ std::vector TesselationInOutsideTest::setupSphere() const { std::vector returnVectors; // start with a cube returnVectors.push_back( Vector(0., 0., 0.) ); returnVectors.push_back( Vector(0., 1., 0.) ); returnVectors.push_back( Vector(1., 0., 0.) ); returnVectors.push_back( Vector(1., 1., 0.) ); returnVectors.push_back( Vector(0., 0., 1.) ); returnVectors.push_back( Vector(0., 1., 1.) ); returnVectors.push_back( Vector(1., 0., 1.) ); returnVectors.push_back( Vector(1., 1., 1.) ); // then add a point slightly above each face returnVectors.push_back( Vector(0.5, 0.5, -0.4142136) ); returnVectors.push_back( Vector(0.5, 0.5, 1.4142136) ); returnVectors.push_back( Vector(0.5, -0.4142136, 0.5) ); returnVectors.push_back( Vector(0.5, 1.4142136, 0.5) ); returnVectors.push_back( Vector(-0.4142136, 0.5, 0.5) ); returnVectors.push_back( Vector(1.4142136, 0.5, 0.5) ); return returnVectors; } /** Prepares Vector's in such a way that the mesh forms a nonconvex form. * */ std::vector TesselationInOutsideTest::setupNonConvex() const { std::vector returnVectors; // make an along the x-axis elongated cuboid returnVectors.push_back( Vector(0., 0., 0.) ); returnVectors.push_back( Vector(0., 1., 0.) ); returnVectors.push_back( Vector(2., 0., 0.) ); returnVectors.push_back( Vector(2., 1., 0.) ); returnVectors.push_back( Vector(0., 0., 1.) ); returnVectors.push_back( Vector(0., 1., 1.) ); returnVectors.push_back( Vector(2., 0., 1.) ); returnVectors.push_back( Vector(2., 1., 1.) ); // add two lowered points in the middle of the elongation returnVectors.push_back( Vector(1., 0.5, 0.) ); returnVectors.push_back( Vector(1., 0.5, 1.) ); returnVectors.push_back( Vector(1., 0., 0.) ); returnVectors.push_back( Vector(1., 0., 1.) ); return returnVectors; } /** Creates the tesselation out of current setup in \a Corners. * */ void TesselationInOutsideTest::prepareTesselation(const double SPHERERADIUS) { // create LinkedCell PointCloudAdaptor< TesselPointSTLList > cloud(&Corners, "TesselPointSTLList"); LinkedList = new LinkedCell_deprecated(cloud, 2.*SPHERERADIUS); // create tesselation TesselStruct = new Tesselation; (*TesselStruct)(cloud, SPHERERADIUS); } /** Removes any currently present tesselation. * */ void TesselationInOutsideTest::removeTesselation() { delete LinkedList; delete TesselStruct; for (TesselPointSTLList::iterator Runner = Corners.begin(); Runner != Corners.end(); Runner++) delete *Runner; LinkedList = NULL; TesselStruct = NULL; } void TesselationInOutsideTest::setUp() { setVerbosity(6); } void TesselationInOutsideTest::tearDown() { removeTesselation(); Corners.clear(); logger::purgeInstance(); errorLogger::purgeInstance(); } /** UnitTest for Tesselation::IsInnerPoint() with a cube mesh */ void TesselationInOutsideTest::IsInnerPointCubeTest() { { const double SPHERERADIUS = 2.; prepareCorners( translateAndexpand( setupCube(), 1., Vector(0.,0.,0.)) ); prepareTesselation(SPHERERADIUS); CPPUNIT_ASSERT( TesselStruct != NULL ); PointCloudAdaptor< TesselPointSTLList > cloud(&Corners, "TesselPointSTLList"); TesselStruct->Output("cube", cloud); double n[3]; const double boundary = 2.; const double step = 1.; // go through the cube and check each point for (n[0] = -boundary; n[0] <= boundary; n[0]+=step) for (n[1] = -boundary; n[1] <= boundary; n[1]+=step) for (n[2] = -boundary; n[2] <= boundary; n[2]+=step) { const Vector testPoint(n[0], n[1], n[2]); if ( ((n[0] >= 0.) && (n[1] >= 0.) && (n[2] >= 0.)) && ((n[0] <= 1.) && (n[1] <= 1.) && (n[2] <= 1.))) CPPUNIT_ASSERT_EQUAL( true , TesselStruct->IsInnerPoint(testPoint, LinkedList) ); else CPPUNIT_ASSERT_EQUAL( false , TesselStruct->IsInnerPoint(testPoint, LinkedList) ); } } } /** UnitTest for Tesselation::IsInnerPoint() with a sphere mesh */ void TesselationInOutsideTest::IsInnerPointSphereTest() { { // with radius 2, we see the opposite point which causes FindStartingTriangle() to fail const double SPHERERADIUS = 1.; const Vector offset(0.5,0.5,0.5); const double factor = 1.; prepareCorners( translateAndexpand( setupSphere(), factor, offset) ); prepareTesselation(SPHERERADIUS); CPPUNIT_ASSERT( TesselStruct != NULL ); double n[3]; const double boundary = 2.; const double step = 1.; const std::vector test(1, true); const Vector SphereCenter( Vector(0.5,0.5,0.5) + offset ); const double SphereRadius = (Vector(0.,0.,0.)+offset - SphereCenter).Norm(); // go through the cube and check each point for (n[0] = -boundary; n[0] <= boundary; n[0]+=step) for (n[1] = -boundary; n[1] <= boundary; n[1]+=step) for (n[2] = -boundary; n[2] <= boundary; n[2]+=step) { const Vector testPoint(n[0], n[1], n[2]); // radius is actually 2. but we simply avoid the corners in this test if ( testPoint.DistanceSquared(SphereCenter) <= factor*SphereRadius ) { LOG(1, "INFO: Testing whether " << testPoint << " is an inner point."); CPPUNIT_ASSERT_EQUAL( true , TesselStruct->IsInnerPoint(testPoint, LinkedList) ); } else { LOG(1, "INFO: Testing whether " << testPoint << " is not an inner point."); CPPUNIT_ASSERT_EQUAL( false , TesselStruct->IsInnerPoint(testPoint, LinkedList) ); } } } } /** UnitTest for Tesselation::IsInnerPoint() with a non-convex mesh */ void TesselationInOutsideTest::IsInnerPointNonConvexTest() { { const double SPHERERADIUS = 1.; prepareCorners( translateAndexpand( setupNonConvex(), 1., Vector(0.,0.,0.)) ); prepareTesselation(SPHERERADIUS); CPPUNIT_ASSERT( TesselStruct != NULL ); double n[3]; const double boundary = 4.; const double step = 1.; // go through the cube and check each point for (n[0] = -boundary; n[0] <= boundary; n[0]+=step) for (n[1] = -boundary; n[1] <= boundary; n[1]+=step) for (n[2] = -boundary; n[2] <= boundary; n[2]+=step) { const Vector testPoint(n[0], n[1], n[2]); if ( ((n[0] >= 0.) && (n[1] >= 0.) && (n[2] >= 0.)) && ((n[0] <= 2.) && (n[1] <= .5) && (n[2] <= 1.))) { // (y) lower half of elongated block LOG(1, "INFO: Testing whether " << testPoint << " is an inner point."); CPPUNIT_ASSERT_EQUAL( true , TesselStruct->IsInnerPoint(testPoint, LinkedList) ); } else if ( ((n[0] >= 0.) && (n[1] >= 0.5) && (n[2] >= 0.)) && ((n[0] <= 2.) && (n[1] <= 1.) && (n[2] <= 1.))) { // (y) upper half of elongated block if ( ((n[0] >= 0.) && (n[1] >= 0.5) && (n[2] >= 0.)) && ((n[0] <= 1.) && (n[1] <= 1.) && (n[2] <= 1.))) { // (x) left side if (n[0]+n[1] <= 1.) { LOG(1, "INFO: Testing whether " << testPoint << " is an inner point."); CPPUNIT_ASSERT_EQUAL( true , TesselStruct->IsInnerPoint(testPoint, LinkedList) ); } else { LOG(1, "INFO: Testing whether " << testPoint << " is not an inner point."); CPPUNIT_ASSERT_EQUAL( false , TesselStruct->IsInnerPoint(testPoint, LinkedList) ); } } else { // (x) right side) if ((1.-n[0])+n[1] <= 1.) { LOG(1, "INFO: Testing whether " << testPoint << " is an inner point."); CPPUNIT_ASSERT_EQUAL( true , TesselStruct->IsInnerPoint(testPoint, LinkedList) ); } else { LOG(1, "INFO: Testing whether " << testPoint << " is not an inner point."); CPPUNIT_ASSERT_EQUAL( false , TesselStruct->IsInnerPoint(testPoint, LinkedList) ); } } } else { LOG(1, "INFO: Testing whether " << testPoint << " is not an inner point."); CPPUNIT_ASSERT_EQUAL( false , TesselStruct->IsInnerPoint(testPoint, LinkedList) ); } } } }