1 // 2 // Copyright (C) 2001-2021 Greg Landrum and other RDKit contributors 3 // 4 // @@ All Rights Reserved @@ 5 // This file is part of the RDKit. 6 // The contents are covered by the terms of the BSD license 7 // which is included in the file license.txt, found at the root 8 // of the RDKit source tree. 9 // 10 #include <RDGeneral/export.h> 11 #ifndef _RD_BOND_H 12 #define _RD_BOND_H 13 14 // std stuff 15 #include <iostream> 16 17 // Ours 18 #include <RDGeneral/Invariant.h> 19 #include <Query/QueryObjects.h> 20 #include <RDGeneral/types.h> 21 #include <RDGeneral/RDProps.h> 22 #include <GraphMol/details.h> 23 24 namespace RDKit { 25 class ROMol; 26 class RWMol; 27 class Atom; 28 29 //! class for representing a bond 30 /*! 31 32 <b>Notes:</b> 33 - many of the methods of Atom require that the Atom be associated 34 with a molecule (an ROMol). 35 - each Bond maintains a Dict of \c properties: 36 - Each \c property is keyed by name and can store an 37 arbitrary type. 38 - \c Properties can be marked as \c calculated, in which case 39 they will be cleared when the \c clearComputedProps() method 40 is called. 41 - Because they have no impact upon chemistry, all \c property 42 operations are \c const, this allows extra flexibility for 43 clients who need to store extra data on Bond objects. 44 45 */ 46 class RDKIT_GRAPHMOL_EXPORT Bond : public RDProps { 47 friend class RWMol; 48 friend class ROMol; 49 50 public: 51 // FIX: grn... 52 typedef Queries::Query<int, Bond const *, true> QUERYBOND_QUERY; 53 54 //! the type of Bond 55 typedef enum { 56 UNSPECIFIED = 0, 57 SINGLE, 58 DOUBLE, 59 TRIPLE, 60 QUADRUPLE, 61 QUINTUPLE, 62 HEXTUPLE, 63 ONEANDAHALF, 64 TWOANDAHALF, 65 THREEANDAHALF, 66 FOURANDAHALF, 67 FIVEANDAHALF, 68 AROMATIC, 69 IONIC, 70 HYDROGEN, 71 THREECENTER, 72 DATIVEONE, //!< one-electron dative (e.g. from a C in a Cp ring to a metal) 73 DATIVE, //!< standard two-electron dative 74 DATIVEL, //!< standard two-electron dative 75 DATIVER, //!< standard two-electron dative 76 OTHER, 77 ZERO //!< Zero-order bond (from 78 // http://pubs.acs.org/doi/abs/10.1021/ci200488k) 79 } BondType; 80 81 //! the bond's direction (for chirality) 82 typedef enum { 83 NONE = 0, //!< no special style 84 BEGINWEDGE, //!< wedged: narrow at begin 85 BEGINDASH, //!< dashed: narrow at begin 86 // FIX: this may not really be adequate 87 ENDDOWNRIGHT, //!< for cis/trans 88 ENDUPRIGHT, //!< ditto 89 EITHERDOUBLE, //!< a "crossed" double bond 90 UNKNOWN, //!< intentionally unspecified stereochemistry 91 } BondDir; 92 93 //! the nature of the bond's stereochem (for cis/trans) 94 typedef enum { // stereochemistry of double bonds 95 STEREONONE = 0, // no special style 96 STEREOANY, // intentionally unspecified 97 // -- Put any true specifications about this point so 98 // that we can do comparisons like if(bond->getStereo()>Bond::STEREOANY) 99 STEREOZ, // Z double bond 100 STEREOE, // E double bond 101 STEREOCIS, // cis double bond 102 STEREOTRANS // trans double bond 103 } BondStereo; 104 105 Bond(); 106 //! construct with a particular BondType 107 explicit Bond(BondType bT); 108 Bond(const Bond &other); 109 virtual ~Bond(); 110 Bond &operator=(const Bond &other); 111 112 //! returns a copy 113 /*! 114 <b>Note:</b> the caller is responsible for <tt>delete</tt>ing 115 the returned pointer. 116 */ 117 virtual Bond *copy() const; 118 119 //! returns our \c bondType getBondType()120 BondType getBondType() const { return static_cast<BondType>(d_bondType); }; 121 //! sets our \c bondType setBondType(BondType bT)122 void setBondType(BondType bT) { d_bondType = bT; }; 123 //! \brief returns our \c bondType as a double 124 //! (e.g. SINGLE->1.0, AROMATIC->1.5, etc.) 125 double getBondTypeAsDouble() const; 126 127 //! returns our contribution to the explicit valence of an Atom 128 /*! 129 <b>Notes:</b> 130 - requires an owning molecule 131 */ 132 virtual double getValenceContrib(const Atom *at) const; 133 134 //! sets our \c isAromatic flag setIsAromatic(bool what)135 void setIsAromatic(bool what) { df_isAromatic = what; }; 136 //! returns the status of our \c isAromatic flag getIsAromatic()137 bool getIsAromatic() const { return df_isAromatic; }; 138 139 //! sets our \c isConjugated flag setIsConjugated(bool what)140 void setIsConjugated(bool what) { df_isConjugated = what; }; 141 //! returns the status of our \c isConjugated flag getIsConjugated()142 bool getIsConjugated() const { return df_isConjugated; }; 143 144 //! returns whether or not this instance belongs to a molecule hasOwningMol()145 bool hasOwningMol() const { return dp_mol != nullptr; }; 146 147 //! returns a reference to the ROMol that owns this instance getOwningMol()148 ROMol &getOwningMol() const { 149 PRECONDITION(dp_mol, "no owner"); 150 return *dp_mol; 151 }; 152 //! sets our owning molecule 153 void setOwningMol(ROMol *other); 154 //! sets our owning molecule setOwningMol(ROMol & other)155 void setOwningMol(ROMol &other) { setOwningMol(&other); }; 156 157 //! returns our index within the ROMol 158 /*! 159 <b>Notes:</b> 160 - this makes no sense if we do not have an owning molecule 161 162 */ getIdx()163 unsigned int getIdx() const { return d_index; }; 164 //! sets our index within the ROMol 165 /*! 166 <b>Notes:</b> 167 - this makes no sense if we do not have an owning molecule 168 - the index should be <tt>< this->getOwningMol()->getNumBonds()</tt> 169 */ setIdx(unsigned int index)170 void setIdx(unsigned int index) { d_index = index; }; 171 172 //! returns the index of our begin Atom 173 /*! 174 <b>Notes:</b> 175 - this makes no sense if we do not have an owning molecule 176 */ getBeginAtomIdx()177 unsigned int getBeginAtomIdx() const { return d_beginAtomIdx; }; 178 179 //! returns the index of our end Atom 180 /*! 181 <b>Notes:</b> 182 - this makes no sense if we do not have an owning molecule 183 */ getEndAtomIdx()184 unsigned int getEndAtomIdx() const { return d_endAtomIdx; }; 185 186 //! given the index of one Atom, returns the index of the other 187 /*! 188 <b>Notes:</b> 189 - this makes no sense if we do not have an owning molecule 190 */ 191 unsigned int getOtherAtomIdx(unsigned int thisIdx) const; 192 193 //! sets the index of our begin Atom 194 /*! 195 <b>Notes:</b> 196 - requires an owning molecule 197 */ 198 void setBeginAtomIdx(unsigned int what); 199 //! sets the index of our end Atom 200 /*! 201 <b>Notes:</b> 202 - requires an owning molecule 203 */ 204 void setEndAtomIdx(unsigned int what); 205 206 //! sets our begin Atom 207 /*! 208 <b>Notes:</b> 209 - requires an owning molecule 210 */ 211 void setBeginAtom(Atom *at); 212 //! sets our end Atom 213 /*! 214 <b>Notes:</b> 215 - requires an owning molecule 216 */ 217 void setEndAtom(Atom *at); 218 219 //! returns a pointer to our begin Atom 220 /*! 221 <b>Notes:</b> 222 - requires an owning molecule 223 */ 224 Atom *getBeginAtom() const; 225 //! returns a pointer to our end Atom 226 /*! 227 <b>Notes:</b> 228 - requires an owning molecule 229 */ 230 Atom *getEndAtom() const; 231 //! returns a pointer to the other Atom 232 /*! 233 <b>Notes:</b> 234 - requires an owning molecule 235 */ 236 Atom *getOtherAtom(Atom const *what) const; 237 238 // ------------------------------------ 239 // Please see the note in Atom.h for some explanation 240 // of these methods 241 // ------------------------------------ 242 243 // This method can be used to distinguish query bonds from standard bonds hasQuery()244 virtual bool hasQuery() const { return false; }; 245 246 // FIX: the const crap here is all mucked up. 247 //! NOT CALLABLE 248 virtual void setQuery(QUERYBOND_QUERY *what); 249 //! NOT CALLABLE 250 virtual QUERYBOND_QUERY *getQuery() const; 251 252 //! NOT CALLABLE 253 virtual void expandQuery( 254 QUERYBOND_QUERY *what, 255 Queries::CompositeQueryType how = Queries::COMPOSITE_AND, 256 bool maintainOrder = true); 257 258 //! returns whether or not we match the argument 259 /*! 260 <b>Notes:</b> 261 - for Bond objects, "match" means that either one of the Bonds 262 has \c bondType Bond::UNSPECIFIED or both Bonds have the 263 same \c bondType. 264 */ 265 virtual bool Match(Bond const *what) const; 266 267 //! sets our direction setBondDir(BondDir what)268 void setBondDir(BondDir what) { d_dirTag = what; }; 269 //! returns our direction getBondDir()270 BondDir getBondDir() const { return static_cast<BondDir>(d_dirTag); }; 271 272 //! sets our stereo code 273 /*! 274 STEREONONE, STEREOANY, STEREOE and STEREOZ can be set without 275 neighboring atoms specified in getStereoAtoms since they are 276 defined by the topology of the molecular graph. In order to set 277 STEREOCIS or STEREOTRANS the neighboring atoms must be set first 278 (using setStereoBonds()) to know what atoms are being considered. 279 280 <b>Notes:</b> 281 - MolOps::findPotentialStereoBonds can be used to set 282 getStereoAtoms before setting CIS/TRANS 283 */ setStereo(BondStereo what)284 void setStereo(BondStereo what) { 285 PRECONDITION(what <= STEREOE || getStereoAtoms().size() == 2, 286 "Stereo atoms should be specified before specifying CIS/TRANS " 287 "bond stereochemistry") 288 d_stereo = what; 289 }; 290 //! returns our stereo code getStereo()291 BondStereo getStereo() const { return static_cast<BondStereo>(d_stereo); }; 292 293 //! sets the atoms to be considered as reference points for bond stereo 294 /*! 295 These do not necessarily need to be the highest 'ranking' atoms 296 like CIP stereo requires. They can be any arbitrary atoms 297 neighboring the begin and end atoms of this bond 298 respectively. STEREOCIS or STEREOTRANS is then set relative to 299 only these atoms. 300 301 If CIP rankings are desired, use 302 MolOps::findPotentialStereoBonds, but this is a more costly 303 function as it takes the whole molecule topology into account. 304 */ 305 void setStereoAtoms(unsigned int bgnIdx, unsigned int endIdx); 306 307 //! returns the indices of our stereo atoms getStereoAtoms()308 const INT_VECT &getStereoAtoms() const { 309 if (!dp_stereoAtoms) { 310 const_cast<Bond *>(this)->dp_stereoAtoms = new INT_VECT(); 311 } 312 return *dp_stereoAtoms; 313 }; 314 //! \overload getStereoAtoms()315 INT_VECT &getStereoAtoms() { 316 if (!dp_stereoAtoms) dp_stereoAtoms = new INT_VECT(); 317 return *dp_stereoAtoms; 318 }; 319 320 //! calculates any of our lazy \c properties 321 /*! 322 <b>Notes:</b> 323 - requires an owning molecule 324 */ 325 void updatePropertyCache(bool strict = true) { (void)strict; } 326 327 protected: 328 //! sets our owning molecule 329 // void setOwningMol(ROMol *other); 330 //! sets our owning molecule 331 // void setOwningMol(ROMol &other) {setOwningMol(&other);}; 332 bool df_isAromatic; 333 bool df_isConjugated; 334 std::uint8_t d_bondType; 335 std::uint8_t d_dirTag; 336 std::uint8_t d_stereo; 337 atomindex_t d_index; 338 atomindex_t d_beginAtomIdx, d_endAtomIdx; 339 ROMol *dp_mol; 340 INT_VECT *dp_stereoAtoms; 341 342 void initBond(); 343 }; 344 345 //! returns twice the \c bondType 346 //! (e.g. SINGLE->2, AROMATIC->3, etc.) 347 uint8_t getTwiceBondType(const RDKit::Bond &b); 348 349 }; // namespace RDKit 350 351 //! allows Bond objects to be dumped to streams 352 RDKIT_GRAPHMOL_EXPORT extern std::ostream &operator<<(std::ostream &target, 353 const RDKit::Bond &b); 354 355 #endif 356