/* * 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 . */ /* * BondAddAction.cpp * * Created on: Nov 12, 2012 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif //#include "CodePatterns/MemDebug.hpp" #include "Atom/atom.hpp" #include "Bond/bond.hpp" #include "CodePatterns/Assert.hpp" #include "CodePatterns/Log.hpp" #include "CodePatterns/Verbose.hpp" #include "Descriptors/AtomIdDescriptor.hpp" #include "molecule.hpp" #include "World.hpp" #include "WorldTime.hpp" #include #include #include "Actions/BondAction/BondAddAction.hpp" using namespace MoleCuilder; // and construct the stuff #include "BondAddAction.def" #include "Action_impl_pre.hpp" /** =========== define the function ====================== */ ActionState::ptr BondAddAction::performCall() { // check preconditions World& world = World::getInstance(); if (world.countSelectedAtoms() <= 1) { STATUS("There must be at least two atoms selected for BondAction Add."); return Action::failure; } // check if we are adding new atoms to a molecule molecules_t molecules; const molecule *add_to_mol_const = NULL; molecules.reserve(world.countSelectedAtoms()); for (World::AtomSelectionConstIterator firstiter = world.beginAtomSelection(); firstiter != world.endAtomSelection(); ++firstiter) { const molecule * const current_mol = firstiter->second->getMolecule(); molecules.push_back(current_mol); if (current_mol != NULL) { if (add_to_mol_const == NULL) add_to_mol_const = current_mol; else if (add_to_mol_const != current_mol) { // we encountered a second molecule, don't set the molecules molecules.clear(); add_to_mol_const = NULL; break; } } } bondPairIds_t bondPairIds; for (World::AtomSelectionConstIterator firstiter = world.beginAtomSelection(); firstiter != world.endAtomSelection(); ++firstiter) { for (World::AtomSelectionConstIterator seconditer = firstiter; seconditer != world.endAtomSelection(); ++seconditer) { if (firstiter == seconditer) continue; if (!(firstiter->second)->IsBondedTo(WorldTime::getTime(), seconditer->second)) bondPairIds.push_back( std::make_pair((firstiter->second)->getId(), (seconditer->second)->getId())); } } if (bondPairIds.empty()) { STATUS("All bonds are already present."); return Action::failure; } // create undo molecule *add_to_mol = NULL; if (add_to_mol_const != NULL) { add_to_mol = world.getMolecule(MoleculeById(add_to_mol_const->getId())); ASSERT( add_to_mol != NULL, "BondAddAction::performCall() - could not obtain molecule from World."); } BondAddState *UndoState = new BondAddState(bondPairIds, molecules, add_to_mol, params); // execute action for (bondPairIds_t::const_iterator iter = bondPairIds.begin(); iter != bondPairIds.end(); ++iter) { atom * const firstatom = world.getAtom(AtomById(iter->first)); atom * const secondatom = world.getAtom(AtomById(iter->second)); ASSERT((firstatom != NULL) && (secondatom != NULL), "BondAddAction::performCall() - at least one of the ids " +toString(iter->first)+" or "+toString(iter->second)+" is not present."); bond::ptr newbond = firstatom->addBond(WorldTime::getTime(), secondatom); newbond->setDegree(params.degree.get()); ASSERT( firstatom->IsBondedTo(WorldTime::getTime(), secondatom), "BondAddAction::performCall() - adding bond in between " +toString(*firstatom)+" and "+toString(*secondatom)+" failed."); } if (add_to_mol != NULL) for (World::AtomSelectionIterator firstiter = world.beginAtomSelection(); firstiter != world.endAtomSelection(); ++firstiter) { if (firstiter->second->getMolecule() != add_to_mol) add_to_mol->AddAtom(firstiter->second); } return ActionState::ptr(UndoState); } ActionState::ptr BondAddAction::performUndo(ActionState::ptr _state) { BondAddState *state = assert_cast(_state.get()); // check whether bond already existed World& world = World::getInstance(); for (bondPairIds_t::const_iterator iter = state->bondPairIds.begin(); iter != state->bondPairIds.end(); ++iter) { atom *firstatom = world.getAtom(AtomById(iter->first)); atom *secondatom = world.getAtom(AtomById(iter->second)); ASSERT((firstatom != NULL) && (secondatom != NULL), "BondAddAction::performCall() - at least one of the ids " +toString(iter->first)+" or "+toString(iter->second)+" is not present."); if (firstatom->IsBondedTo(WorldTime::getTime(), secondatom)) { firstatom->removeBond(WorldTime::getTime(), secondatom); } else { ELOG(2, "There is no bond in between "+toString(iter->first) +" and "+toString(iter->second)+"."); } } if (state->add_to_mol != NULL) { molecules_t::const_iterator mol_iter = state->molecules.begin(); for (World::AtomSelectionIterator firstiter = world.beginAtomSelection(); firstiter != world.endAtomSelection(); ++firstiter) { const molecule * const current_mol = *mol_iter++; atom * const Walker = firstiter->second; if (current_mol != Walker->getMolecule()) { if (Walker->getMolecule() != NULL) Walker->removeFromMolecule(); if (current_mol != NULL) { molecule *add_to_mol = world.getMolecule(MoleculeById(current_mol->getId())); add_to_mol->AddAtom(Walker); } } } ASSERT(mol_iter == state->molecules.end(), "BondAddAction::performUndo() - number of molecule ptrs not coinciding with number of selected atoms."); } return ActionState::ptr(_state); } ActionState::ptr BondAddAction::performRedo(ActionState::ptr _state){ BondAddState *state = assert_cast(_state.get()); // check whether bond already existed World& world = World::getInstance(); for (bondPairIds_t::const_iterator iter = state->bondPairIds.begin(); iter != state->bondPairIds.end(); ++iter) { atom * const firstatom = world.getAtom(AtomById(iter->first)); atom * const secondatom = world.getAtom(AtomById(iter->second)); ASSERT((firstatom != NULL) && (secondatom != NULL), "BondAddAction::performCall() - at least one of the ids " +toString(iter->first)+" or "+toString(iter->second)+" is not present."); if (!firstatom->IsBondedTo(WorldTime::getTime(), secondatom)) { firstatom->addBond(WorldTime::getTime(), secondatom); } else { ELOG(2, "There is already a bond in between "+toString(iter->first) +" and "+toString(iter->second)+"."); } } if (state->add_to_mol != NULL) for (World::AtomSelectionIterator firstiter = world.beginAtomSelection(); firstiter != world.endAtomSelection(); ++firstiter) { if (firstiter->second->getMolecule() != state->add_to_mol) state->add_to_mol->AddAtom(firstiter->second); } return ActionState::ptr(_state); } bool BondAddAction::canUndo() { return true; } bool BondAddAction::shouldUndo() { return true; } /** =========== end of function ====================== */