1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkMolecule.h
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /**
16  * @class   vtkMolecule
17  * @brief   class describing a molecule
18  *
19  *
20  *
21  * vtkMolecule and the convenience classes vtkAtom and vtkBond
22  * describe the geometry and connectivity of a molecule. The molecule
23  * can be constructed using the AppendAtom() and AppendBond() methods in one
24  * of two ways; either by fully specifying the atom/bond in a single
25  * call, or by incrementally setting the various attributes using the
26  * convenience vtkAtom and vtkBond classes:
27  *
28  * Single call:
29  * \code
30  * vtkMolecule *mol = vtkMolecule::New();
31  * vtkAtom h1 = mol->AppendAtom(1, 0.0, 0.0, -0.5);
32  * vtkAtom h2 = mol->AppendAtom(1, 0.0, 0.0,  0.5);
33  * vtkBond b  = mol->AppendBond(h1, h2, 1);
34  * \endcode
35  *
36  * Incremental:
37  * \code
38  * vtkMolecule *mol = vtkMolecule::New();
39  *
40  * vtkAtom h1 = mol->AppendAtom();
41  * h1.SetAtomicNumber(1);
42  * h1.SetPosition(0.0, 0.0, -0.5);
43  *
44  * vtkAtom h2 = mol->AppendAtom();
45  * h2.SetAtomicNumber(1);
46  * vtkVector3d displacement (0.0, 0.0, 1.0);
47  * h2.SetPosition(h1.GetPositionAsVector3d() + displacement);
48  *
49  * vtkBond b  = mol->AppendBond(h1, h2, 1);
50  * \endcode
51  *
52  * Both of the above methods will produce the same molecule, two
53  * hydrogens connected with a 1.0 Angstrom single bond, aligned to the
54  * z-axis. The second example also demonstrates the use of VTK's
55  * vtkVector class, which is fully supported by the Chemistry kit.
56  *
57  * The vtkMolecule object is intended to be used with the
58  * vtkMoleculeMapper class for visualizing molecular structure using
59  * common rendering techniques.
60  *
61  * \warning While direct use of the underlying vtkUndirectedGraph
62  * structure is possible due to vtkMolecule's public inheritance, this
63  * should not be relied upon and may change in the future.
64  *
65  * @sa
66  * vtkAtom vtkBond vtkMoleculeMapper vtkPeriodicTable
67 */
68 
69 #ifndef vtkMolecule_h
70 #define vtkMolecule_h
71 
72 #include "vtkCommonDataModelModule.h" // For export macro
73 #include "vtkUndirectedGraph.h"
74 #include "vtkSmartPointer.h" // For vtkSmartPointer
75 
76 #include "vtkAtom.h" // Simple proxy class dependent on vtkMolecule
77 #include "vtkBond.h" // Simple proxy class dependent on vtkMolecule
78 
79 #include "vtkVector.h" // Small templated vector convenience class
80 
81 class vtkAbstractElectronicData;
82 class vtkDataArray;
83 class vtkInformation;
84 class vtkInformationVector;
85 class vtkMatrix3x3;
86 class vtkPlane;
87 class vtkPoints;
88 class vtkUnsignedCharArray;
89 class vtkUnsignedShortArray;
90 
91 class VTKCOMMONDATAMODEL_EXPORT vtkMolecule : public vtkUndirectedGraph
92 {
93 public:
94   static vtkMolecule *New();
95   vtkTypeMacro(vtkMolecule,vtkUndirectedGraph);
96   void PrintSelf(ostream &os, vtkIndent indent) override;
97   void Initialize() override;
98 
99   /**
100    * Return what type of dataset this is.
101    */
GetDataObjectType()102   int GetDataObjectType() override {return VTK_MOLECULE;}
103 
104   /**
105    * Add new atom with atomic number 0 (dummy atom) at origin. Return
106    * a vtkAtom that refers to the new atom.
107    */
AppendAtom()108   vtkAtom AppendAtom()
109   {
110     return this->AppendAtom(0, vtkVector3f(0, 0, 0));
111   }
112 
113   /**
114    * Add new atom with the specified atomic number and position. Return a
115    * vtkAtom that refers to the new atom.
116    */
117   vtkAtom AppendAtom(unsigned short atomicNumber, const vtkVector3f &pos);
118 
119   /**
120    * Convenience methods to append a new atom with the specified atomic number
121    * and position.
122    */
AppendAtom(unsigned short atomicNumber,double x,double y,double z)123   vtkAtom AppendAtom(unsigned short atomicNumber, double x, double y, double z)
124   {
125     return this->AppendAtom(atomicNumber, vtkVector3f(x, y, z));
126   }
127 
128   /**
129    * Return a vtkAtom that refers to the atom with the specified id.
130    */
131   vtkAtom GetAtom(vtkIdType atomId);
132 
133   /**
134    * Return the number of atoms in the molecule.
135    */
136   vtkIdType GetNumberOfAtoms();
137 
138   //@{
139   /**
140    * Add a bond between the specified atoms, optionally setting the
141    * bond order (default: 1). Return a vtkBond object referring to the
142    * new bond.
143    */
144   vtkBond AppendBond(vtkIdType atom1, vtkIdType atom2,
145                      unsigned short order = 1);
146   vtkBond AppendBond(const vtkAtom &atom1, const vtkAtom &atom2,
147                      unsigned short order = 1)
148   {
149     return this->AppendBond(atom1.Id, atom2.Id, order);
150   }
151   //@}
152 
153   /**
154    * Return a vtkAtom that refers to the bond with the specified id.
155    */
156   vtkBond GetBond(vtkIdType bondId);
157 
158   /**
159    * Return the number of bonds in the molecule.
160    */
161   vtkIdType GetNumberOfBonds();
162 
163   /**
164    * Return the atomic number of the atom with the specified id.
165    */
166   unsigned short GetAtomAtomicNumber(vtkIdType atomId);
167 
168   /**
169    * Set the atomic number of the atom with the specified id.
170    */
171   void SetAtomAtomicNumber(vtkIdType atomId,
172                            unsigned short atomicNum);
173 
174   //@{
175   /**
176    * Set the position of the atom with the specified id.
177    */
178   void SetAtomPosition(vtkIdType atomId, const vtkVector3f &pos);
179   void SetAtomPosition(vtkIdType atomId, double x, double y, double z);
180   //@}
181 
182   //@{
183   /**
184    * Get the position of the atom with the specified id.
185    */
186   vtkVector3f GetAtomPosition(vtkIdType atomId);
187   void GetAtomPosition(vtkIdType atomId, float pos[3]);
188   //@}
189 
190   //@{
191   /**
192    * Get/Set the bond order of the bond with the specified id
193    */
194   void SetBondOrder(vtkIdType bondId, unsigned short order);
195   unsigned short GetBondOrder(vtkIdType bondId);
196   //@}
197 
198   /**
199    * Get the bond length of the bond with the specified id
200 
201    * \note If the associated vtkBond object is already available,
202    * vtkBond::GetBondLength is potentially much faster than this
203    * function, as a list of all bonds may need to be constructed to
204    * locate the appropriate bond.
205    * \sa UpdateBondList()
206    */
207   double GetBondLength(vtkIdType bondId);
208 
209   //@{
210   /**
211    * Access the raw arrays used in this vtkMolecule instance
212    */
213   vtkPoints * GetAtomicPositionArray();
214   vtkUnsignedShortArray * GetAtomicNumberArray();
215   vtkUnsignedShortArray * GetBondOrdersArray();
216   //@}
217 
218   //@{
219   /**
220    * Set/Get the AbstractElectronicData-subclassed object for this molecule.
221    */
222   vtkGetObjectMacro(ElectronicData, vtkAbstractElectronicData);
223   virtual void SetElectronicData(vtkAbstractElectronicData*);
224   //@}
225 
226   /**
227    * Performs the same operation as ShallowCopy(),
228    * but instead of reporting an error for an incompatible graph,
229    * returns false.
230    */
231   bool CheckedShallowCopy(vtkGraph *g) override;
232 
233   /**
234    * Performs the same operation as DeepCopy(),
235    * but instead of reporting an error for an incompatible graph,
236    * returns false.
237    */
238   bool CheckedDeepCopy(vtkGraph *g) override;
239 
240   /**
241    * Shallow copies the data object into this molecule.
242    */
243   void ShallowCopy(vtkDataObject *obj) override;
244 
245   /**
246    * Deep copies the data object into this molecule.
247    */
248   void DeepCopy(vtkDataObject *obj) override;
249 
250   /**
251    * Shallow copies the atoms and bonds from @a m into @a this.
252    */
253   virtual void ShallowCopyStructure(vtkMolecule *m);
254 
255   /**
256    * Deep copies the atoms and bonds from @a m into @a this.
257    */
258   virtual void DeepCopyStructure(vtkMolecule *m);
259 
260   /**
261    * Shallow copies attributes (i.e. everything besides atoms and bonds) from
262    * @a m into @a this.
263    */
264   virtual void ShallowCopyAttributes(vtkMolecule *m);
265 
266   /**
267    * Deep copies attributes (i.e. everything besides atoms and bonds) from
268    * @a m into @a this.
269    */
270   virtual void DeepCopyAttributes(vtkMolecule *m);
271 
272   //@{
273   /**
274    * Obtain the plane that passes through the indicated bond with the given
275    * normal. If the plane is set successfully, the function returns true.
276 
277    * If the normal is not orthogonal to the bond, a new normal will be
278    * constructed in such a way that the plane will be orthogonal to
279    * the plane spanned by the bond vector and the input normal vector.
280 
281    * This ensures that the plane passes through the bond, and the
282    * normal is more of a "hint" indicating the orientation of the plane.
283 
284    * The new normal (n) is defined as the input normal vector (n_i) minus
285    * the projection of itself (proj[n_i]_v) onto the bond vector (v):
286 
287    * @verbatim
288    * v ^
289    * |  n = (n_i - proj[n_j]_v)
290    * proj[n_i]_v ^  |----x
291    * |  |   /
292    * |  |  / n_i
293    * |  | /
294    * |  |/
295    * @endverbatim
296 
297    * If n_i is parallel to v, a warning will be printed and no plane will be
298    * added. Obviously, n_i must not be parallel to v.
299    */
300   static bool GetPlaneFromBond(const vtkBond &bond, const vtkVector3f &normal,
301                                vtkPlane *plane);
302   static bool GetPlaneFromBond(const vtkAtom &atom1, const vtkAtom &atom2,
303                                const vtkVector3f &normal, vtkPlane *plane);
304   //@}
305 
306   /**
307    * Return true if a unit cell lattice is defined.
308    */
309   bool HasLattice();
310 
311   /**
312    * Remove any unit cell lattice information from the molecule.
313    */
314   void ClearLattice();
315 
316   //@{
317   /**
318    * The unit cell vectors. The matrix is stored using a row-major layout, with
319    * the vectors encoded as columns.
320    */
321   void SetLattice(vtkMatrix3x3 *matrix);
322   void SetLattice(const vtkVector3d &a,
323                   const vtkVector3d &b,
324                   const vtkVector3d &c);
325   //@}
326 
327   /**
328    * Get the unit cell lattice vectors. The matrix is stored using a row-major
329    * layout, with the vectors encoded as columns. Will return nullptr if no
330    * unit cell information is available.
331    * @sa GetLatticeOrigin
332    */
333   vtkMatrix3x3* GetLattice();
334 
335   //@{
336   /**
337    * Get the unit cell lattice vectors, and optionally, the origin.
338    */
339   void GetLattice(vtkVector3d &a, vtkVector3d &b, vtkVector3d &c);
340   void GetLattice(vtkVector3d &a, vtkVector3d &b, vtkVector3d &c,
341                   vtkVector3d &origin);
342   //@}
343 
344   //@{
345   /**
346    * Get the unit cell origin (for rendering purposes).
347    */
348   vtkGetMacro(LatticeOrigin, vtkVector3d)
349   vtkSetMacro(LatticeOrigin, vtkVector3d)
350   //@}
351 
352   /**
353    * Get the array that defines the ghost type of each atom.
354    */
355   vtkUnsignedCharArray* GetAtomGhostArray();
356 
357   /**
358    * Allocate ghost array for atoms.
359    */
360   void AllocateAtomGhostArray();
361 
362   /**
363    * Get the array that defines the ghost type of each bond.
364    */
365   vtkUnsignedCharArray* GetBondGhostArray();
366 
367   /**
368    * Allocate ghost array for bonds.
369    */
370   void AllocateBondGhostArray();
371 
372   /**
373    * Initialize a molecule with an atom per input point.
374    * Parameters atomPositions and atomicNumberArray should have the same size.
375    */
376   int Initialize(vtkPoints* atomPositions,
377     vtkDataArray* atomicNumberArray,
378     vtkDataSetAttributes* atomData);
379 
380   /**
381    * Overloads Initialize method.
382    */
Initialize(vtkPoints * atomPositions,vtkDataSetAttributes * atomData)383   int Initialize(vtkPoints* atomPositions,
384     vtkDataSetAttributes* atomData)
385   {
386     return this->Initialize(atomPositions, nullptr, atomData);
387   }
388 
389   /**
390    * Use input molecule points, atomic number and atomic data to initialize the new molecule.
391    */
392   int Initialize(vtkMolecule* molecule);
393 
394   //@{
395   /**
396    * Retrieve a molecule from an information vector.
397    */
398   static vtkMolecule* GetData(vtkInformation *info);
399   static vtkMolecule* GetData(vtkInformationVector *v, int i=0);
400   //@}
401 
402   /**
403    * Return the VertexData of the underlying graph
404    */
GetAtomData()405   vtkDataSetAttributes* GetAtomData()
406   {
407     return this->GetVertexData();
408   }
409 
410   /**
411    * Return the EdgeData of the underlying graph
412    */
GetBondData()413   vtkDataSetAttributes* GetBondData()
414   {
415     return this->GetEdgeData();
416   }
417 
418   /**
419    * Return the edge id from the underlying graph.
420    */
GetBondId(vtkIdType a,vtkIdType b)421   vtkIdType GetBondId(vtkIdType a, vtkIdType b)
422   {
423     return this->GetEdgeId(a, b);
424   }
425 
426   //@{
427   /**
428    * Get/Set the atomic number array name.
429    */
430   vtkSetStringMacro(AtomicNumberArrayName);
431   vtkGetStringMacro(AtomicNumberArrayName);
432   //@}
433 
434   //@{
435   /**
436    * Get/Set the bond orders array name.
437    */
438   vtkSetStringMacro(BondOrdersArrayName);
439   vtkGetStringMacro(BondOrdersArrayName);
440   //@}
441 
442  protected:
443   vtkMolecule();
444   ~vtkMolecule() override;
445 
446   /**
447    * Copy bonds and atoms.
448    */
449   virtual void CopyStructureInternal(vtkMolecule *m, bool deep);
450 
451   /**
452    * Copy everything but bonds and atoms.
453    */
454   virtual void CopyAttributesInternal(vtkMolecule *m, bool deep);
455 
456   //@{
457   /**
458    * The graph superclass does not provide fast random access to the
459    * edge (bond) data. All random access is performed using a lookup
460    * table that must be rebuilt periodically. These allow for lazy
461    * building of the lookup table
462    */
463   bool BondListIsDirty;
SetBondListDirty()464   void SetBondListDirty() {this->BondListIsDirty = true;}
465   void UpdateBondList();
466   vtkIdTypeArray* GetBondList();
467   //@}
468 
469   friend class vtkAtom;
470   friend class vtkBond;
471 
472   vtkAbstractElectronicData *ElectronicData;
473   vtkSmartPointer<vtkMatrix3x3> Lattice;
474   vtkVector3d LatticeOrigin;
475 
476   vtkUnsignedCharArray* AtomGhostArray;
477   vtkUnsignedCharArray* BondGhostArray;
478 
479   char* AtomicNumberArrayName;
480   char* BondOrdersArrayName;
481 
482 private:
483   vtkMolecule(const vtkMolecule&) = delete;
484   void operator=(const vtkMolecule&) = delete;
485 };
486 
487 #endif
488