// -*- C++ -*-
/*
* GChemPaint library
* chain.h
*
* Copyright (C) 2001-2004 Jean Bréfort <jean.brefort@normalesup.org>
*
* 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<Atom*, Bond*>::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<Atom*, Bond*>::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<Atom*, Bond*>::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<gcpAtom*, gcpChainElt>::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<gcpAtom*, gcpChainElt>::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<gcpAtom*, gcpChainElt>::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<gcpAtom*, gcpChainElt>::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<gcpAtom*, gcpChainElt>::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);
}
syntax highlighted by Code2HTML, v. 0.9.1