Files
rdkit/Code/GraphMol/Bond.h
2015-03-22 16:46:36 +01:00

458 lines
14 KiB
C++

//
// Copyright (C) 2001-2014 Greg Landrum and Rational Discovery LLC
//
// @@ All Rights Reserved @@
// This file is part of the RDKit.
// The contents are covered by the terms of the BSD license
// which is included in the file license.txt, found at the root
// of the RDKit source tree.
//
#ifndef _RD_BOND_H
#define _RD_BOND_H
// std stuff
#include <iostream>
// Ours
// FIX: grn...
#include <Query/QueryObjects.h>
#include <RDGeneral/types.h>
#include <GraphMol/details.h>
#include <boost/foreach.hpp>
namespace RDKit{
class ROMol;
class RWMol;
class Atom;
typedef boost::shared_ptr<Atom> ATOM_SPTR;
//! class for representing a bond
/*!
<b>Notes:</b>
- many of the methods of Atom require that the Atom be associated
with a molecule (an ROMol).
- each Bond maintains a Dict of \c properties:
- Each \c property is keyed by name and can store an
arbitrary type.
- \c Properties can be marked as \c calculated, in which case
they will be cleared when the \c clearComputedProps() method
is called.
- Because they have no impact upon chemistry, all \c property
operations are \c const, this allows extra flexibility for
clients who need to store extra data on Bond objects.
*/
class Bond {
friend class RWMol;
friend class ROMol;
public:
typedef boost::shared_ptr<Bond> BOND_SPTR;
// FIX: grn...
typedef Queries::Query<int,Bond const *,true> QUERYBOND_QUERY;
//! the type of Bond
typedef enum {
UNSPECIFIED = 0,
SINGLE,
DOUBLE,
TRIPLE,
QUADRUPLE,
QUINTUPLE,
HEXTUPLE,
ONEANDAHALF,
TWOANDAHALF,
THREEANDAHALF,
FOURANDAHALF,
FIVEANDAHALF,
AROMATIC,
IONIC,
HYDROGEN,
THREECENTER,
DATIVEONE, //!< one-electron dative (e.g. from a C in a Cp ring to a metal)
DATIVE, //!< standard two-electron dative
DATIVEL, //!< standard two-electron dative
DATIVER, //!< standard two-electron dative
OTHER,
ZERO //!< Zero-order bond (from http://pubs.acs.org/doi/abs/10.1021/ci200488k)
} BondType;
//! the bond's direction (for chirality)
typedef enum {
NONE=0, //!< no special style
BEGINWEDGE, //!< wedged: narrow at begin
BEGINDASH, //!< dashed: narrow at begin
// FIX: this may not really be adequate
ENDDOWNRIGHT, //!< for cis/trans
ENDUPRIGHT, //!< ditto
EITHERDOUBLE, //!< a "crossed" double bond
UNKNOWN, //!< intentionally unspecified stereochemistry
} BondDir;
//! the nature of the bond's stereochem (for cis/trans)
typedef enum { // stereochemistry of double bonds
STEREONONE=0, // no special style
STEREOANY, // intentionally unspecified
// -- Put any true specifications about this point so
// that we can do comparisons like if(bond->getStereo()>Bond::STEREOANY)
STEREOZ, // Z double bond
STEREOE, // E double bond
} BondStereo;
Bond();
//! construct with a particular BondType
explicit Bond(BondType bT);
Bond(const Bond &other);
virtual ~Bond();
Bond &operator=(const Bond &other);
//! returns a copy
/*!
<b>Note:</b> the caller is responsible for <tt>delete</tt>ing
the returned pointer.
*/
virtual Bond *copy() const;
//! returns our \c bondType
BondType getBondType() const { return static_cast<BondType>(d_bondType); };
//! sets our \c bondType
void setBondType(BondType bT) { d_bondType = bT; };
//! \brief returns our \c bondType as a double
//! (e.g. SINGLE->1.0, AROMATIC->1.5, etc.)
double getBondTypeAsDouble() const;
//! returns our contribution to the explicit valence of an Atom
/*!
<b>Notes:</b>
- requires an owning molecule
*/
double getValenceContrib(const Atom *at) const;
// \overload
double getValenceContrib(ATOM_SPTR at) const;
//! sets our \c isAromatic flag
void setIsAromatic( bool what ) { df_isAromatic = what; };
//! returns the status of our \c isAromatic flag
bool getIsAromatic() const { return df_isAromatic; };
//! sets our \c isConjugated flag
void setIsConjugated(bool what) {df_isConjugated = what;};
//! returns the status of our \c isConjugated flag
bool getIsConjugated() const {return df_isConjugated;};
//! returns a reference to the ROMol that owns this Bond
ROMol &getOwningMol() const { return *dp_mol; };
//! sets our owning molecule
void setOwningMol(ROMol *other);
//! sets our owning molecule
void setOwningMol(ROMol &other) {setOwningMol(&other);};
//! returns our index within the ROMol
/*!
<b>Notes:</b>
- this makes no sense if we do not have an owning molecule
*/
unsigned int getIdx() const {return d_index;};
//! sets our index within the ROMol
/*!
<b>Notes:</b>
- this makes no sense if we do not have an owning molecule
- the index should be <tt>< this->getOwningMol()->getNumBonds()</tt>
*/
void setIdx(unsigned int index) {d_index=index;};
//! returns the index of our begin Atom
/*!
<b>Notes:</b>
- this makes no sense if we do not have an owning molecule
*/
unsigned int getBeginAtomIdx() const { return d_beginAtomIdx; };
//! returns the index of our end Atom
/*!
<b>Notes:</b>
- this makes no sense if we do not have an owning molecule
*/
unsigned int getEndAtomIdx() const { return d_endAtomIdx; };
//! given the index of one Atom, returns the index of the other
/*!
<b>Notes:</b>
- this makes no sense if we do not have an owning molecule
*/
unsigned int getOtherAtomIdx(unsigned int thisIdx) const;
//! sets the index of our begin Atom
/*!
<b>Notes:</b>
- requires an owning molecule
*/
void setBeginAtomIdx(unsigned int what);
//! sets the index of our end Atom
/*!
<b>Notes:</b>
- requires an owning molecule
*/
void setEndAtomIdx(unsigned int what);
//! sets our begin Atom
/*!
<b>Notes:</b>
- requires an owning molecule
*/
void setBeginAtom(Atom *at);
//! \overload
void setBeginAtom(ATOM_SPTR at);
//! sets our end Atom
/*!
<b>Notes:</b>
- requires an owning molecule
*/
void setEndAtom(Atom *at);
//! \overload
void setEndAtom(ATOM_SPTR at);
//! returns a pointer to our begin Atom
/*!
<b>Notes:</b>
- requires an owning molecule
*/
Atom *getBeginAtom() const;
//! returns a pointer to our end Atom
/*!
<b>Notes:</b>
- requires an owning molecule
*/
Atom *getEndAtom() const;
//! returns a pointer to the other Atom
/*!
<b>Notes:</b>
- requires an owning molecule
*/
Atom *getOtherAtom(Atom const *what) const;
// ------------------------------------
// Please see the note in Atom.h for some explanation
// of these methods
// ------------------------------------
// This method can be used to distinguish query bonds from standard bonds
virtual bool hasQuery() const { return false; };
// FIX: the const crap here is all mucked up.
//! NOT CALLABLE
virtual void setQuery(QUERYBOND_QUERY *what);
//! NOT CALLABLE
virtual QUERYBOND_QUERY *getQuery() const;
//! NOT CALLABLE
virtual void expandQuery(QUERYBOND_QUERY *what,
Queries::CompositeQueryType how=Queries::COMPOSITE_AND,
bool maintainOrder=true);
//! returns whether or not we match the argument
/*!
<b>Notes:</b>
- for Bond objects, "match" means that either one of the Bonds
has \c bondType Bond::UNSPECIFIED or both Bonds have the
same \c bondType.
*/
virtual bool Match(Bond const *what) const;
//! \overload
virtual bool Match(const Bond::BOND_SPTR what) const;
//! sets our direction
void setBondDir(BondDir what) { d_dirTag = what; };
//! returns our direction
BondDir getBondDir() const { return static_cast<BondDir>(d_dirTag); };
//! sets our stereo code
void setStereo(BondStereo what) { d_stereo = what; };
//! returns our stereo code
BondStereo getStereo() const { return static_cast<BondStereo>(d_stereo); };
//! returns the indices of our stereo atoms
const INT_VECT &getStereoAtoms() const {
if(!dp_stereoAtoms){
const_cast<Bond *>(this)->dp_stereoAtoms = new INT_VECT();
}
return *dp_stereoAtoms;
};
//! \overload
INT_VECT &getStereoAtoms() {
if(!dp_stereoAtoms) dp_stereoAtoms = new INT_VECT();
return *dp_stereoAtoms;
};
// ------------------------------------
// Local Property Dict functionality
// FIX: at some point this stuff should go in a mixin class
// ------------------------------------
//! returns a list with the names of our \c properties
STR_VECT getPropList() const {
return dp_props->keys();
}
//! sets a \c property value
/*!
\param key the name under which the \c property should be stored.
If a \c property is already stored under this name, it will be
replaced.
\param val the value to be stored
\param computed (optional) allows the \c property to be flagged
\c computed.
*/
template <typename T>
void setProp(const char *key,T val, bool computed=false) const{
//if(!dp_props) dp_props = new Dict();
std::string what(key);
setProp(what,val, computed);
}
//! \overload
template <typename T>
void setProp(const std::string &key,T val, bool computed=false ) const{
//setProp(key.c_str(),val);
if (computed) {
STR_VECT compLst;
getPropIfPresent(detail::computedPropName, compLst);
if (std::find(compLst.begin(), compLst.end(), key) == compLst.end()) {
compLst.push_back(key);
dp_props->setVal(detail::computedPropName, compLst);
}
}
dp_props->setVal(key,val);
}
//! allows retrieval of a particular property value
/*!
\param key the name under which the \c property should be stored.
If a \c property is already stored under this name, it will be
replaced.
\param res a reference to the storage location for the value.
<b>Notes:</b>
- if no \c property with name \c key exists, a KeyErrorException will be thrown.
- the \c boost::lexical_cast machinery is used to attempt type conversions.
If this fails, a \c boost::bad_lexical_cast exception will be thrown.
*/
template <typename T>
void getProp(const char *key,T &res) const {
PRECONDITION(dp_props,"getProp called on empty property dict");
dp_props->getVal(key,res);
}
//! \overload
template <typename T>
void getProp(const std::string &key,T &res) const {
PRECONDITION(dp_props,"getProp called on empty property dict");
dp_props->getVal(key,res);
}
//! \Overload
template <typename T>
T getProp(const char *key) const {
return dp_props->getVal<T>(key);
}
//! \overload
template <typename T>
T getProp(const std::string &key) const {
return dp_props->getVal<T>(key);
}
//! returns whether or not we have a \c property with name \c key
//! and assigns the value if we do
template <typename T>
bool getPropIfPresent(const char *key,T &res) const {
return dp_props->getValIfPresent(key,res);
}
//! \overload
template <typename T>
bool getPropIfPresent(const std::string &key,T &res) const {
return dp_props->getValIfPresent(key,res);
}
//! returns whether or not we have a \c property with name \c key
bool hasProp(const char *key) const {
if(!dp_props) return false;
return dp_props->hasVal(key);
};
//! \overload
bool hasProp(const std::string &key) const {
if(!dp_props) return false;
return dp_props->hasVal(key);
};
//! clears the value of a \c property
/*!
<b>Notes:</b>
- if no \c property with name \c key exists, a KeyErrorException
will be thrown.
- if the \c property is marked as \c computed, it will also be removed
from our list of \c computedProperties
*/
void clearProp(const char *key) const {
std::string what(key);
clearProp(what);
};
//! \overload
void clearProp(const std::string &key) const {
STR_VECT compLst;
if (getPropIfPresent(detail::computedPropName, compLst)) {
STR_VECT_I svi = std::find(compLst.begin(), compLst.end(), key);
if (svi != compLst.end()) {
compLst.erase(svi);
dp_props->setVal(detail::computedPropName, compLst);
}
}
dp_props->clearVal(key);
}
//! clears all of our \c computed \c properties
void clearComputedProps() const {
STR_VECT compLst;
if(getPropIfPresent(detail::computedPropName, compLst)) {
BOOST_FOREACH(const std::string &sv,compLst){
dp_props->clearVal(sv);
}
compLst.clear();
dp_props->setVal(detail::computedPropName, compLst);
}
}
//! calculates any of our lazy \c properties
/*!
<b>Notes:</b>
- requires an owning molecule
*/
void updatePropertyCache(bool strict=true) { (void)strict; }
protected:
//! sets our owning molecule
//void setOwningMol(ROMol *other);
//! sets our owning molecule
//void setOwningMol(ROMol &other) {setOwningMol(&other);};
bool df_isAromatic;
bool df_isConjugated;
boost::uint8_t d_bondType;
boost::uint8_t d_dirTag;
boost::uint8_t d_stereo;
atomindex_t d_index;
atomindex_t d_beginAtomIdx,d_endAtomIdx;
ROMol *dp_mol;
Dict *dp_props;
INT_VECT *dp_stereoAtoms;
void initBond();
};
};
//! allows Bond objects to be dumped to streams
extern std::ostream & operator<<(std::ostream& target, const RDKit::Bond &b);
#endif