/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 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 . */ /* * StretchBondAction.cpp * * Created on: Sep 26, 2012 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "CodePatterns/MemDebug.hpp" #include "Actions/MoleculeAction/StretchBondAction.hpp" #include "CodePatterns/Log.hpp" #include "CodePatterns/Verbose.hpp" #include "LinearAlgebra/Plane.hpp" #include "Atom/atom.hpp" #include "Bond/bond.hpp" #include "molecule.hpp" #include "World.hpp" using namespace MoleCuilder; // and construct the stuff #include "StretchBondAction.def" #include "Action_impl_pre.hpp" /** =========== define the function ====================== */ Action::state_ptr MoleculeStretchBondAction::performCall() { // check preconditions const std::vector< atom *> atoms = World::getInstance().getSelectedAtoms(); if (atoms.size() != 2) { ELOG(1, "Exactly two atoms must be selected."); return Action::failure; } const molecule *mol = atoms[0]->getMolecule(); if (mol != atoms[1]->getMolecule()) { ELOG(1, "The two selected atoms must belong to the same molecule."); return Action::failure; } // gather undo information const double olddistance = atoms[0]->getPosition().distance(atoms[1]->getPosition()); const double newdistance = params.bonddistance.get(); LOG(1, "INFO: Old bond distance is " << olddistance << ", stretching to " << newdistance << "."); // create the bond plane and mid-distance const Vector NormalVector = (atoms[0]->getPosition() - atoms[1]->getPosition())* (1./olddistance); const Vector OffsetVector = 0.5*(atoms[0]->getPosition() + atoms[1]->getPosition()); Plane bondplane(NormalVector, OffsetVector); // go through the molecule and stretch each atom relative two plane const double shift = 0.5*(newdistance - olddistance); const Vector PositiveShift = shift * NormalVector; const Vector NegativeShift = -shift * NormalVector; Box &domain = World::getInstance().getDomain(); for (molecule::iterator iter = mol->begin(); iter != mol->end(); ++iter) { const Vector &position = (*iter)->getPosition(); // for each atom determine on which side of plane it is and shift accordingly if (bondplane.SignedDistance(position) > 0) { (*iter)->setPosition( domain.enforceBoundaryConditions(position+PositiveShift) ); } else { (*iter)->setPosition( domain.enforceBoundaryConditions(position+NegativeShift) ); } } MoleculeStretchBondState *UndoState = new MoleculeStretchBondState(shift, bondplane, mol, params); return Action::state_ptr(UndoState); } Action::state_ptr MoleculeStretchBondAction::performUndo(Action::state_ptr _state) { MoleculeStretchBondState *state = assert_cast(_state.get()); // use given plane to undo const Vector PositiveShift = state->shift * state->bondplane.getNormal(); const Vector NegativeShift = -state->shift * state->bondplane.getNormal(); Box &domain = World::getInstance().getDomain(); for (molecule::iterator iter = state->mol->begin(); iter != state->mol->end(); ++iter) { const Vector &position = (*iter)->getPosition(); // for each atom determine on which side of plane it is and shift accordingly if (state->bondplane.SignedDistance(position) < 0) { (*iter)->setPosition( domain.enforceBoundaryConditions(position+PositiveShift) ); } else { (*iter)->setPosition( domain.enforceBoundaryConditions(position+NegativeShift) ); } } return Action::state_ptr(_state); } Action::state_ptr MoleculeStretchBondAction::performRedo(Action::state_ptr _state){ MoleculeStretchBondState *state = assert_cast(_state.get()); // use given plane to undo const Vector PositiveShift = state->shift * state->bondplane.getNormal(); const Vector NegativeShift = -state->shift * state->bondplane.getNormal(); Box &domain = World::getInstance().getDomain(); for (molecule::iterator iter = state->mol->begin(); iter != state->mol->end(); ++iter) { const Vector &position = (*iter)->getPosition(); // for each atom determine on which side of plane it is and shift accordingly if (state->bondplane.SignedDistance(position) > 0) { (*iter)->setPosition( domain.enforceBoundaryConditions(position+PositiveShift) ); } else { (*iter)->setPosition( domain.enforceBoundaryConditions(position+NegativeShift) ); } } return Action::state_ptr(_state); } bool MoleculeStretchBondAction::canUndo() { return true; } bool MoleculeStretchBondAction::shouldUndo() { return true; } /** =========== end of function ====================== */