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 "vtkSmartPointer.h"          // For vtkSmartPointer
74 #include "vtkUndirectedGraph.h"
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() { return this->AppendAtom(0, 0., 0., 0.); }
109 
110   ///@{
111   /**
112    * Add new atom with the specified atomic number and position. Return a
113    * vtkAtom that refers to the new atom.
114    */
115   vtkAtom AppendAtom(unsigned short atomicNumber, double x, double y, double z);
AppendAtom(unsigned short atomicNumber,const vtkVector3f & pos)116   vtkAtom AppendAtom(unsigned short atomicNumber, const vtkVector3f& pos)
117   {
118     return this->AppendAtom(atomicNumber, pos[0], pos[1], pos[2]);
119   }
120 
AppendAtom(unsigned short atomicNumber,double pos[3])121   vtkAtom AppendAtom(unsigned short atomicNumber, double pos[3])
122   {
123     return this->AppendAtom(atomicNumber, pos[0], pos[1], pos[2]);
124   }
125   ///@}
126 
127   /**
128    * Return a vtkAtom that refers to the atom with the specified id.
129    */
130   vtkAtom GetAtom(vtkIdType atomId);
131 
132   /**
133    * Return the number of atoms in the molecule.
134    */
135   vtkIdType GetNumberOfAtoms();
136 
137   ///@{
138   /**
139    * Add a bond between the specified atoms, optionally setting the
140    * bond order (default: 1). Return a vtkBond object referring to the
141    * new bond.
142    */
143   vtkBond AppendBond(vtkIdType atom1, vtkIdType atom2, unsigned short order = 1);
144   vtkBond AppendBond(const vtkAtom& atom1, const vtkAtom& atom2, unsigned short order = 1)
145   {
146     return this->AppendBond(atom1.Id, atom2.Id, order);
147   }
148   ///@}
149 
150   /**
151    * Return a vtkAtom that refers to the bond with the specified id.
152    */
153   vtkBond GetBond(vtkIdType bondId);
154 
155   /**
156    * Return the number of bonds in the molecule.
157    */
158   vtkIdType GetNumberOfBonds();
159 
160   /**
161    * Return the atomic number of the atom with the specified id.
162    */
163   unsigned short GetAtomAtomicNumber(vtkIdType atomId);
164 
165   /**
166    * Set the atomic number of the atom with the specified id.
167    */
168   void SetAtomAtomicNumber(vtkIdType atomId, unsigned short atomicNum);
169 
170   ///@{
171   /**
172    * Set the position of the atom with the specified id.
173    */
174   void SetAtomPosition(vtkIdType atomId, const vtkVector3f& pos);
175   void SetAtomPosition(vtkIdType atomId, double x, double y, double z);
SetAtomPosition(vtkIdType atomId,double pos[3])176   void SetAtomPosition(vtkIdType atomId, double pos[3])
177   {
178     this->SetAtomPosition(atomId, pos[0], pos[1], pos[2]);
179   }
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   void GetAtomPosition(vtkIdType atomId, double pos[3]);
189   ///@}
190 
191   ///@{
192   /**
193    * Get/Set the bond order of the bond with the specified id
194    */
195   void SetBondOrder(vtkIdType bondId, unsigned short order);
196   unsigned short GetBondOrder(vtkIdType bondId);
197   ///@}
198 
199   /**
200    * Get the bond length of the bond with the specified id
201 
202    * \note If the associated vtkBond object is already available,
203    * vtkBond::GetBondLength is potentially much faster than this
204    * function, as a list of all bonds may need to be constructed to
205    * locate the appropriate bond.
206    * \sa UpdateBondList()
207    */
208   double GetBondLength(vtkIdType bondId);
209 
210   ///@{
211   /**
212    * Access the raw arrays used in this vtkMolecule instance
213    */
214   vtkPoints* GetAtomicPositionArray();
215   vtkUnsignedShortArray* GetAtomicNumberArray();
216   vtkUnsignedShortArray* GetBondOrdersArray();
217   ///@}
218 
219   ///@{
220   /**
221    * Set/Get the AbstractElectronicData-subclassed object for this molecule.
222    */
223   vtkGetObjectMacro(ElectronicData, vtkAbstractElectronicData);
224   virtual void SetElectronicData(vtkAbstractElectronicData*);
225   ///@}
226 
227   /**
228    * Performs the same operation as ShallowCopy(),
229    * but instead of reporting an error for an incompatible graph,
230    * returns false.
231    */
232   bool CheckedShallowCopy(vtkGraph* g) override;
233 
234   /**
235    * Performs the same operation as DeepCopy(),
236    * but instead of reporting an error for an incompatible graph,
237    * returns false.
238    */
239   bool CheckedDeepCopy(vtkGraph* g) override;
240 
241   /**
242    * Shallow copies the data object into this molecule.
243    */
244   void ShallowCopy(vtkDataObject* obj) override;
245 
246   /**
247    * Deep copies the data object into this molecule.
248    */
249   void DeepCopy(vtkDataObject* obj) override;
250 
251   /**
252    * Shallow copies the atoms and bonds from @a m into @a this.
253    */
254   virtual void ShallowCopyStructure(vtkMolecule* m);
255 
256   /**
257    * Deep copies the atoms and bonds from @a m into @a this.
258    */
259   virtual void DeepCopyStructure(vtkMolecule* m);
260 
261   /**
262    * Shallow copies attributes (i.e. everything besides atoms and bonds) from
263    * @a m into @a this.
264    */
265   virtual void ShallowCopyAttributes(vtkMolecule* m);
266 
267   /**
268    * Deep copies attributes (i.e. everything besides atoms and bonds) from
269    * @a m into @a this.
270    */
271   virtual void DeepCopyAttributes(vtkMolecule* m);
272 
273   ///@{
274   /**
275    * Obtain the plane that passes through the indicated bond with the given
276    * normal. If the plane is set successfully, the function returns true.
277 
278    * If the normal is not orthogonal to the bond, a new normal will be
279    * constructed in such a way that the plane will be orthogonal to
280    * the plane spanned by the bond vector and the input normal vector.
281 
282    * This ensures that the plane passes through the bond, and the
283    * normal is more of a "hint" indicating the orientation of the plane.
284 
285    * The new normal (n) is defined as the input normal vector (n_i) minus
286    * the projection of itself (proj[n_i]_v) onto the bond vector (v):
287 
288    * @verbatim
289    * v ^
290    * |  n = (n_i - proj[n_j]_v)
291    * proj[n_i]_v ^  |----x
292    * |  |   /
293    * |  |  / n_i
294    * |  | /
295    * |  |/
296    * @endverbatim
297 
298    * If n_i is parallel to v, a warning will be printed and no plane will be
299    * added. Obviously, n_i must not be parallel to v.
300    */
301   static bool GetPlaneFromBond(const vtkBond& bond, const vtkVector3f& normal, vtkPlane* plane);
302   static bool GetPlaneFromBond(
303     const vtkAtom& atom1, const vtkAtom& atom2, 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, const vtkVector3d& b, const vtkVector3d& c);
323   ///@}
324 
325   /**
326    * Get the unit cell lattice vectors. The matrix is stored using a row-major
327    * layout, with the vectors encoded as columns. Will return nullptr if no
328    * unit cell information is available.
329    * @sa GetLatticeOrigin
330    */
331   vtkMatrix3x3* GetLattice();
332 
333   ///@{
334   /**
335    * Get the unit cell lattice vectors, and optionally, the origin.
336    */
337   void GetLattice(vtkVector3d& a, vtkVector3d& b, vtkVector3d& c);
338   void GetLattice(vtkVector3d& a, vtkVector3d& b, vtkVector3d& c, vtkVector3d& origin);
339   ///@}
340 
341   ///@{
342   /**
343    * Get the unit cell origin (for rendering purposes).
344    */
345   vtkGetMacro(LatticeOrigin, vtkVector3d);
346   vtkSetMacro(LatticeOrigin, vtkVector3d);
347   ///@}
348 
349   /**
350    * Get the array that defines the ghost type of each atom.
351    */
352   vtkUnsignedCharArray* GetAtomGhostArray();
353 
354   /**
355    * Allocate ghost array for atoms.
356    */
357   void AllocateAtomGhostArray();
358 
359   /**
360    * Get the array that defines the ghost type of each bond.
361    */
362   vtkUnsignedCharArray* GetBondGhostArray();
363 
364   /**
365    * Allocate ghost array for bonds.
366    */
367   void AllocateBondGhostArray();
368 
369   /**
370    * Initialize a molecule with an atom per input point.
371    * Parameters atomPositions and atomicNumberArray should have the same size.
372    */
373   int Initialize(
374     vtkPoints* atomPositions, vtkDataArray* atomicNumberArray, vtkDataSetAttributes* atomData);
375 
376   /**
377    * Overloads Initialize method.
378    */
Initialize(vtkPoints * atomPositions,vtkDataSetAttributes * atomData)379   int Initialize(vtkPoints* atomPositions, vtkDataSetAttributes* atomData)
380   {
381     return this->Initialize(atomPositions, nullptr, atomData);
382   }
383 
384   /**
385    * Use input molecule points, atomic number and atomic data to initialize the new molecule.
386    */
387   int Initialize(vtkMolecule* molecule);
388 
389   ///@{
390   /**
391    * Retrieve a molecule from an information vector.
392    */
393   static vtkMolecule* GetData(vtkInformation* info);
394   static vtkMolecule* GetData(vtkInformationVector* v, int i = 0);
395   ///@}
396 
397   /**
398    * Return the VertexData of the underlying graph
399    */
GetAtomData()400   vtkDataSetAttributes* GetAtomData() { return this->GetVertexData(); }
401 
402   /**
403    * Return the EdgeData of the underlying graph
404    */
GetBondData()405   vtkDataSetAttributes* GetBondData() { return this->GetEdgeData(); }
406 
407   /**
408    * Return the edge id from the underlying graph.
409    */
GetBondId(vtkIdType a,vtkIdType b)410   vtkIdType GetBondId(vtkIdType a, vtkIdType b) { return this->GetEdgeId(a, b); }
411 
412   ///@{
413   /**
414    * Get/Set the atomic number array name.
415    */
416   vtkSetStringMacro(AtomicNumberArrayName);
417   vtkGetStringMacro(AtomicNumberArrayName);
418   ///@}
419 
420   ///@{
421   /**
422    * Get/Set the bond orders array name.
423    */
424   vtkSetStringMacro(BondOrdersArrayName);
425   vtkGetStringMacro(BondOrdersArrayName);
426   ///@}
427 
428   /**
429    * Return the actual size of the data in kibibytes (1024 bytes). This number
430    * is valid only after the pipeline has updated. The memory size
431    * returned is guaranteed to be greater than or equal to the
432    * memory required to represent the data (e.g., extra space in
433    * arrays, etc. are not included in the return value).
434    */
435   unsigned long GetActualMemorySize() override;
436 
437 protected:
438   vtkMolecule();
439   ~vtkMolecule() override;
440 
441   /**
442    * Copy bonds and atoms.
443    */
444   virtual void CopyStructureInternal(vtkMolecule* m, bool deep);
445 
446   /**
447    * Copy everything but bonds and atoms.
448    */
449   virtual void CopyAttributesInternal(vtkMolecule* m, bool deep);
450 
451   ///@{
452   /**
453    * The graph superclass does not provide fast random access to the
454    * edge (bond) data. All random access is performed using a lookup
455    * table that must be rebuilt periodically. These allow for lazy
456    * building of the lookup table
457    */
458   bool BondListIsDirty;
SetBondListDirty()459   void SetBondListDirty() { this->BondListIsDirty = true; }
460   void UpdateBondList();
461   vtkIdTypeArray* GetBondList();
462   ///@}
463 
464   friend class vtkAtom;
465   friend class vtkBond;
466 
467   vtkAbstractElectronicData* ElectronicData;
468   vtkSmartPointer<vtkMatrix3x3> Lattice;
469   vtkVector3d LatticeOrigin;
470 
471   vtkUnsignedCharArray* AtomGhostArray;
472   vtkUnsignedCharArray* BondGhostArray;
473 
474   char* AtomicNumberArrayName;
475   char* BondOrdersArrayName;
476 
477 private:
478   vtkMolecule(const vtkMolecule&) = delete;
479   void operator=(const vtkMolecule&) = delete;
480 };
481 
482 #endif
483