/*
* Project: MoleCuilder
* Description: creates and alters molecular systems
* Copyright (C) 2010-2012 University of Bonn. All rights reserved.
*
*
* This file is part of MoleCuilder.
*
* MoleCuilder is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* MoleCuilder is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MoleCuilder. If not, see .
*/
/*
* 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) );
}
}
}
}