/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * Box.cpp * * Created on: Jun 30, 2010 * Author: crueger */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "CodePatterns/MemDebug.hpp" #include "Box.hpp" #include #include #include #include "CodePatterns/Assert.hpp" #include "CodePatterns/Log.hpp" #include "CodePatterns/Verbose.hpp" #include "Helpers/defs.hpp" #include "LinearAlgebra/RealSpaceMatrix.hpp" #include "LinearAlgebra/Vector.hpp" #include "LinearAlgebra/Plane.hpp" #include "Shapes/BaseShapes.hpp" #include "Shapes/ShapeOps.hpp" using namespace std; VECTORSET(std::list) Box::internal_list; Box::Box() : M(new RealSpaceMatrix()), Minv(new RealSpaceMatrix()) { M->setIdentity(); Minv->setIdentity(); conditions.resize(3); conditions[0] = conditions[1] = conditions[2] = Wrap; } Box::Box(const Box& src) : conditions(src.conditions), M(new RealSpaceMatrix(*src.M)), Minv(new RealSpaceMatrix(*src.Minv)) {} Box::Box(RealSpaceMatrix _M) : M(new RealSpaceMatrix(_M)), Minv(new RealSpaceMatrix()) { ASSERT(M->determinant()!=0,"Matrix in Box construction was not invertible"); *Minv = M->invert(); } Box::~Box() { delete M; delete Minv; } const RealSpaceMatrix &Box::getM() const{ return *M; } const RealSpaceMatrix &Box::getMinv() const{ return *Minv; } void Box::setM(RealSpaceMatrix _M){ ASSERT(_M.determinant()!=0,"Matrix in Box construction was not invertible"); *M =_M; *Minv = M->invert(); } Vector Box::translateIn(const Vector &point) const{ return (*M) * point; } Vector Box::translateOut(const Vector &point) const{ return (*Minv) * point; } Vector Box::WrapPeriodically(const Vector &point) const{ Vector helper = translateOut(point); for(int i=NDIM;i--;){ switch(conditions[i]){ case Wrap: helper.at(i)=fmod(helper.at(i),1); helper.at(i)+=(helper.at(i)>=0)?0:1; break; case Bounce: { // there probably is a better way to handle this... // all the fabs and fmod modf probably makes it very slow double intpart,fracpart; fracpart = modf(fabs(helper.at(i)),&intpart); helper.at(i) = fabs(fracpart-fmod(intpart,2)); } break; case Ignore: break; default: ASSERT(0,"No default case for this"); } } return translateIn(helper); } bool Box::isInside(const Vector &point) const { bool result = true; Vector tester = translateOut(point); for(int i=0;i= -MYEPSILON) && ((tester[i] - 1.) < MYEPSILON))); return result; } VECTORSET(std::list) Box::explode(const Vector &point,int n) const{ ASSERT(isInside(point),"Exploded point not inside Box"); internal_explode(point, n); VECTORSET(std::list) res(internal_list); return res; } void Box::internal_explode(const Vector &point,int n) const{ internal_list.clear(); Vector translater = translateOut(point); Vector mask; // contains the ignored coordinates // count the number of coordinates we need to do int dims = 0; // number of dimensions that are not ignored vector coords; vector index; for(int i=0;i x // 1 -> 2-x // 2 -> 2+x // 3 -> 4-x // 4 -> 4+x // the first number is the next bigger even number (n+n%2) // the next number is the value with alternating sign (x-2*(n%2)*x) // the negative numbers produce the same sequence reversed and shifted int n = abs(index[i]) + ((index[i]<0)?-1:0); int sign = (index[i]<0)?-1:+1; int even = n%2; helper[coords[i]]=n+even+translater[coords[i]]-2*even*translater[coords[i]]; helper[coords[i]]*=sign; } break; case Ignore: ASSERT(0,"Ignored coordinate handled in generation loop"); break; default: ASSERT(0,"No default case for this switch-case"); break; } } // add back all ignored coordinates (not handled in above loop) helper+=mask; internal_list.push_back(translateIn(helper)); // set the new indexes int pos=0; ++index[pos]; while(index[pos]>n){ index[pos++]=-n; if(pos>=dims) { // it's trying to increase one beyond array... all vectors generated done = true; break; } ++index[pos]; } } } VECTORSET(std::list) Box::explode(const Vector &point) const{ ASSERT(isInside(point),"Exploded point not inside Box"); return explode(point,1); } double Box::periodicDistanceSquared(const Vector &point1,const Vector &point2) const{ Vector helper1(!isInside(point1) ? WrapPeriodically(point1) : point1); Vector helper2(!isInside(point2) ? WrapPeriodically(point2) : point2); internal_explode(helper1,1); double res = internal_list.minDistSquared(helper2); return res; } double Box::periodicDistance(const Vector &point1,const Vector &point2) const{ double res; res = sqrt(periodicDistanceSquared(point1,point2)); return res; } double Box::DistanceToBoundary(const Vector &point) const { std::map DistanceSet; std::vector > Boundaries = getBoundingPlanes(); for (int i=0;ifirst; } Shape Box::getShape() const{ return transform(Cuboid(Vector(0,0,0),Vector(1,1,1)),(*M)); } const Box::Conditions_t Box::getConditions() const { return conditions; } void Box::setCondition(int i,Box::BoundaryCondition_t condition){ conditions[i]=condition; } const vector > Box::getBoundingPlanes() const { vector > res; for(int i=0;i0 && endpoint[1]>0 && endpoint[2]>0,"Vector does not define a full cuboid"); M->setIdentity(); M->diagonal()=endpoint; Vector &dinv = Minv->diagonal(); for(int i=NDIM;i--;) dinv[i]=1/endpoint[i]; } Box &Box::operator=(const Box &src){ if(&src!=this){ delete M; delete Minv; M = new RealSpaceMatrix(*src.M); Minv = new RealSpaceMatrix(*src.Minv); conditions = src.conditions; } return *this; } Box &Box::operator=(const RealSpaceMatrix &mat){ setM(mat); return *this; } ostream & operator << (ostream& ost, const Box &m) { ost << m.getM(); return ost; }