| 1 | /********************************************************************** | 
| 2 | base.cpp - Base classes to build a graph | 
| 3 |  | 
| 4 | Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc. | 
| 5 | Some portions Copyright (C) 2001-2005 by Geoffrey R. Hutchison | 
| 6 |  | 
| 7 | This file is part of the Open Babel project. | 
| 8 | For more information, see <http://openbabel.sourceforge.net/> | 
| 9 |  | 
| 10 | This program is free software; you can redistribute it and/or modify | 
| 11 | it under the terms of the GNU General Public License as published by | 
| 12 | the Free Software Foundation version 2 of the License. | 
| 13 |  | 
| 14 | This program is distributed in the hope that it will be useful, | 
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| 17 | GNU General Public License for more details. | 
| 18 | ***********************************************************************/ | 
| 19 |  | 
| 20 | #include "config.h" | 
| 21 | #include "base.hpp" | 
| 22 |  | 
| 23 | #if HAVE_IOSTREAM | 
| 24 | #include <iostream> | 
| 25 | #elif HAVE_IOSTREAM_H | 
| 26 | #include <iostream.h> | 
| 27 | #endif | 
| 28 |  | 
| 29 | #if HAVE_FSTREAM | 
| 30 | #include <fstream> | 
| 31 | #elif HAVE_FSTREAM_H | 
| 32 | #include <fstream.h> | 
| 33 | #endif | 
| 34 |  | 
| 35 | using namespace std; | 
| 36 |  | 
| 37 | //! Global namespace for all Open Babel code | 
| 38 | namespace OpenBabel | 
| 39 | { | 
| 40 | /* | 
| 41 | bool OBGraphBase::Match(OBGraphBase &g,bool singleMatch) | 
| 42 | { | 
| 43 | SetFinishedMatch(false); | 
| 44 | SetSingleMatch(singleMatch); | 
| 45 | ClearMatches(); | 
| 46 | g.SetVisitLock(true); | 
| 47 | g.ResetVisitFlags(); | 
| 48 |  | 
| 49 | OBNodeBase *node; | 
| 50 | OBNodeBase *seed = GetFirstSeed(); | 
| 51 | vector<OBNodeBase*>::iterator i; | 
| 52 |  | 
| 53 | for (node = g.Begin(i);node;node = g.Next(i)) | 
| 54 | if (!node->Visit && seed->Eval(node)) | 
| 55 | { | 
| 56 | node->Visit = true; | 
| 57 | seed->SetMatch(node); | 
| 58 | Match(g,BgnMatch(),BgnMatch()->second.begin()); | 
| 59 | seed->SetMatch((OBNodeBase*)NULL); | 
| 60 | node->Visit = false; | 
| 61 | if (SingleMatch() && FinishedMatch()) | 
| 62 | break; | 
| 63 | } | 
| 64 |  | 
| 65 | g.SetVisitLock(false); | 
| 66 |  | 
| 67 | return(FinishedMatch()); | 
| 68 | } | 
| 69 |  | 
| 70 | bool OBGraphBase::Match(OBGraphBase &g, | 
| 71 | vector<pair<OBNodeBase*,vector<OBEdgeBase*> > >::iterator i, | 
| 72 | vector<OBEdgeBase*>::iterator j) | 
| 73 | { | 
| 74 | //bail if only one match has been requested | 
| 75 | if (SingleMatch() && FinishedMatch()) | 
| 76 | return(true); | 
| 77 |  | 
| 78 | //full match completed | 
| 79 | if (i == EndMatch() || (j == i->second.end() && (i+1) == EndMatch())) | 
| 80 | { | 
| 81 | SetFinishedMatch(true); | 
| 82 | OBNodeBase *node; | 
| 83 | vector<OBNodeBase*> vn; | 
| 84 | vector<OBNodeBase*>::iterator i; | 
| 85 | for (node = Begin(i);node;node = Next(i)) | 
| 86 | vn.push_back(node->GetMatch()); | 
| 87 | PushBack(vn); | 
| 88 |  | 
| 89 | return(true); | 
| 90 | } | 
| 91 |  | 
| 92 | //handle next seed of disconnected pattern | 
| 93 | if (j == i->second.end()) | 
| 94 | { | 
| 95 | i++; | 
| 96 | OBNodeBase *node; | 
| 97 | OBNodeBase *seed = i->first; | 
| 98 | vector<OBNodeBase*>::iterator k; | 
| 99 | for (node = g.Begin(k);node;node = g.Next(k)) | 
| 100 | if (!node->Visit && seed->Eval(node)) | 
| 101 | { | 
| 102 | node->Visit = true; | 
| 103 | seed->SetMatch(node); | 
| 104 | Match(g,i,i->second.begin()); | 
| 105 | seed->SetMatch((OBNodeBase*)NULL); | 
| 106 | node->Visit = false; | 
| 107 | if (SingleMatch() && FinishedMatch()) | 
| 108 | break; | 
| 109 | } | 
| 110 | return(true); | 
| 111 | } | 
| 112 |  | 
| 113 | OBEdgeBase *edge = *j++; | 
| 114 | if (edge->IsClosure()) //check to see if matched atoms are bonded | 
| 115 | { | 
| 116 | if (edge->GetBgn()->GetMatch()->IsConnected(edge->GetEnd()->GetMatch())) | 
| 117 | Match(g,i,j); | 
| 118 | } | 
| 119 | else //bond hasn't been covered yet | 
| 120 | { | 
| 121 | OBNodeBase *nbr; | 
| 122 | OBNodeBase *curr = edge->GetBgn(); | 
| 123 | OBNodeBase *next = edge->GetEnd(); | 
| 124 | OBNodeBase *match = curr->GetMatch(); | 
| 125 | vector<OBEdgeBase*>::iterator k; | 
| 126 |  | 
| 127 | for (nbr = match->BeginNbr(k);nbr;nbr = match->NextNbr(k)) | 
| 128 | if (!nbr->Visit && next->Eval(nbr) && edge->Eval(*k)) | 
| 129 | { | 
| 130 | nbr->Visit = true; | 
| 131 | next->SetMatch(nbr); | 
| 132 | Match(g,i,j); | 
| 133 | next->SetMatch(NULL); | 
| 134 | nbr->Visit = false; | 
| 135 | } | 
| 136 | } | 
| 137 |  | 
| 138 | return(false); | 
| 139 | } | 
| 140 | */ | 
| 141 | OBNodeBase *OBGraphBase::Begin(vector<OBNodeBase*>::iterator &i) | 
| 142 | { | 
| 143 | i = _vatom.begin(); | 
| 144 | return((i != _vatom.end()) ? *i : NULL); | 
| 145 | } | 
| 146 |  | 
| 147 | OBNodeBase *OBGraphBase::Next(vector<OBNodeBase*>::iterator &i) | 
| 148 | { | 
| 149 | i++; | 
| 150 | return((i != _vatom.end()) ? *i : NULL); | 
| 151 | } | 
| 152 |  | 
| 153 | OBEdgeBase *OBGraphBase::Begin(vector<OBEdgeBase*>::iterator &i) | 
| 154 | { | 
| 155 | i = _vbond.begin(); | 
| 156 | return((i != _vbond.end()) ? *i : NULL); | 
| 157 | } | 
| 158 |  | 
| 159 | OBEdgeBase *OBGraphBase::Next(vector<OBEdgeBase*>::iterator &i) | 
| 160 | { | 
| 161 | i++; | 
| 162 | return((i != _vbond.end()) ? *i : NULL); | 
| 163 | } | 
| 164 |  | 
| 165 | OBNodeBase *OBNodeBase::BeginNbr(vector<OBEdgeBase*>::iterator &i) | 
| 166 | { | 
| 167 | i = _vbond.begin(); | 
| 168 |  | 
| 169 | if (i == _vbond.end()) | 
| 170 | return(NULL); | 
| 171 | return((this == (*i)->GetBgn()) ? (*i)->GetEnd() : (*i)->GetBgn()); | 
| 172 | } | 
| 173 |  | 
| 174 | OBNodeBase *OBNodeBase::NextNbr(vector<OBEdgeBase*>::iterator &i) | 
| 175 | { | 
| 176 | i++; | 
| 177 | if (i == _vbond.end()) | 
| 178 | return(NULL); | 
| 179 | return((this == (*i)->GetBgn()) ? (*i)->GetEnd() : (*i)->GetBgn()); | 
| 180 | } | 
| 181 |  | 
| 182 | void OBNodeBase::SetParent(OBGraphBase *p) | 
| 183 | { | 
| 184 | _parent = p; | 
| 185 | } | 
| 186 |  | 
| 187 | void OBEdgeBase::SetParent(OBGraphBase *p) | 
| 188 | { | 
| 189 | _parent = p; | 
| 190 | } | 
| 191 |  | 
| 192 | bool OBNodeBase::IsConnected(OBNodeBase *nb) | 
| 193 | { | 
| 194 | vector<OBEdgeBase*>::iterator i; | 
| 195 | for (i = _vbond.begin();i != _vbond.end();i++) | 
| 196 | if (nb == (*i)->GetBgn() || nb == (*i)->GetEnd()) | 
| 197 | return(true); | 
| 198 |  | 
| 199 | return(false); | 
| 200 | } | 
| 201 |  | 
| 202 | void OBGraphBase::ResetVisitFlags() | 
| 203 | { | 
| 204 | OBNodeBase *nb; | 
| 205 | vector<OBNodeBase*>::iterator i; | 
| 206 | for (nb = Begin(i);nb;nb = Next(i)) | 
| 207 | nb->Visit = false; | 
| 208 |  | 
| 209 | OBEdgeBase *eb; | 
| 210 | vector<OBEdgeBase*>::iterator j; | 
| 211 | for (eb = Begin(j);eb;eb = Next(j)) | 
| 212 | eb->Visit = false; | 
| 213 | } | 
| 214 |  | 
| 215 | bool OBGraphBase::SetVisitLock(bool v) | 
| 216 | { | 
| 217 | if (v && _vlock) | 
| 218 | return(false); | 
| 219 | _vlock = v; | 
| 220 | return(true); | 
| 221 | } | 
| 222 |  | 
| 223 | /*! \mainpage | 
| 224 |  | 
| 225 | \section intro Introduction and History | 
| 226 |  | 
| 227 | It is fair to say that Open Babel is a direct result of the original Babel. | 
| 228 | Application development is facilitated | 
| 229 | by building software on top of libraries rich in functionality. Babel | 
| 230 | was the first experience for Matt Stahl in designing a molecule | 
| 231 | library. In addition to developing Babel, Pat Walters and Matt | 
| 232 | developed `OBabel' at Vertex Pharmaceuticals, a first | 
| 233 | attempt at developing an object oriented molecule library. | 
| 234 | Matt later designed a new molecule class library, OELib -- designed | 
| 235 | to be flexible, extensible, portable, and efficient. | 
| 236 |  | 
| 237 | OELib was released under the GNU General Public License (GPL) by Matt Stahl | 
| 238 | and Open Eye Scientific Software, Inc. to take advantage of many of | 
| 239 | the "great minds writing chemical software." Open Babel took up where | 
| 240 | OELib and Babel left off, starting from the existing GPL version of | 
| 241 | OELib, and has continued to evolve and improve into a separate | 
| 242 | high-quality chemistry class library and tool. Open Babel is now a | 
| 243 | separate project and library and has changed considerably from the OELib days. | 
| 244 |  | 
| 245 | Thanks to all who have helped with Babel, OBabel, OELib and Open Babel. | 
| 246 | The list is long and growing. | 
| 247 |  | 
| 248 | \section pointers Key Modules | 
| 249 |  | 
| 250 | The heart of Open Babel lies in the \link OpenBabel::OBMol OBMol\endlink, | 
| 251 | \link OpenBabel::OBAtom OBAtom\endlink, and | 
| 252 | \link OpenBabel::OBBond OBBond\endlink classes, | 
| 253 | which handle operations on atoms, bonds and molecules. Newcomers should | 
| 254 | start with looking at the \link OpenBabel::OBMol OBMol\endlink class, | 
| 255 | designed to store the basic information | 
| 256 | in a molecule and to perceive information about a molecule. | 
| 257 |  | 
| 258 | One of the key philosophies in the code is that transformations and | 
| 259 | automatic perception of properties are performed in a <a href="http://en.wikipedia.org/wiki/Lazy_evaluation">"lazy"</a> | 
| 260 | manner. That is, until you call for partial atomic charges, no | 
| 261 | charges are calculated. This ensures faster transformations of | 
| 262 | chemical data -- properties that are not needed for your code will | 
| 263 | typically not be calculated. When such data is needed, appropriate | 
| 264 | routines are called, and a "flag" is set (e.g., via OBMol::SetFlag | 
| 265 | or OBAtom::SetFlag etc.) so that the code is only run once. | 
| 266 |  | 
| 267 | Arbitrary custom data and text descriptors can be stored in any atom, | 
| 268 | bond, molecule, or residue using the \link OpenBabel::OBGenericData | 
| 269 | OBGenericData\endlink or \link OpenBabel::OBPairData | 
| 270 | OBPairData\endlink classes. | 
| 271 |  | 
| 272 | Conversion between various chemical file formats is accomplished through | 
| 273 | the \link OpenBabel::OBConversion OBConversion\endlink and \link | 
| 274 | OpenBabel::OBFormat OBFormat\endlink classes, often through use of the \link | 
| 275 | OpenBabel::OBMoleculeFormat OBMoleculeFormat\endlink subclass which is designed | 
| 276 | for easy read/write access to one or more \link OpenBabel::OBMol OBMol\endlink | 
| 277 | objects. The philosophy of the file format codes is to parse as much | 
| 278 | chemical information from a given file as possible (no data left | 
| 279 | behind) and ideally any perception or transformations will occur when | 
| 280 | writing to some other format later. | 
| 281 |  | 
| 282 | */ | 
| 283 |  | 
| 284 | } // namespace OpenBabel | 
| 285 |  | 
| 286 | //! \file base.cpp | 
| 287 | //! \brief Implementation of base classes. |