1 /******************************************************************************
2 
3   This source file is part of the Avogadro project.
4 
5   Copyright 2013-2015 Kitware, Inc.
6 
7   This source code is released under the New BSD License, (the "License").
8 
9   Unless required by applicable law or agreed to in writing, software
10   distributed under the License is distributed on an "AS IS" BASIS,
11   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   See the License for the specific language governing permissions and
13   limitations under the License.
14 
15 ******************************************************************************/
16 
17 #ifndef AVOGADRO_QTGUI_RWMOLECULE_H
18 #define AVOGADRO_QTGUI_RWMOLECULE_H
19 
20 #include "avogadroqtguiexport.h"
21 #include <QtCore/QObject>
22 
23 #include "molecule.h"
24 #include "persistentatom.h"
25 #include "persistentbond.h"
26 
27 #include <avogadro/core/array.h>
28 #include <avogadro/core/atom.h>
29 #include <avogadro/core/avogadrocore.h>
30 #include <avogadro/core/bond.h>
31 #include <avogadro/core/crystaltools.h>
32 #include <avogadro/core/unitcell.h>
33 #include <avogadro/core/vector.h>
34 
35 #include <QtWidgets/QUndoStack>
36 
37 namespace Avogadro {
38 namespace QtGui {
39 
40 /** Concrete atom/bond proxy classes for RWMolecule. @{ */
41 class RWAtom;
42 class RWBond;
43 /** @} */
44 
45 /**
46  * @class RWMolecule rwmolecule.h <avogadro/qtgui/rwmolecule.h>
47  * @brief The RWMolecule class is an editable molecule class that automatically
48  * populates an undo stack.
49  *
50  * This class implements the molecule API and composes a QUndoStack
51  * (undoStack()). New undo commands are automatically generated and push each
52  * time a non-const method is called.
53  *
54  * An interactive mode is supported that causes "noisy" commands, such as
55  * atom position changes, to be merged into a single command, saving memory
56  * keeping the stack usable during interactive editing of the molecule. Use
57  * setInteractive(bool) to toggle interactive mode.
58  *
59  * Similarly, multiple sequences of commands can be compressed into a single
60  * named action using the QUndoStack's macro capability. Call
61  * undoStack().beginMacro(tr("User Description Of Change")) to begin a macro,
62  * and undoStack().endMacro() when finished.
63  */
64 class AVOGADROQTGUI_EXPORT RWMolecule : public QObject
65 {
66   Q_OBJECT
67 
68 public:
69   /** Typedef for Atom class. */
70   typedef RWAtom AtomType;
71 
72   /** Typedef for PersistentAtom class. */
73   typedef PersistentAtom<RWMolecule> PersistentAtomType;
74 
75   /** Typedef for Bond class. */
76   typedef RWBond BondType;
77 
78   /** Typedef for PersistentBond class. */
79   typedef PersistentBond<RWMolecule> PersistentBondType;
80 
81   /** Construct a molecule with the atoms/bonds of mol. */
82   explicit RWMolecule(Molecule& mol, QObject* parent = 0);
83 
84   ~RWMolecule() override;
85 
molecule()86   Molecule& molecule() { return m_molecule; }
molecule()87   const Molecule& molecule() const { return m_molecule; }
88 
89   /**
90    * Add a new atom to the molecule.
91    * @param atomicNumber The atomic number of the new atom.
92    * @param usingPositions Whether or not to use positions for this atom.
93    *                       Default is true. Set to false if the atom
94    *                       will not be using coordinates.
95    * @return The new Atom object.
96    */
97   AtomType addAtom(unsigned char atomicNumber, bool usingPositions = true);
98 
99   /**
100    * Add a new atom to the molecule and set its position.
101    * @param atomicNumber The atomic number of the new atom.
102    * @param position3d The position of the atom.
103    * @return The new Atom object.
104    */
105   AtomType addAtom(unsigned char atomicNumber, const Vector3& position3d);
106 
107   /**
108    * Obtain an atom object.
109    * @param atomId The index of the atom to return.
110    * @return The requested atom object. Will be invalid if @a atomId >= @a
111    * atomCount().
112    */
113   AtomType atom(Index atomId) const;
114 
115   /**
116    * Obtain an atom object from it's unique id.
117    * @param atomUId The unique of the requested atom.
118    * @return The requested atom object. Will be invalid if @a atomUId is not
119    * in use.
120    */
121   AtomType atomByUniqueId(Index atomUId) const;
122 
123   /**
124    * @return The unique id of the atom.
125    * @{
126    */
127   Index atomUniqueId(Index atomId) const;
128   Index atomUniqueId(const AtomType& atom) const;
129   /** @} */
130 
131   /**
132    * @return The number of atoms in the molecule.
133    */
134   Index atomCount() const;
135 
136   /**
137    * @return The number of atoms in the molecule with the atomic number @a
138    * atomicNumber.
139    */
140   Index atomCount(unsigned char atomicNumber) const;
141 
142   /**
143    * Delete the specified atom from this molecule.
144    * @return True on success, false otherwise.
145    * @note This also removes all bonds connected to the atom.
146    * @{
147    */
148   bool removeAtom(Index atomId);
149   bool removeAtom(const AtomType& atom);
150   /** @} */
151 
152   /**
153    * Delete all atoms from this molecule.
154    * @note This also removes all bonds.
155    */
156   void clearAtoms();
157 
158   /**
159    * Adjust hydrogens for an atom.
160    * @param atomId The index of the atom.
161    * @note Checks to make sure the atom is valid before adjusting the hydrogens.
162    */
163   void adjustHydrogens(Index atomId);
164 
165   /**
166    * Adjust hydrogens for multiple atoms.
167    * @param atomIds The indices for the atoms.
168    * @note Checks to make sure the atoms are valid before adjusting the
169    * hydrogens.
170    */
171   void adjustHydrogens(const Core::Array<Index>& atomIds);
172 
173   /**
174    * @return An array containing atomic numbers for all atoms in the molecule,
175    * indexed by atom index.
176    */
177   const Core::Array<unsigned char>& atomicNumbers() const;
178 
179   /**
180    * Get the atomic number for the requested atom.
181    * @param atomId The index of the atom.
182    * @return The atomic number of the atom indexed at @a atomId, or
183    * Avogadro::InvalidElement if @a atomId is invalid.
184    */
185   unsigned char atomicNumber(Index atomId) const;
186 
187   /**
188    * Replace the current array of atomic numbers.
189    * @param nums The new atomic number array. Must be of length atomCount().
190    * @return True on success, false otherwise.
191    */
192   bool setAtomicNumbers(const Core::Array<unsigned char>& nums);
193 
194   /**
195    * Set the atomic number of a single atom.
196    * @param atomId The index of the atom to modify.
197    * @param atomicNumber The new atomic number.
198    * @return True on success, false otherwise.
199    */
200   bool setAtomicNumber(Index atomId, unsigned char atomicNumber);
201 
202   /**
203    * @return An array containing 3D coordinates for all atoms in the molecule,
204    * indexed by atom index.
205    * @note May be empty if position information has not been set for any atoms.
206    */
207   const Core::Array<Vector3>& atomPositions3d() const;
208 
209   /**
210    * Get the 3D position of a single atom.
211    * @param atomId The index of the atom.
212    * @return The position of the atom, or Vector3::Zero() if no position
213    * information has been set.
214    */
215   Vector3 atomPosition3d(Index atomId) const;
216 
217   /**
218    * Replace the current array of 3D atomic coordinates.
219    * @param pos The new coordinate array. Must be of length atomCount().
220    * @param undoText The undo text to be displayed for undo commands.
221    * @return True on success, false otherwise.
222    */
223   bool setAtomPositions3d(
224     const Core::Array<Vector3>& pos,
225     const QString& undoText = QStringLiteral("Change Atom Positions"));
226 
227   /**
228    * Set the 3D position of a single atom.
229    * @param atomId The index of the atom to modify.
230    * @param pos The new position of the atom.
231    * @param undoText The undo text to be displayed for undo commands.
232    * @return True on success, false otherwise.
233    */
234   bool setAtomPosition3d(
235     Index atomId, const Vector3& pos,
236     const QString& undoText = QStringLiteral("Change Atom Position"));
237 
238   /**
239    * Set whether the specified atom is selected or not.
240    */
241   void setAtomSelected(Index atomId, bool selected);
242 
243   /**
244    * Query whether the supplied atom index has been selected.
245    */
246   bool atomSelected(Index atomId) const;
247 
setAtomPosition2d(Index,const Vector2 &)248   bool setAtomPosition2d(Index, const Vector2&) { return false; }
atomPosition2d(Index)249   Vector2 atomPosition2d(Index) { return Vector2(0, 0); }
atomPositions2d()250   const Core::Array<Vector2>& atomPositions2d() const
251   {
252     return m_molecule.m_positions2d;
253   }
254 
255   /**
256    * Get the hybridization for the requested atom.
257    * @param atomId The index of the atom.
258    * @return The hybridization of the atom indexed at @a atomId, or
259    * 0 if @a atomId is invalid.
260    */
261   Core::AtomHybridization hybridization(Index atomId) const;
262 
263   /**
264    * Set the hybridization of a single atom.
265    * @param atomId The index of the atom to modify.
266    * @param hyb The new hybridization.
267    * @return True on success, false otherwise.
268    */
269   bool setHybridization(Index atomId, Core::AtomHybridization hyb);
270 
271   /**
272    * Get the formal charge for the requested atom.
273    * @param atomId The index of the atom.
274    * @return The formal charge of the atom indexed at @a atomId, or
275    * 0 if @a atomId is invalid.
276    */
277   signed char formalCharge(Index atomId) const;
278 
279   /**
280    * Set the formal charge of a single atom.
281    * @param atomId The index of the atom to modify.
282    * @param charge The new formal charge.
283    * @return True on success, false otherwise.
284    */
285   bool setFormalCharge(Index atomId, signed char charge);
286 
287   /**
288    * Get the color for the requested atom.
289    * @param atomId The index of the atom.
290    * @return The color of the atom indexed at @a atomId, or
291    * (0, 0, 0) if @a atomId is invalid. If no color is set for the
292    * given atomId, the default color for the atomic number of
293    * the atomId is returned.
294    */
295   Vector3ub color(Index atomId) const;
296 
297   /**
298    * Set the color of a single atom.
299    * @param atomId The index of the atom to modify.
300    * @param color The new color.
301    * @return True on success, false otherwise.
302    */
303   bool setColor(Index atomId, Vector3ub color);
304 
305   /**
306    * Create a new bond in the molecule.
307    * @param atom1 The first atom in the bond.
308    * @param atom2 The second order in the bond.
309    * @param order The bond order.
310    * @return The new bond object. Will be invalid if @a atom1 or @a atom2 does
311    * not exist.
312    * @{
313    */
314   BondType addBond(Index atom1, Index atom2, unsigned char order = 1);
315   BondType addBond(const AtomType& atom1, const AtomType& atom2,
316                    unsigned char order = 1);
317   /** @} */
318 
319   /**
320    * Get a bond object.
321    * @param bondId The index of the requested bond.
322    * @return The requested bond object. Will be invalid if @a bondId >=
323    * @a bondCount().
324    */
325   BondType bond(Index bondId) const;
326 
327   /**
328    * Get a bond object.
329    * @param atom1 The index of one atom in the bond.
330    * @param atom2 The index of the other atom in bond.
331    * @return The requested bond object. Will be invalid if @a atom1 or @a atom2
332    * do not exist.
333    */
334   BondType bond(Index atom1, Index atom2) const;
335 
336   /**
337    * Get a bond object.
338    * @param atom1 One atom in the bond.
339    * @param atom2 The other atom in bond.
340    * @return The requested bond object. Will be invalid if @a atom1 or @a atom2
341    * are invalid.
342    */
343   BondType bond(const AtomType& atom1, const AtomType& atom2) const;
344 
345   /**
346    * Get a bond object from its unique id.
347    * @param bondUid The unique id of the bond.
348    * @return The requested bond object. Will be invalid if @a bondUid is not in
349    * use.
350    */
351   BondType bondByUniqueId(Index bondUid) const;
352 
353   /**
354    * Get the unique id of a bond.
355    * @param bondId The index of the requested bond.
356    * @return The unique id currently assigned to the bond at index @a bondId
357    */
358   Index bondUniqueId(Index bondId) const;
359 
360   /**
361    * Get the unique id of a bond.
362    * @param bond The requested bond object.
363    * @return The unique id currently assigned to @a bond.
364    */
365   Index bondUniqueId(const BondType& bond) const;
366 
367   /**
368    * @return The number of bonds in the molecule.
369    */
370   Index bondCount() const;
371 
372   /**
373    * Remove the requested bond.
374    * @return True on success, false otherwise.
375    * @{
376    */
377   bool removeBond(Index bondId);
378   bool removeBond(const BondType& bond);
379   bool removeBond(Index atom1, Index atom2);
380   bool removeBond(const AtomType& atom1, const AtomType& atom2);
381   /** @} */
382 
383   /**
384    * Remove all bonds from the molecule.
385    */
386   void clearBonds();
387 
388   /**
389    * Find bonds connected to an atom.
390    * @param atom The atom of interest.
391    * @return An array of bond objects that are attached to the specified atom.
392    */
393   Core::Array<BondType> bonds(const AtomType& atom) const;
394 
395   /**
396    * Find bonds connected to an atom.
397    * @param atomId The index for the atom of interest.
398    * @return An array of bond objects that are attached to the specified atom.
399    */
400   Core::Array<BondType> bonds(const Index& atomId) const;
401 
402   /**
403    * @return An array of bond orders for all bonds in the molecule, indexed by
404    * bond index.
405    */
406   const Core::Array<unsigned char>& bondOrders() const;
407 
408   /**
409    * Get the order of a bond.
410    * @param bondId The id of the bond.
411    * @return The bond order.
412    */
413   unsigned char bondOrder(Index bondId) const;
414 
415   /**
416    * Replace the current array of bond orders.
417    * @param orders The new array.
418    * @return True on success, false on failure.
419    */
420   bool setBondOrders(const Core::Array<unsigned char>& orders);
421 
422   /**
423    * Set the order of a bond in the molecule.
424    * @param bondId The bond's index.
425    * @param order The new order of the bond.
426    * @return True on success, false on failure.
427    */
428   bool setBondOrder(Index bondId, unsigned char order);
429 
430   /**
431    * @return An array of all bonded atoms in the molecule, indexed by bond
432    * index.
433    * Each bond pair is represented by a pair of atom indices.
434    */
435   const Core::Array<std::pair<Index, Index>>& bondPairs() const;
436 
437   /**
438    * Get the set of bonded atoms corresponding to @a bondId.
439    * @param bondId The index of the requested bond.
440    * @return The bonded atom pair, represented as a pair of atom indices.
441    */
442   std::pair<Index, Index> bondPair(Index bondId) const;
443 
444   /**
445    * Replace the current array of bonded atoms.
446    * @param pairs The array.
447    * @return True on success, false on failure.
448    * @note The bonded atoms are represented as a pair of bond indices.
449    * @note If needed, the elements in @a pairs will be modified to ensure that
450    * the first atom index is less than the second.
451    */
452   bool setBondPairs(const Core::Array<std::pair<Index, Index>>& pairs);
453 
454   /**
455    * Set the bonded atoms for a bond.
456    * @param bondId The bond to modify.
457    * @param pair The new bond pair.
458    * @return True on success, false otherwise.
459    * @note If needed, @a pair will be modified to ensure that the first atom
460    * index is less than the second.
461    */
462   bool setBondPair(Index bondId, const std::pair<Index, Index>& pair);
463 
464   /**
465    * Add a default unit cell to the molecule. Does nothing if there already
466    * is a unit cell. Changes are emitted.
467    */
468   void addUnitCell();
469 
470   /**
471    * Remove the unit cell from the molecule. Does nothing if there is
472    * no unit cell. Changes are emitted.
473    */
474   void removeUnitCell();
475 
476   /**
477    * Generic edit that changes the current molecule to be @a newMolecule.
478    * Also sets the text for the undo command to be @a undoText. Changes are
479    * emitted.
480    * @param newMolecule The new molecule to be set.
481    * @param changes The changes to be emitted.
482    * @param undoText The text description for the undo command.
483    */
484   void modifyMolecule(
485     const Molecule& newMolecule, Molecule::MoleculeChanges changes,
486     const QString& undoText = QStringLiteral("Modify Molecule"));
487 
488   /**
489    * Generic edit that adds @a newMolecule to the current molecule.
490    * Also sets the text for the undo command to be @a undoText. Changes are
491    * emitted.
492    * @param addMolecule The new molecule to be set.
493    * @param undoText The text description for the undo command.
494    */
495   void appendMolecule(
496     const Molecule& addMolecule,
497     const QString& undoText = QStringLiteral("Append Molecule"));
498 
499   /**
500    * Edit the unit cell by replacing the current cell matrix with a new cell
501    * matrix. Changes are emitted.
502    * @param cellMatrix The new cell matrix to be set.
503    * @param opts If TransformAtoms is specified, the atoms in @a molecule are
504    * adjusted so that their fractional (lattice) coordinates are preserved. This
505    * option is ignored if the input molecule has no unit cell.
506    */
507   void editUnitCell(Matrix3 cellMatrix, Core::CrystalTools::Options opts);
508 
509   /**
510    * Wrap atoms to the unit cell. Changes are emitted.
511    */
512   void wrapAtomsToCell();
513 
514   /**
515    * Rotate cell to standard orientation. Changes are emitted.
516    */
517   void rotateCellToStandardOrientation();
518 
519   /**
520    * Scale a cell's volume. Changes are emitted.
521    * @param newVolume The new volume to be set.
522    * @param options If CrystalTools::TransformAtoms is set, then
523    *                the atoms will be transformed during the scaling.
524    */
525   void setCellVolume(double newVolume, Core::CrystalTools::Options options);
526 
527   /**
528    * Build a supercell. Changes are emitted.
529    * @param a The final number of units along the A vector (at least 1).
530    * @param b The final number of units along the B vector (at least 1).
531    * @param c The final number of units along the C vector (at least 1).
532    */
533   void buildSupercell(unsigned int a, unsigned int b, unsigned int c);
534 
535   /**
536    * Perform a Niggli reduction on the cell. Changes are emitted.
537    */
538   void niggliReduceCell();
539 
540   /**
541    * Use spglib to reduce the cell to its primitive form. Changes are emitted.
542    * @param cartTol Cartesian tolerance for primitive reduction.
543    * @return True if the algorithm succeeded, and false if it failed.
544    */
545   bool reduceCellToPrimitive(double cartTol = 1e-5);
546 
547   /**
548    * Use spglib to convert the cell to its conventional form. Changes are
549    * emitted.
550    * @param cartTol Cartesian tolerance for conventionalization.
551    * @return True if the algorithm succeeded, and false if it failed.
552    */
553   bool conventionalizeCell(double cartTol = 1e-5);
554 
555   /**
556    * Use spglib to symmetrize the cell. Changes are emitted.
557    * @param cartTol Cartesian tolerance for symmetrization.
558    * @return True if the algorithm succeeded, and false if it failed.
559    */
560   bool symmetrizeCell(double cartTol = 1e-5);
561 
562   /**
563    * Fill unit cell using transforms for the space group. Changes are emitted.
564    * @param hallNumber The hall number to be used for transforming the cell.
565    * @param cartTol Cartesian tolerance for comparing atom positions.
566    * @return True if the algorithm succeeded, and false if it failed.
567    */
568   bool fillUnitCell(unsigned short hallNumber, double cartTol = 1e-5);
569 
570   /**
571    * Use transforms to reduce a cell to its asymmetric unit. Changes are
572    * emitted.
573    * @param hallNumber The hall number to be used for obtaining the transforms.
574    * @param cartTol Cartesian tolerance for comparing atom positions.
575    * @return True if the algorithm succeeded, and false if it failed.
576    */
577   bool reduceCellToAsymmetricUnit(unsigned short hallNumber,
578                                   double cartTol = 1e-5);
579 
580   /**
581    * Call this function when you wish to merge all undo commands.
582    * It turns on interactive mode to merge similar undo commands in a series
583    * (in order to save space), and it uses QUndoStack's beginMacro() to merge
584    * dissimilar undo commands together. You must call endMergeMode() to end
585    * the merging section (undo and redo are unavailable while merge mode is
586    * on).
587    * @param undoName The name of the undo command
588    */
589   void beginMergeMode(const QString& undoName = QStringLiteral("Draw"));
590 
591   /**
592    * Call this function when you wish merge mode to end. This will turn off
593    * interactive mode, and it will call QUndoStack's endMacro(). All of the
594    * undo commands pushed between beginMergeMode() and endMergeMode() will be
595    * merged into one undo command. beginMergeMode() should have been called
596    * before this is called.
597    */
598   void endMergeMode();
599 
600   /**
601    * @brief Begin or end an interactive edit.
602    *
603    * If enabled, certain undo operations will be merged together. For instance,
604    * an editor dragging an atom through space in response to mouse movement will
605    * only generate a single undo command containing the initial and final
606    * positions and discard the intermediate states. If disabled, each
607    * intermediate action will appear in the undo log.
608    */
609   void setInteractive(bool b);
610 
611   /**
612    * @return True if interactive mode is enabled, false otherwise.
613    * @sa setInteractive
614    */
615   bool isInteractive() const;
616 
617   /**
618    * @return The QUndoStack for this molecule.
619    * @{
620    */
621   QUndoStack& undoStack();
622   const QUndoStack& undoStack() const;
623   /** @} */
624 
625   class UndoCommand;
626   friend class UndoCommand;
627 
628   /** Returns a vector of forces for the atoms in the molecule. */
629   const Core::Array<Vector3>& forceVectors() const;
630 
631   /**
632    * Replace the current array of force vectors.
633    * @param pos The new force vector array. Must be of length atomCount().
634    * @param undoText The undo text to be displayed for undo commands.
635    * @return True on success, false otherwise.
636    */
637   bool setForceVector(
638     Index atomId, const Vector3& pos,
639     const QString& undoText = QStringLiteral("Change Force Vectors"));
640 
641 public slots:
642   /**
643    * @brief Force the molecule to emit the changed() signal.
644    * @param change See changed().
645    */
646   void emitChanged(unsigned int change);
647 
648 signals:
649   /**
650    * @brief Indicates that the molecule has changed.
651    * @param change Use the MoleculeChange enum to check what has changed.
652    *
653    * The @p change variable indicates what has changed, i.e. if
654    * change & Atoms == true then atoms were changed in some way, and if
655    * change & Removed == true then one or more atoms were removed.
656    */
657   void changed(unsigned int change);
658 
659 protected:
660   Index findAtomUniqueId(Index atomId) const;
661   Index findBondUniqueId(Index bondId) const;
662 
663   /**
664    * @brief m_molecule still stored all data, this class acts upon it and builds
665    * an undo/redo stack that can be used to offer undo and redo.
666    */
667   Molecule& m_molecule;
668   bool m_interactive;
669 
670   QUndoStack m_undoStack;
671 
672   friend class Molecule;
673 };
674 
675 class AVOGADROQTGUI_EXPORT RWAtom : public Core::AtomTemplate<RWMolecule>
676 {
677 public:
RWAtom()678   RWAtom() : Core::AtomTemplate<RWMolecule>() {}
RWAtom(RWMolecule * m,Index i)679   RWAtom(RWMolecule* m, Index i) : Core::AtomTemplate<RWMolecule>(m, i) {}
680 };
681 
682 class AVOGADROQTGUI_EXPORT RWBond : public Core::BondTemplate<RWMolecule>
683 {
684 public:
RWBond()685   RWBond() : Core::BondTemplate<RWMolecule>() {}
RWBond(RWMolecule * m,Index i)686   RWBond(RWMolecule* m, Index i) : Core::BondTemplate<RWMolecule>(m, i) {}
687 };
688 
atom(Index atomId)689 inline RWMolecule::AtomType RWMolecule::atom(Index atomId) const
690 {
691   return AtomType(const_cast<RWMolecule*>(this), atomId);
692 }
693 
atomByUniqueId(Index atomUId)694 inline RWMolecule::AtomType RWMolecule::atomByUniqueId(Index atomUId) const
695 {
696   return atomUId < m_molecule.m_atomUniqueIds.size()
697            ? AtomType(const_cast<RWMolecule*>(this),
698                       m_molecule.m_atomUniqueIds[atomUId])
699            : AtomType();
700 }
701 
atomUniqueId(Index atomId)702 inline Index RWMolecule::atomUniqueId(Index atomId) const
703 {
704   return findAtomUniqueId(atomId);
705 }
706 
atomUniqueId(const RWMolecule::AtomType & a)707 inline Index RWMolecule::atomUniqueId(const RWMolecule::AtomType& a) const
708 {
709   return a.molecule() == this ? findAtomUniqueId(a.index()) : MaxIndex;
710 }
711 
atomCount()712 inline Index RWMolecule::atomCount() const
713 {
714   return m_molecule.atomCount();
715 }
716 
removeAtom(const AtomType & a)717 inline bool RWMolecule::removeAtom(const AtomType& a)
718 {
719   return a.molecule() == this ? removeAtom(a.index()) : false;
720 }
721 
atomicNumbers()722 inline const Core::Array<unsigned char>& RWMolecule::atomicNumbers() const
723 {
724   return m_molecule.atomicNumbers();
725 }
726 
atomicNumber(Index atomId)727 inline unsigned char RWMolecule::atomicNumber(Index atomId) const
728 {
729   return m_molecule.atomicNumber(atomId);
730 }
731 
atomPositions3d()732 inline const Core::Array<Vector3>& RWMolecule::atomPositions3d() const
733 {
734   return m_molecule.atomPositions3d();
735 }
736 
atomPosition3d(Index atomId)737 inline Vector3 RWMolecule::atomPosition3d(Index atomId) const
738 {
739   return m_molecule.atomPosition3d(atomId);
740 }
741 
hybridization(Index atomId)742 inline Core::AtomHybridization RWMolecule::hybridization(Index atomId) const
743 {
744   return m_molecule.hybridization(atomId);
745 }
746 
formalCharge(Index atomId)747 inline signed char RWMolecule::formalCharge(Index atomId) const
748 {
749   return m_molecule.formalCharge(atomId);
750 }
751 
color(Index atomId)752 inline Vector3ub RWMolecule::color(Index atomId) const
753 {
754   return m_molecule.color(atomId);
755 }
756 
addBond(const AtomType & atom1,const AtomType & atom2,unsigned char order)757 inline RWMolecule::BondType RWMolecule::addBond(const AtomType& atom1,
758                                                 const AtomType& atom2,
759                                                 unsigned char order)
760 {
761   if (atom1.molecule() != atom2.molecule() || atom1.molecule() != this)
762     return BondType();
763   return addBond(atom1.index(), atom2.index(), order);
764 }
765 
bond(Index bondId)766 inline RWMolecule::BondType RWMolecule::bond(Index bondId) const
767 {
768   return BondType(const_cast<RWMolecule*>(this), bondId);
769 }
770 
bond(const RWMolecule::AtomType & atom1,const RWMolecule::AtomType & atom2)771 inline RWMolecule::BondType RWMolecule::bond(
772   const RWMolecule::AtomType& atom1, const RWMolecule::AtomType& atom2) const
773 {
774   if (atom1.molecule() == atom2.molecule() && atom1.molecule() == this)
775     return bond(atom1.index(), atom2.index());
776   return BondType();
777 }
778 
bondByUniqueId(Index bondUid)779 inline RWMolecule::BondType RWMolecule::bondByUniqueId(Index bondUid) const
780 {
781   return bondUid < m_molecule.m_bondUniqueIds.size()
782            ? BondType(const_cast<RWMolecule*>(this),
783                       m_molecule.m_bondUniqueIds[bondUid])
784            : BondType();
785 }
786 
bondUniqueId(Index bondId)787 inline Index RWMolecule::bondUniqueId(Index bondId) const
788 {
789   return findBondUniqueId(bondId);
790 }
791 
bondUniqueId(const RWMolecule::BondType & b)792 inline Index RWMolecule::bondUniqueId(const RWMolecule::BondType& b) const
793 {
794   return b.molecule() == this ? findBondUniqueId(b.index()) : MaxIndex;
795 }
796 
bondCount()797 inline Index RWMolecule::bondCount() const
798 {
799   return m_molecule.bondCount();
800 }
801 
removeBond(const RWMolecule::BondType & b)802 inline bool RWMolecule::removeBond(const RWMolecule::BondType& b)
803 {
804   return b.molecule() == this ? removeBond(b.index()) : false;
805 }
806 
removeBond(Index atom1,Index atom2)807 inline bool RWMolecule::removeBond(Index atom1, Index atom2)
808 {
809   return removeBond(bond(atom1, atom2).index());
810 }
811 
removeBond(const RWMolecule::AtomType & atom1,const RWMolecule::AtomType & atom2)812 inline bool RWMolecule::removeBond(const RWMolecule::AtomType& atom1,
813                                    const RWMolecule::AtomType& atom2)
814 {
815   if (atom1.molecule() != atom2.molecule() || atom1.molecule() != this)
816     return false;
817   return removeBond(bond(atom1.index(), atom2.index()).index());
818 }
819 
bonds(const RWMolecule::AtomType & a)820 inline Core::Array<RWMolecule::BondType> RWMolecule::bonds(
821   const RWMolecule::AtomType& a) const
822 {
823   return a.molecule() == this ? bonds(a.index()) : Core::Array<BondType>();
824 }
825 
bonds(const Index & atomId)826 inline Core::Array<RWMolecule::BondType> RWMolecule::bonds(
827   const Index& atomId) const
828 {
829   Core::Array<RWMolecule::BondType> result;
830   for (Index i = 0; i < m_molecule.m_bondPairs.size(); ++i)
831     if (m_molecule.m_bondPairs[i].first == atomId ||
832         m_molecule.m_bondPairs[i].second == atomId)
833       result.push_back(BondType(const_cast<RWMolecule*>(this), i));
834   return result;
835 }
836 
bondOrders()837 inline const Core::Array<unsigned char>& RWMolecule::bondOrders() const
838 {
839   return m_molecule.bondOrders();
840 }
841 
bondOrder(Index bondId)842 inline unsigned char RWMolecule::bondOrder(Index bondId) const
843 {
844   return m_molecule.bondOrder(bondId);
845 }
846 
bondPairs()847 inline const Core::Array<std::pair<Index, Index>>& RWMolecule::bondPairs() const
848 {
849   return m_molecule.bondPairs();
850 }
851 
bondPair(Index bondId)852 inline std::pair<Index, Index> RWMolecule::bondPair(Index bondId) const
853 {
854   return m_molecule.bondPair(bondId);
855 }
856 
beginMergeMode(const QString & undoName)857 inline void RWMolecule::beginMergeMode(const QString& undoName)
858 {
859   m_interactive = true;
860   m_undoStack.beginMacro(undoName);
861 }
862 
endMergeMode()863 inline void RWMolecule::endMergeMode()
864 {
865   m_interactive = false;
866   m_undoStack.endMacro();
867 }
868 
setInteractive(bool b)869 inline void RWMolecule::setInteractive(bool b)
870 {
871   m_interactive = b;
872 }
873 
isInteractive()874 inline bool RWMolecule::isInteractive() const
875 {
876   return m_interactive;
877 }
878 
undoStack()879 inline QUndoStack& RWMolecule::undoStack()
880 {
881   return m_undoStack;
882 }
883 
undoStack()884 inline const QUndoStack& RWMolecule::undoStack() const
885 {
886   return m_undoStack;
887 }
888 
forceVectors()889 inline const Core::Array<Vector3>& RWMolecule::forceVectors() const
890 {
891   return m_molecule.forceVectors();
892 }
893 
894 } // namespace QtGui
895 } // namespace Avogadro
896 
897 #endif // AVOGADRO_QTGUI_RWMOLECULE_H
898