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