/src/rdkit/Code/GraphMol/Bond.h
Line | Count | Source |
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 <utility> |
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 | | STEREOATROPCW, // atropisomer clockwise rotation |
104 | | STEREOATROPCCW, // atropisomer counter clockwise rotation |
105 | | } BondStereo; |
106 | | |
107 | | Bond(); |
108 | | //! construct with a particular BondType |
109 | | explicit Bond(BondType bT); |
110 | | Bond(const Bond &other); |
111 | | virtual ~Bond(); |
112 | | Bond &operator=(const Bond &other); |
113 | | |
114 | 0 | Bond(Bond &&o) noexcept : RDProps(std::move(o)) { |
115 | 0 | df_isAromatic = o.df_isAromatic; |
116 | 0 | df_isConjugated = o.df_isConjugated; |
117 | 0 | d_bondType = o.d_bondType; |
118 | 0 | d_dirTag = o.d_dirTag; |
119 | 0 | d_stereo = o.d_stereo; |
120 | 0 | d_index = o.d_index; |
121 | 0 | d_beginAtomIdx = o.d_beginAtomIdx; |
122 | 0 | d_endAtomIdx = o.d_endAtomIdx; |
123 | 0 | // NOTE: this is somewhat fraught for bonds associated with molecules since |
124 | 0 | // the molecule will still be pointing to the original object |
125 | 0 | dp_mol = std::exchange(o.dp_mol, nullptr); |
126 | 0 | dp_stereoAtoms = std::exchange(o.dp_stereoAtoms, nullptr); |
127 | 0 | d_flags = std::exchange(o.d_flags, 0); |
128 | 0 | } |
129 | 0 | Bond &operator=(Bond &&o) noexcept { |
130 | 0 | if (this == &o) { |
131 | 0 | return *this; |
132 | 0 | } |
133 | 0 | RDProps::operator=(std::move(o)); |
134 | 0 | df_isAromatic = o.df_isAromatic; |
135 | 0 | df_isConjugated = o.df_isConjugated; |
136 | 0 | d_bondType = o.d_bondType; |
137 | 0 | d_dirTag = o.d_dirTag; |
138 | 0 | d_stereo = o.d_stereo; |
139 | 0 | d_index = o.d_index; |
140 | 0 | d_beginAtomIdx = o.d_beginAtomIdx; |
141 | 0 | d_endAtomIdx = o.d_endAtomIdx; |
142 | 0 | // NOTE: this is somewhat fraught for bonds associated with molecules since |
143 | 0 | // the molecule will still be pointing to the original object |
144 | 0 | delete dp_stereoAtoms; |
145 | 0 | dp_mol = std::exchange(o.dp_mol, nullptr); |
146 | 0 | dp_stereoAtoms = std::exchange(o.dp_stereoAtoms, nullptr); |
147 | 0 | d_flags = std::exchange(o.d_flags, 0); |
148 | 0 | return *this; |
149 | 0 | } |
150 | | |
151 | | //! returns a copy |
152 | | /*! |
153 | | <b>Note:</b> the caller is responsible for <tt>delete</tt>ing |
154 | | the returned pointer. |
155 | | */ |
156 | | virtual Bond *copy() const; |
157 | | |
158 | | //! returns our \c bondType |
159 | 611M | BondType getBondType() const { return static_cast<BondType>(d_bondType); } |
160 | | //! sets our \c bondType |
161 | 18.2M | void setBondType(BondType bT) { d_bondType = bT; } |
162 | | //! \brief returns our \c bondType as a double |
163 | | //! (e.g. SINGLE->1.0, AROMATIC->1.5, etc.) |
164 | | double getBondTypeAsDouble() const; |
165 | | |
166 | | //! returns our contribution to the explicit valence of an Atom |
167 | | /*! |
168 | | <b>Notes:</b> |
169 | | - requires an owning molecule |
170 | | */ |
171 | | virtual double getValenceContrib(const Atom *at) const; |
172 | | |
173 | | //! sets our \c isAromatic flag |
174 | 8.11M | void setIsAromatic(bool what) { df_isAromatic = what; } |
175 | | //! returns the status of our \c isAromatic flag |
176 | 160M | bool getIsAromatic() const { return df_isAromatic; } |
177 | | |
178 | | //! sets our \c isConjugated flag |
179 | 5.87M | void setIsConjugated(bool what) { df_isConjugated = what; } |
180 | | //! returns the status of our \c isConjugated flag |
181 | 900k | bool getIsConjugated() const { return df_isConjugated; } |
182 | | |
183 | | //! returns whether or not this instance belongs to a molecule |
184 | 4.22M | bool hasOwningMol() const { return dp_mol != nullptr; } |
185 | | |
186 | | //! returns a reference to the ROMol that owns this instance |
187 | 44.0M | ROMol &getOwningMol() const { |
188 | 44.0M | PRECONDITION(dp_mol, "no owner"); |
189 | 44.0M | return *dp_mol; |
190 | 44.0M | } |
191 | | //! sets our owning molecule |
192 | | void setOwningMol(ROMol *other); |
193 | | //! sets our owning molecule |
194 | 0 | void setOwningMol(ROMol &other) { setOwningMol(&other); } |
195 | | |
196 | | // inverts the chirality of an atropisomer |
197 | | bool invertChirality(); |
198 | | |
199 | | //! returns our index within the ROMol |
200 | | /*! |
201 | | <b>Notes:</b> |
202 | | - this makes no sense if we do not have an owning molecule |
203 | | |
204 | | */ |
205 | 282M | unsigned int getIdx() const { return d_index; } |
206 | | //! sets our index within the ROMol |
207 | | /*! |
208 | | <b>Notes:</b> |
209 | | - this makes no sense if we do not have an owning molecule |
210 | | - the index should be <tt>< this->getOwningMol()->getNumBonds()</tt> |
211 | | */ |
212 | 47.1M | void setIdx(unsigned int index) { d_index = index; } |
213 | | |
214 | | //! returns the index of our begin Atom |
215 | | /*! |
216 | | <b>Notes:</b> |
217 | | - this makes no sense if we do not have an owning molecule |
218 | | */ |
219 | 61.0M | unsigned int getBeginAtomIdx() const { return d_beginAtomIdx; } |
220 | | |
221 | | //! returns the index of our end Atom |
222 | | /*! |
223 | | <b>Notes:</b> |
224 | | - this makes no sense if we do not have an owning molecule |
225 | | */ |
226 | 58.0M | unsigned int getEndAtomIdx() const { return d_endAtomIdx; } |
227 | | |
228 | | //! given the index of one Atom, returns the index of the other |
229 | | /*! |
230 | | <b>Notes:</b> |
231 | | - this makes no sense if we do not have an owning molecule |
232 | | */ |
233 | | unsigned int getOtherAtomIdx(unsigned int thisIdx) const; |
234 | | |
235 | | //! sets the index of our begin Atom |
236 | | /*! |
237 | | <b>Notes:</b> |
238 | | - requires an owning molecule |
239 | | */ |
240 | | void setBeginAtomIdx(unsigned int what); |
241 | | //! sets the index of our end Atom |
242 | | /*! |
243 | | <b>Notes:</b> |
244 | | - requires an owning molecule |
245 | | */ |
246 | | void setEndAtomIdx(unsigned int what); |
247 | | |
248 | | //! sets our begin Atom |
249 | | /*! |
250 | | <b>Notes:</b> |
251 | | - requires an owning molecule |
252 | | */ |
253 | | void setBeginAtom(Atom *at); |
254 | | //! sets our end Atom |
255 | | /*! |
256 | | <b>Notes:</b> |
257 | | - requires an owning molecule |
258 | | */ |
259 | | void setEndAtom(Atom *at); |
260 | | |
261 | | //! returns a pointer to our begin Atom |
262 | | /*! |
263 | | <b>Notes:</b> |
264 | | - requires an owning molecule |
265 | | */ |
266 | | Atom *getBeginAtom() const; |
267 | | //! returns a pointer to our end Atom |
268 | | /*! |
269 | | <b>Notes:</b> |
270 | | - requires an owning molecule |
271 | | */ |
272 | | Atom *getEndAtom() const; |
273 | | //! returns a pointer to the other Atom |
274 | | /*! |
275 | | <b>Notes:</b> |
276 | | - requires an owning molecule |
277 | | */ |
278 | | Atom *getOtherAtom(Atom const *what) const; |
279 | | |
280 | | // ------------------------------------ |
281 | | // Please see the note in Atom.h for some explanation |
282 | | // of these methods |
283 | | // ------------------------------------ |
284 | | |
285 | | // This method can be used to distinguish query bonds from standard bonds |
286 | 81.1M | virtual bool hasQuery() const { return false; } |
287 | | |
288 | | // FIX: the const crap here is all mucked up. |
289 | | //! NOT CALLABLE |
290 | | virtual void setQuery(QUERYBOND_QUERY *what); |
291 | | //! NOT CALLABLE |
292 | | virtual QUERYBOND_QUERY *getQuery() const; |
293 | | |
294 | | //! NOT CALLABLE |
295 | | virtual void expandQuery( |
296 | | QUERYBOND_QUERY *what, |
297 | | Queries::CompositeQueryType how = Queries::COMPOSITE_AND, |
298 | | bool maintainOrder = true); |
299 | | |
300 | | //! returns whether or not we match the argument |
301 | | /*! |
302 | | <b>Notes:</b> |
303 | | - for Bond objects, "match" means that either one of the Bonds |
304 | | has \c bondType Bond::UNSPECIFIED or both Bonds have the |
305 | | same \c bondType. |
306 | | */ |
307 | | virtual bool Match(Bond const *what) const; |
308 | | |
309 | | //! sets our direction |
310 | 551k | void setBondDir(BondDir what) { d_dirTag = what; } |
311 | | //! returns our direction |
312 | 251M | BondDir getBondDir() const { return static_cast<BondDir>(d_dirTag); } |
313 | | |
314 | | //! sets our stereo code |
315 | | /*! |
316 | | STEREONONE, STEREOANY, STEREOE and STEREOZ can be set without |
317 | | neighboring atoms specified in getStereoAtoms since they are |
318 | | defined by the topology of the molecular graph. In order to set |
319 | | STEREOCIS or STEREOTRANS the neighboring atoms must be set first |
320 | | (using setStereoBonds()) to know what atoms are being considered. |
321 | | |
322 | | <b>Notes:</b> |
323 | | - MolOps::findPotentialStereoBonds can be used to set |
324 | | getStereoAtoms before setting CIS/TRANS |
325 | | */ |
326 | 699k | void setStereo(BondStereo what) { |
327 | 699k | PRECONDITION(((what != STEREOCIS && what != STEREOTRANS) || |
328 | 699k | getStereoAtoms().size() == 2), |
329 | 699k | "Stereo atoms should be specified before specifying CIS/TRANS " |
330 | 699k | "bond stereochemistry") |
331 | 699k | d_stereo = what; |
332 | 699k | } |
333 | | //! returns our stereo code |
334 | 25.8M | BondStereo getStereo() const { return static_cast<BondStereo>(d_stereo); } |
335 | | |
336 | | //! sets the atoms to be considered as reference points for bond stereo |
337 | | /*! |
338 | | These do not necessarily need to be the highest 'ranking' atoms |
339 | | like CIP stereo requires. They can be any arbitrary atoms |
340 | | neighboring the begin and end atoms of this bond |
341 | | respectively. STEREOCIS or STEREOTRANS is then set relative to |
342 | | only these atoms. |
343 | | |
344 | | If CIP rankings are desired, use |
345 | | MolOps::findPotentialStereoBonds, but this is a more costly |
346 | | function as it takes the whole molecule topology into account. |
347 | | */ |
348 | | void setStereoAtoms(unsigned int bgnIdx, unsigned int endIdx); |
349 | | |
350 | | //! returns the indices of our stereo atoms |
351 | 8.55k | const INT_VECT &getStereoAtoms() const { |
352 | 8.55k | if (!dp_stereoAtoms) { |
353 | 0 | const_cast<Bond *>(this)->dp_stereoAtoms = new INT_VECT(); |
354 | 0 | } |
355 | 8.55k | return *dp_stereoAtoms; |
356 | 8.55k | } |
357 | | //! \overload |
358 | 50.6M | INT_VECT &getStereoAtoms() { |
359 | 50.6M | if (!dp_stereoAtoms) { |
360 | 1.93M | dp_stereoAtoms = new INT_VECT(); |
361 | 1.93M | } |
362 | 50.6M | return *dp_stereoAtoms; |
363 | 50.6M | } |
364 | | |
365 | | //! calculates any of our lazy \c properties |
366 | | /*! |
367 | | <b>Notes:</b> |
368 | | - requires an owning molecule |
369 | | */ |
370 | 14.3M | void updatePropertyCache(bool strict = true) { (void)strict; } |
371 | | |
372 | | //! Flags that can be used by to store information on bonds. |
373 | | //! These are not serialized and should be treated as temporary values. |
374 | | //! No guarantees are made about preserving these flags across library |
375 | | //! calls. |
376 | 0 | void setFlags(std::uint64_t flags) { d_flags = flags; } |
377 | 0 | std::uint64_t getFlags() const { return d_flags; } |
378 | 0 | std::uint64_t &getFlags() { return d_flags; } |
379 | | |
380 | | protected: |
381 | | //! sets our owning molecule |
382 | | /// void setOwningMol(ROMol *other); |
383 | | //! sets our owning molecule |
384 | | /// void setOwningMol(ROMol &other) { setOwningMol(&other); } |
385 | | ROMol *dp_mol; |
386 | | INT_VECT *dp_stereoAtoms; |
387 | | atomindex_t d_index; |
388 | | atomindex_t d_beginAtomIdx, d_endAtomIdx; |
389 | | bool df_isAromatic; |
390 | | bool df_isConjugated; |
391 | | std::uint8_t d_bondType; |
392 | | std::uint8_t d_dirTag; |
393 | | std::uint8_t d_stereo; |
394 | | std::uint64_t d_flags = 0; |
395 | | |
396 | | void initBond(); |
397 | | }; |
398 | | |
399 | 25.1M | inline bool isDative(const Bond::BondType bt) { |
400 | 25.1M | return bt == Bond::BondType::DATIVE || bt == Bond::BondType::DATIVEL || |
401 | 25.1M | bt == Bond::BondType::DATIVER || bt == Bond::BondType::DATIVEONE; |
402 | 25.1M | } |
403 | | |
404 | 6.36M | inline bool isDative(const Bond &bond) { |
405 | 6.36M | auto bt = bond.getBondType(); |
406 | 6.36M | return isDative(bt); |
407 | 6.36M | } |
408 | | |
409 | 0 | inline bool canSetDoubleBondStereo(const Bond &bond) { |
410 | 0 | auto bondType = bond.getBondType(); |
411 | 0 | return (bondType == Bond::SINGLE || bondType == Bond::AROMATIC || |
412 | 0 | isDative(bond)); |
413 | 0 | } |
414 | | |
415 | 8.47M | inline bool canHaveDirection(const Bond &bond) { |
416 | 8.47M | auto bondType = bond.getBondType(); |
417 | 8.47M | return (bondType == Bond::SINGLE || bondType == Bond::AROMATIC); |
418 | 8.47M | } |
419 | | |
420 | | //! returns twice the \c bondType |
421 | | //! (e.g. SINGLE->2, AROMATIC->3, etc.) |
422 | | RDKIT_GRAPHMOL_EXPORT extern uint8_t getTwiceBondType(const RDKit::Bond &b); |
423 | | |
424 | | }; // namespace RDKit |
425 | | |
426 | | //! allows Bond objects to be dumped to streams |
427 | | RDKIT_GRAPHMOL_EXPORT extern std::ostream &operator<<(std::ostream &target, |
428 | | const RDKit::Bond &b); |
429 | | |
430 | | #endif |