// -*- C++ -*-
/*
* GChemPaint library
* cycle.cc
*
* 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 "molecule.h"
gcpCycle::gcpCycle(gcpMolecule* Molecule): gcpChain(Molecule, (gcpAtom*)NULL, CycleType)
{
}
gcpCycle::~gcpCycle()
{
}
void gcpCycle::Simplify()
{
std::map<gcpAtom*, gcpChainElt>::iterator i, k;
for (i = m_Bonds.begin(); i != m_Bonds.end(); i++)
{
if ((*i).second.fwd->IsCyclic() > 1)
{
std::list<gcpCycle*>::iterator j;
gcpCycle* pCycle = (*i).second.fwd->GetFirstCycle(j, this);
while (pCycle)
{
for (k = pCycle->m_Bonds.begin(); (*k).second.fwd != (*i).second.fwd; k++);
gcpAtom *pAtom0 = (*i).first, *pAtom1, *pAtom2;
bool bReverse = (pAtom0 != (*k).first);
gcpBond *pBond0 = (*i).second.fwd, *pBond;
gcpCycle Common(NULL);
Common.m_Bonds[pAtom0].fwd = pBond0;
pAtom1 = pAtom2 = pAtom0;
pBond = pBond0;
pAtom2 = (gcpAtom*)pBond0->GetAtom(pAtom2);
Common.m_Bonds[pAtom2].rev = pBond;
if (bReverse)
{
//explore forward
while ((pBond = m_Bonds[pAtom2].fwd) == pCycle->m_Bonds[pAtom2].rev)
{
Common.m_Bonds[pAtom2].fwd = pBond;
pAtom2 = (gcpAtom*)pBond->GetAtom(pAtom2);
Common.m_Bonds[pAtom2].rev = pBond;
}
//explore reverse
while ((pBond0 = m_Bonds[pAtom1].rev) == pCycle->m_Bonds[pAtom1].fwd)
{
Common.m_Bonds[pAtom1].rev = pBond0;
pAtom1 = (gcpAtom*)pBond0->GetAtom(pAtom1);
Common.m_Bonds[pAtom1].rev = pBond0;
}
}
else
{
//explore forward
while ((pBond = m_Bonds[pAtom2].fwd) == pCycle->m_Bonds[pAtom2].fwd)
{
Common.m_Bonds[pAtom2].fwd = pBond;
pAtom2 = (gcpAtom*)pBond->GetAtom(pAtom2);
Common.m_Bonds[pAtom2].rev = pBond;
}
//explore reverse
while ((pBond0 = m_Bonds[pAtom1].rev) == pCycle->m_Bonds[pAtom1].rev)
{
Common.m_Bonds[pAtom1].rev = pBond0;
pAtom1 = (gcpAtom*)pBond0->GetAtom(pAtom1);
Common.m_Bonds[pAtom1].rev = pBond0;
}
}
//Search if another portion is common to the two cycles
gcpAtom* pAtom = (gcpAtom*)m_Bonds[pAtom2].fwd->GetAtom(pAtom2);
while (pAtom != pAtom1)
{
if (pAtom->IsInCycle(pCycle)) break;
pAtom = (gcpAtom*)m_Bonds[pAtom].fwd->GetAtom(pAtom);
}
if (pAtom != pAtom1) {pCycle = (*i).second.fwd->GetNextCycle(j, this); continue;}
//Test for possible simplification
bool bLargest = (m_Bonds.size() > pCycle->m_Bonds.size());
unsigned n = (bLargest) ? pCycle->m_Bonds.size() : m_Bonds.size();
if (2 * (Common.m_Bonds.size() - 1) > n)
{
if (bLargest)
{
Erase(pAtom1, pAtom2);
if (bReverse)
{
pCycle->Extract(pAtom1, pAtom2, Common);
}
else
{
pCycle->Extract(pAtom2, pAtom1, Common);
Common.Reverse();
}
Insert(pAtom1, pAtom2, Common);
}
else
{
Extract(pAtom2, pAtom1, Common);
if (bReverse)
{
pCycle->Erase(pAtom2, pAtom1);
pCycle->Insert(pAtom2, pAtom1, Common);
}
else
{
Common.Reverse();
pCycle->Erase(pAtom1, pAtom2);
pCycle->Insert(pAtom1, pAtom2, Common);
}
}
Simplify();
return;
}
pCycle = (*i).second.fwd->GetNextCycle(j, this);
}
}
}
}
void gcpCycle::Erase(gcpAtom* pAtom1, gcpAtom* pAtom2)
{//This function is not safe
gcpAtom *pAtom = (gcpAtom*)m_Bonds[pAtom1].fwd->GetAtom(pAtom1), *pAtom0;
m_Bonds[pAtom1].fwd->RemoveCycle(this);
m_Bonds[pAtom1].fwd = NULL;
if (m_Bonds[pAtom1].rev->GetOrder() == 2) m_Bonds[pAtom1].rev->SetDirty();
while (pAtom != pAtom2)
{
m_Bonds[pAtom].fwd->RemoveCycle(this);
pAtom = (gcpAtom*)m_Bonds[pAtom].fwd->GetAtom(pAtom0 = pAtom);
m_Bonds.erase(pAtom0);
}
m_Bonds[pAtom2].rev = NULL;
if (m_Bonds[pAtom2].fwd->GetOrder() == 2) m_Bonds[pAtom2].fwd->SetDirty();
}
void gcpCycle::Insert(gcpAtom* pAtom1, gcpAtom* pAtom2, gcpChain& Chain)
{//This function is not safe
if (m_Bonds[pAtom1].rev->GetOrder() == 2) m_Bonds[pAtom1].rev->SetDirty();
m_Bonds[pAtom1].fwd = ((gcpCycle&)Chain).m_Bonds[pAtom1].fwd;
m_Bonds[pAtom1].fwd->AddCycle(this);
gcpAtom *pAtom = (gcpAtom*)m_Bonds[pAtom1].fwd->GetAtom(pAtom1);
while (pAtom != pAtom2)
{
m_Bonds[pAtom] = ((gcpCycle&)Chain).m_Bonds[pAtom];
m_Bonds[pAtom].fwd->AddCycle(this);
pAtom = (gcpAtom*)m_Bonds[pAtom].fwd->GetAtom(pAtom);
}
m_Bonds[pAtom2].rev = ((gcpCycle&)Chain).m_Bonds[pAtom2].rev;
if (m_Bonds[pAtom2].fwd->GetOrder() == 2) m_Bonds[pAtom2].fwd->SetDirty();
}
bool gcpCycle::IsBetterForBonds(gcpCycle* pCycle)
{
//Returns true if pCycle is better
//Prefered cycle should have a maximum unsaturation number
unsigned n1 = GetUnsaturations(), n2 = pCycle->GetUnsaturations();
if (n1 < n2) return true;
else if (n1 > n2) return false;
//Prefered cycle should be smallest
n1 = m_Bonds.size();
n2 = pCycle->m_Bonds.size();
if (n1 > n2) return true;
else if (n1 < n2) return false;
//Prefered Cycle should have a maximum heteroatoms
n1 = GetHeteroatoms();
n2 = pCycle->GetHeteroatoms();
if (n1 < n2) return true;
//Prefered cycle should have the least common bonds
n1 = GetFusedBonds();
n2 = pCycle->GetFusedBonds();
if (n1 > n2) return true;
else return false;
//if every thing is the same return false (this will be prefered)
}
void gcpCycle::GetAngles2D(gcpBond *pBond, double* a1, double* a2)
{
gcpAtom *pAtom1 = (gcpAtom*)pBond->GetAtom(0), *pAtom2 = (gcpAtom*)pBond->GetAtom(1);
if (m_Bonds[pAtom1].fwd == pBond)
{
*a1 = m_Bonds[pAtom1].rev->GetAngle2DRad(pAtom1);
*a2 = m_Bonds[pAtom2].fwd->GetAngle2DRad(pAtom2);
}
else
{
*a1 = m_Bonds[pAtom1].fwd->GetAngle2DRad(pAtom1);
*a2 = m_Bonds[pAtom2].rev->GetAngle2DRad(pAtom2);
}
}
int gcpCycle::GetFusedBonds()
{
int n = 0;
std::map<gcpAtom*, gcpChainElt>::iterator i;
for (i = m_Bonds.begin(); i != m_Bonds.end(); i++)
if ((*i).second.fwd->IsCyclic() > 1) n++;
return n;
}
syntax highlighted by Code2HTML, v. 0.9.1