/* * 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. */ /* * FillSphericalSurfaceAction.cpp * * Created on: Mar 29, 2012 * Author: heber, bollerhe */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "CodePatterns/MemDebug.hpp" #include "Actions/UndoRedoHelpers.hpp" #include "Atom/atom.hpp" #include "Atom/AtomicInfo.hpp" #include "Atom/CopyAtoms/CopyAtoms_withBonds.hpp" #include "CodePatterns/Log.hpp" #include "Filling/Cluster.hpp" #include "Filling/Filler.hpp" #include "Filling/Inserter/Inserter.hpp" #include "Filling/Inserter/SurfaceInserter.hpp" #include "Filling/Mesh/MeshAdaptor.hpp" #include "Filling/Predicates/IsVoidNode_FillPredicate.hpp" #include "molecule.hpp" #include "Shapes/BaseShapes.hpp" #include "World.hpp" #include #include #include #include #include #include #include "Actions/FillAction/FillSphericalSurfaceAction.hpp" using namespace MoleCuilder; // and construct the stuff #include "FillSphericalSurfaceAction.def" #include "Action_impl_pre.hpp" /** =========== define the function ====================== */ Action::state_ptr FillSphericalSurfaceAction::performCall() { // get the filler molecule const std::vector< molecule *> molecules = World::getInstance().getSelectedMolecules(); std::vector movedatoms; if (molecules.size() != 1) { ELOG(1, "No exactly one molecule selected, aborting,"); return Action::failure; } molecule *filler = *(molecules.begin()); for(molecule::const_iterator iter = filler->begin(); iter != filler->end(); ++iter) movedatoms.push_back( AtomicInfo(*(*iter)) ); LOG(1, "INFO: Chosen molecule has " << filler->size() << " atoms."); // center filler's tip at origin Vector max; filler->CenterEdge(&max); // determine center with respect to alignment axis Vector sum = zeroVec; for (molecule::iterator it2=filler->begin();it2 !=filler->end();++it2) { const Vector helper = (**it2).getPosition().partition(params.AlignedAxis).second; sum += helper; } sum *= 1./filler->size(); // translate molecule's closest atom to origin (such that is resides on the filler spot) LOG(1, "DEBUG: molecule is off Alignment axis by " << sum << ", shifting ..."); { Vector translater = -1.*sum; filler->Translate(&translater); } // create predicate, mesh, and filler FillSphericalSurfaceState *UndoState = NULL; bool successflag = false; { FillPredicate *voidnode_predicate = new FillPredicate( IsVoidNode_FillPredicate( Sphere(zeroVec, params.mindistance) ) ); Shape s = Sphere(params.center, params.radius); boost::function func = boost::bind(&Shape::getHomogeneousPointsOnSurface, boost::ref(s), params.N); Mesh *mesh = new MeshAdaptor(func); Inserter *inserter = new Inserter( Inserter::impl_ptr(new SurfaceInserter(s, params.AlignedAxis))); // fill { Filler *fillerFunction = new Filler(*mesh, *voidnode_predicate, *inserter); ClusterInterface::Cluster_impl cluster( new Cluster( filler->getAtomIds(), filler->getBoundingShape() ) ); CopyAtoms_withBonds copyMethod; Filler::ClusterVector_t ClonedClusters; successflag = (*fillerFunction)(copyMethod, cluster, ClonedClusters); delete fillerFunction; // append each cluster's atoms to clonedatoms (however not selected ones) std::vector clonedatoms; std::vector clonedatominfos; for (Filler::ClusterVector_t::const_iterator iter = ClonedClusters.begin(); iter != ClonedClusters.end(); ++iter) { const AtomIdSet &atoms = (*iter)->getAtomIds(); clonedatoms.reserve(clonedatoms.size()+atoms.size()); for (AtomIdSet::const_iterator atomiter = atoms.begin(); atomiter != atoms.end(); ++atomiter) if (!filler->containsAtom(*atomiter)) { clonedatoms.push_back( *atomiter ); clonedatominfos.push_back( AtomicInfo(*(*atomiter)) ); } } std::vector< BondInfo > clonedbonds; StoreBondInformationFromAtoms(clonedatoms, clonedbonds); LOG(2, "DEBUG: There are " << clonedatominfos.size() << " newly created atoms with " << clonedbonds.size()/2 << " bonds."); if (!successflag) { ELOG(1, "Insertion failed, removing inserted clusters, translating original one back"); RemoveAtomsFromAtomicInfo(clonedatominfos); clonedatoms.clear(); SetAtomsFromAtomicInfo(movedatoms); } else { std::vector MovedToVector(filler->size(), zeroVec); std::transform(filler->begin(), filler->end(), MovedToVector.begin(), boost::bind(&AtomInfo::getPosition, _1) ); UndoState = new FillSphericalSurfaceState(clonedatominfos,clonedbonds,movedatoms,MovedToVector,params); } } // remove delete mesh; delete inserter; delete voidnode_predicate; } if (successflag) return Action::state_ptr(UndoState); else return Action::failure; } Action::state_ptr FillSphericalSurfaceAction::performUndo(Action::state_ptr _state) { FillSphericalSurfaceState *state = assert_cast(_state.get()); // remove all created atoms RemoveAtomsFromAtomicInfo(state->clonedatoms); // add the original cluster SetAtomsFromAtomicInfo(state->movedatoms); return Action::state_ptr(_state); } Action::state_ptr FillSphericalSurfaceAction::performRedo(Action::state_ptr _state){ FillSphericalSurfaceState *state = assert_cast(_state.get()); // place filler cluster again at new spot ResetAtomPosition(state->movedatoms, state->MovedToVector); // re-create all clusters bool statusflag = AddAtomsFromAtomicInfo(state->clonedatoms); // re-create the bonds statusflag = statusflag && AddBondsFromBondInfo(state->clonedbonds); if (statusflag) return Action::state_ptr(_state); else return Action::failure; } bool FillSphericalSurfaceAction::canUndo() { return true; } bool FillSphericalSurfaceAction::shouldUndo() { return true; } /** =========== end of function ====================== */