/* * 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 . */ /* * FillSurfaceAction.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 "Shapes/ShapeRegistry.hpp" #include "World.hpp" #include #include #include #include #include #include #include "Actions/FillAction/FillSurfaceAction.hpp" using namespace MoleCuilder; // and construct the stuff #include "FillSurfaceAction.def" #include "Action_impl_pre.hpp" /** =========== define the function ====================== */ ActionState::ptr FillSurfaceAction::performCall() { // get the filler molecule const std::vector< molecule *> molecules = World::getInstance().getSelectedMolecules(); std::vector movedatoms; if (molecules.size() != 1) { STATUS("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 filler->CenterEdge(); // 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.get()).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 FillSurfaceState *UndoState = NULL; bool successflag = false; { FillPredicate *voidnode_predicate = new FillPredicate( IsVoidNode_FillPredicate( Sphere(zeroVec, params.mindistance.get()) ) ); std::vector selectedShapes = ShapeRegistry::getInstance().getSelectedShapes(); if (selectedShapes.size() != 1){ STATUS("There has to be exactly 1 selected shape."); return Action::failure; } boost::function func = boost::bind(&Shape::getHomogeneousPointsOnSurface, boost::ref(*selectedShapes[0]), params.N.get()); Mesh *mesh = new MeshAdaptor(func); Inserter *inserter = new Inserter( Inserter::impl_ptr(new SurfaceInserter(*selectedShapes[0], params.AlignedAxis.get()))); // fill { Filler *fillerFunction = new Filler(*mesh, *voidnode_predicate, *inserter); ClusterInterface::Cluster_impl cluster( new Cluster( filler->getAtomIds(), filler->getBoundingSphere() ) ); 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) { STATUS("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 FillSurfaceState(clonedatominfos,clonedbonds,movedatoms,MovedToVector,params); } } // remove delete mesh; delete inserter; delete voidnode_predicate; } if (successflag) return ActionState::ptr(UndoState); else return Action::failure; } ActionState::ptr FillSurfaceAction::performUndo(ActionState::ptr _state) { FillSurfaceState *state = assert_cast(_state.get()); // remove all created atoms RemoveAtomsFromAtomicInfo(state->clonedatoms); // add the original cluster SetAtomsFromAtomicInfo(state->movedatoms); return ActionState::ptr(_state); } ActionState::ptr FillSurfaceAction::performRedo(ActionState::ptr _state){ FillSurfaceState *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 ActionState::ptr(_state); else { STATUS("Failed to re-added filled in atoms."); return Action::failure; } } bool FillSurfaceAction::canUndo() { return true; } bool FillSurfaceAction::shouldUndo() { return true; } /** =========== end of function ====================== */