// -*- C++ -*- /* * GChemPaint library * chain.h * * Copyright (C) 2001-2004 Jean Bréfort * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 * USA */ #include "gchempaint-config.h" #include "chain.h" #include "molecule.h" #include "document.h" gcpChain::gcpChain(gcpBond* pBond, gcpAtom* pAtom, TypeId Type): Object(Type) { gcpAtom *pAtom0; if (pAtom) pAtom0 = (gcpAtom*)pBond->GetAtom(pAtom); else { pAtom0 = (gcpAtom*)pBond->GetAtom(1); pAtom = (gcpAtom*)pBond->GetAtom(0); } m_Bonds[pAtom].fwd = pBond; m_Bonds[pAtom0].rev = pBond; } gcpChain::gcpChain(gcpMolecule* Molecule, gcpAtom* pAtom, TypeId Type): Object(Type) { m_Molecule = Molecule; if (pAtom) { FindCycles(pAtom); } } /* * Add a bond in an existing molecule and update cycles * Implementation might have to be changed */ gcpChain::gcpChain(gcpMolecule* Molecule, gcpBond* pBond, TypeId Type): Object(Type) { m_Molecule = Molecule; if (pBond) { gcpAtom *pAtom0, *pAtom; pAtom0 = (gcpAtom*)pBond->GetAtom(0); m_Bonds[pAtom0].fwd = pBond; pAtom = (gcpAtom*)pBond->GetAtom(1); m_Bonds[pAtom].rev = pBond; map::iterator i; gcpBond* pBond0 = (gcpBond*)pAtom->GetFirstBond(i); while (pBond0) { if ((pBond0 != pBond) && FindCycle(pAtom, pBond0)) break; pBond0 = (gcpBond*)pAtom->GetNextBond(i); } } gcpDocument* pDoc = (gcpDocument*)m_Molecule->GetDocument(); if (pDoc) pDoc->Update(); } gcpChain::~gcpChain() { m_Bonds.clear(); } bool gcpChain::FindCycle(gcpAtom* pAtom, gcpBond* pBond) { gcpAtom* pAtom1 = (gcpAtom*)pBond->GetAtom(pAtom); if (m_Bonds[pAtom1].fwd != NULL) { if (m_Bonds[pAtom1].rev != NULL) return false; gcpCycle* pCycle = new gcpCycle(m_Molecule); pCycle->m_Bonds[pAtom1].rev = pBond; pCycle->m_Bonds[pAtom1].fwd = m_Bonds[pAtom1].fwd; pCycle->m_Bonds[pAtom].fwd = pBond; pCycle->m_Bonds[pAtom].rev= m_Bonds[pAtom].rev; m_Bonds[pAtom].rev->AddCycle(pCycle); pBond->AddCycle(pCycle); while (pBond = pCycle->m_Bonds[pAtom1].fwd, pAtom1 = (gcpAtom*)pBond->GetAtom(pAtom1), pAtom != pAtom1) { pCycle->m_Bonds[pAtom1].rev = pBond; pCycle->m_Bonds[pAtom1].fwd = m_Bonds[pAtom1].fwd; pBond->AddCycle(pCycle); } pCycle->Simplify();//to reduce size of fused cycles return true; } m_Bonds[pAtom].fwd = pBond; m_Bonds[pAtom1].rev = pBond; map::iterator i; gcpBond* pBond1 = (gcpBond*)pAtom1->GetFirstBond(i); while (pBond1) { if ((pBond1 != pBond) && FindCycle(pAtom1, pBond1)) return true; pBond1 = (gcpBond*)pAtom1->GetNextBond(i); } m_Bonds[pAtom].fwd = NULL; m_Bonds.erase(pAtom1); return false; } void gcpChain::FindCycles(gcpAtom* pAtom) { map::iterator i; gcpBond* pBond = (gcpBond*)pAtom->GetFirstBond(i); gcpAtom* pAtom0; while (pBond != NULL) { m_Bonds[pAtom].fwd = pBond; pAtom0 = (gcpAtom*)pBond->GetAtom(pAtom); if (pBond->GetMolecule() != m_Molecule) { m_Molecule->AddBond(pBond); } if ((pAtom0)->GetMolecule() != m_Molecule) { if (pAtom0->GetMolecule() != m_Molecule) pAtom0->AddToMolecule(m_Molecule); m_Bonds[pAtom0].rev = pBond; FindCycles(pAtom0); } else { if (m_Bonds[pAtom0].fwd != NULL) { gcpBond* pBond0 = m_Bonds[pAtom0].fwd; if (pAtom != pBond0->GetAtom(pAtom0)) //Cycle found. { gcpCycle* pCycle = new gcpCycle(m_Molecule); pCycle->m_Bonds[pAtom0].rev = pBond; pCycle->m_Bonds[pAtom0].fwd = pBond0; pBond0->AddCycle(pCycle); while (pAtom != pAtom0) { pAtom0 = (gcpAtom*)pBond0->GetAtom(pAtom0); pCycle->m_Bonds[pAtom0].rev = pBond0; pBond0 = m_Bonds[pAtom0].fwd; pCycle->m_Bonds[pAtom0].fwd = pBond0; pBond0->AddCycle(pCycle); } pCycle->Simplify();//to reduce size of fused cycles } } } pBond = (gcpBond*)pAtom->GetNextBond(i); } m_Bonds.erase(pAtom); } void gcpChain::Reverse() { map::iterator i; gcpBond* pBond; for (i = m_Bonds.begin(); i != m_Bonds.end(); i++) { pBond = (*i).second.fwd; (*i).second.fwd = (*i).second.rev; (*i).second.rev = pBond; } } void gcpChain::Erase(gcpAtom* pAtom1, gcpAtom* pAtom2) {//This function is not safe gcpAtom *pAtom = (gcpAtom*)m_Bonds[pAtom1].fwd->GetAtom(pAtom1), *pAtom0; m_Bonds[pAtom1].fwd = NULL; while (pAtom != pAtom2) { pAtom = (gcpAtom*)m_Bonds[pAtom].fwd->GetAtom(pAtom0 = pAtom); m_Bonds.erase(pAtom0); } m_Bonds[pAtom2].rev = NULL; } void gcpChain::Insert(gcpAtom* pAtom1, gcpAtom* pAtom2, gcpChain& Chain) {//This function is not safe m_Bonds[pAtom1].fwd = Chain.m_Bonds[pAtom1].fwd; gcpAtom *pAtom = (gcpAtom*)m_Bonds[pAtom1].fwd->GetAtom(pAtom1); while (pAtom != pAtom2) { m_Bonds[pAtom] = Chain.m_Bonds[pAtom]; pAtom = (gcpAtom*)m_Bonds[pAtom].fwd->GetAtom(pAtom); } m_Bonds[pAtom2].rev = Chain.m_Bonds[pAtom2].rev; } void gcpChain::Extract(gcpAtom* pAtom1, gcpAtom* pAtom2, gcpChain& Chain) { Chain.m_Bonds.clear(); if (m_Bonds[pAtom1].fwd == NULL) { if (m_Bonds[pAtom1].rev == NULL) m_Bonds.erase(pAtom1);//pAtom1 is not in the chain return; } Chain.m_Bonds[pAtom1].fwd = m_Bonds[pAtom1].fwd; Chain.m_Bonds[pAtom1].rev = NULL; gcpAtom *pAtom = (gcpAtom*)Chain.m_Bonds[pAtom1].fwd->GetAtom(pAtom1); while (pAtom != pAtom2) { Chain.m_Bonds[pAtom] = m_Bonds[pAtom]; if (m_Bonds[pAtom].fwd == NULL) return; //Chain never reach pAtom2 pAtom = (gcpAtom*)m_Bonds[pAtom].fwd->GetAtom(pAtom); } Chain.m_Bonds[pAtom2].rev = m_Bonds[pAtom2].rev; Chain.m_Bonds[pAtom2].fwd = NULL; } unsigned gcpChain::GetUnsaturations() { unsigned n = 0; std::map::iterator i; for (i = m_Bonds.begin(); i != m_Bonds.end(); i++) if ((*i).second.fwd && ((*i).second.fwd->GetOrder() > 1)) n += 1; return n; } unsigned gcpChain::GetHeteroatoms() { unsigned n = 0; std::map::iterator i; for (i = m_Bonds.begin(); i != m_Bonds.end(); i++) if ((*i).first->GetZ() != 6) n += 1; return n; } void gcpChain::AddBond(gcpAtom* start, gcpAtom* end) { gcpBond* pBond = (gcpBond*)start->GetBond(end); m_Bonds[start].fwd = pBond; m_Bonds[end].rev = pBond; } bool gcpChain::Contains(gcpAtom* pAtom) { if ((m_Bonds[pAtom].fwd == NULL) && (m_Bonds[pAtom].rev == NULL)) { m_Bonds.erase(pAtom); return false; } else return true; } bool gcpChain::Contains(gcpBond* pBond) { gcpAtom *pAtom = (gcpAtom*)pBond->GetAtom(0); if ((m_Bonds[pAtom].fwd == NULL) && (m_Bonds[pAtom].rev == NULL)) { m_Bonds.erase(pAtom); return false; } if ((m_Bonds[pAtom].fwd == pBond) && (m_Bonds[pAtom].rev == pBond)) return true; return false; } unsigned gcpChain::GetLength() { unsigned n = 0; std::map::iterator i; for (i = m_Bonds.begin(); i != m_Bonds.end(); i++) if ((*i).second.fwd) n++; return n; } double gcpChain::GetMeanBondLength() { unsigned n = 0; double l = 0; std::map::iterator i; for (i = m_Bonds.begin(); i != m_Bonds.end(); i++) if ((*i).second.fwd) { n++; l += (*i).second.fwd->Get2DLength(); } return l / n; } gcpAtom* gcpChain::GetNextAtom(gcpAtom* pAtom) { return (gcpAtom*)m_Bonds[pAtom].fwd->GetAtom(pAtom); }