You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

483 lines
14 KiB
C

/*=========================================================================
Program: Visualization Toolkit
Module: vtkMolecule.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
/**
* @class vtkMolecule
* @brief class describing a molecule
*
*
*
* vtkMolecule and the convenience classes vtkAtom and vtkBond
* describe the geometry and connectivity of a molecule. The molecule
* can be constructed using the AppendAtom() and AppendBond() methods in one
* of two ways; either by fully specifying the atom/bond in a single
* call, or by incrementally setting the various attributes using the
* convenience vtkAtom and vtkBond classes:
*
* Single call:
* \code
* vtkMolecule *mol = vtkMolecule::New();
* vtkAtom h1 = mol->AppendAtom(1, 0.0, 0.0, -0.5);
* vtkAtom h2 = mol->AppendAtom(1, 0.0, 0.0, 0.5);
* vtkBond b = mol->AppendBond(h1, h2, 1);
* \endcode
*
* Incremental:
* \code
* vtkMolecule *mol = vtkMolecule::New();
*
* vtkAtom h1 = mol->AppendAtom();
* h1.SetAtomicNumber(1);
* h1.SetPosition(0.0, 0.0, -0.5);
*
* vtkAtom h2 = mol->AppendAtom();
* h2.SetAtomicNumber(1);
* vtkVector3d displacement (0.0, 0.0, 1.0);
* h2.SetPosition(h1.GetPositionAsVector3d() + displacement);
*
* vtkBond b = mol->AppendBond(h1, h2, 1);
* \endcode
*
* Both of the above methods will produce the same molecule, two
* hydrogens connected with a 1.0 Angstrom single bond, aligned to the
* z-axis. The second example also demonstrates the use of VTK's
* vtkVector class, which is fully supported by the Chemistry kit.
*
* The vtkMolecule object is intended to be used with the
* vtkMoleculeMapper class for visualizing molecular structure using
* common rendering techniques.
*
* \warning While direct use of the underlying vtkUndirectedGraph
* structure is possible due to vtkMolecule's public inheritance, this
* should not be relied upon and may change in the future.
*
* @sa
* vtkAtom vtkBond vtkMoleculeMapper vtkPeriodicTable
*/
#ifndef vtkMolecule_h
#define vtkMolecule_h
#include "vtkCommonDataModelModule.h" // For export macro
#include "vtkSmartPointer.h" // For vtkSmartPointer
#include "vtkUndirectedGraph.h"
#include "vtkAtom.h" // Simple proxy class dependent on vtkMolecule
#include "vtkBond.h" // Simple proxy class dependent on vtkMolecule
#include "vtkVector.h" // Small templated vector convenience class
class vtkAbstractElectronicData;
class vtkDataArray;
class vtkInformation;
class vtkInformationVector;
class vtkMatrix3x3;
class vtkPlane;
class vtkPoints;
class vtkUnsignedCharArray;
class vtkUnsignedShortArray;
class VTKCOMMONDATAMODEL_EXPORT vtkMolecule : public vtkUndirectedGraph
{
public:
static vtkMolecule* New();
vtkTypeMacro(vtkMolecule, vtkUndirectedGraph);
void PrintSelf(ostream& os, vtkIndent indent) override;
void Initialize() override;
/**
* Return what type of dataset this is.
*/
int GetDataObjectType() override { return VTK_MOLECULE; }
/**
* Add new atom with atomic number 0 (dummy atom) at origin. Return
* a vtkAtom that refers to the new atom.
*/
vtkAtom AppendAtom() { return this->AppendAtom(0, 0., 0., 0.); }
//@{
/**
* Add new atom with the specified atomic number and position. Return a
* vtkAtom that refers to the new atom.
*/
vtkAtom AppendAtom(unsigned short atomicNumber, double x, double y, double z);
vtkAtom AppendAtom(unsigned short atomicNumber, const vtkVector3f& pos)
{
return this->AppendAtom(atomicNumber, pos[0], pos[1], pos[2]);
}
vtkAtom AppendAtom(unsigned short atomicNumber, double pos[3])
{
return this->AppendAtom(atomicNumber, pos[0], pos[1], pos[2]);
}
//@}
/**
* Return a vtkAtom that refers to the atom with the specified id.
*/
vtkAtom GetAtom(vtkIdType atomId);
/**
* Return the number of atoms in the molecule.
*/
vtkIdType GetNumberOfAtoms();
//@{
/**
* Add a bond between the specified atoms, optionally setting the
* bond order (default: 1). Return a vtkBond object referring to the
* new bond.
*/
vtkBond AppendBond(vtkIdType atom1, vtkIdType atom2, unsigned short order = 1);
vtkBond AppendBond(const vtkAtom& atom1, const vtkAtom& atom2, unsigned short order = 1)
{
return this->AppendBond(atom1.Id, atom2.Id, order);
}
//@}
/**
* Return a vtkAtom that refers to the bond with the specified id.
*/
vtkBond GetBond(vtkIdType bondId);
/**
* Return the number of bonds in the molecule.
*/
vtkIdType GetNumberOfBonds();
/**
* Return the atomic number of the atom with the specified id.
*/
unsigned short GetAtomAtomicNumber(vtkIdType atomId);
/**
* Set the atomic number of the atom with the specified id.
*/
void SetAtomAtomicNumber(vtkIdType atomId, unsigned short atomicNum);
//@{
/**
* Set the position of the atom with the specified id.
*/
void SetAtomPosition(vtkIdType atomId, const vtkVector3f& pos);
void SetAtomPosition(vtkIdType atomId, double x, double y, double z);
void SetAtomPosition(vtkIdType atomId, double pos[3])
{
this->SetAtomPosition(atomId, pos[0], pos[1], pos[2]);
}
//@}
//@{
/**
* Get the position of the atom with the specified id.
*/
vtkVector3f GetAtomPosition(vtkIdType atomId);
void GetAtomPosition(vtkIdType atomId, float pos[3]);
void GetAtomPosition(vtkIdType atomId, double pos[3]);
//@}
//@{
/**
* Get/Set the bond order of the bond with the specified id
*/
void SetBondOrder(vtkIdType bondId, unsigned short order);
unsigned short GetBondOrder(vtkIdType bondId);
//@}
/**
* Get the bond length of the bond with the specified id
* \note If the associated vtkBond object is already available,
* vtkBond::GetBondLength is potentially much faster than this
* function, as a list of all bonds may need to be constructed to
* locate the appropriate bond.
* \sa UpdateBondList()
*/
double GetBondLength(vtkIdType bondId);
//@{
/**
* Access the raw arrays used in this vtkMolecule instance
*/
vtkPoints* GetAtomicPositionArray();
vtkUnsignedShortArray* GetAtomicNumberArray();
vtkUnsignedShortArray* GetBondOrdersArray();
//@}
//@{
/**
* Set/Get the AbstractElectronicData-subclassed object for this molecule.
*/
vtkGetObjectMacro(ElectronicData, vtkAbstractElectronicData);
virtual void SetElectronicData(vtkAbstractElectronicData*);
//@}
/**
* Performs the same operation as ShallowCopy(),
* but instead of reporting an error for an incompatible graph,
* returns false.
*/
bool CheckedShallowCopy(vtkGraph* g) override;
/**
* Performs the same operation as DeepCopy(),
* but instead of reporting an error for an incompatible graph,
* returns false.
*/
bool CheckedDeepCopy(vtkGraph* g) override;
/**
* Shallow copies the data object into this molecule.
*/
void ShallowCopy(vtkDataObject* obj) override;
/**
* Deep copies the data object into this molecule.
*/
void DeepCopy(vtkDataObject* obj) override;
/**
* Shallow copies the atoms and bonds from @a m into @a this.
*/
virtual void ShallowCopyStructure(vtkMolecule* m);
/**
* Deep copies the atoms and bonds from @a m into @a this.
*/
virtual void DeepCopyStructure(vtkMolecule* m);
/**
* Shallow copies attributes (i.e. everything besides atoms and bonds) from
* @a m into @a this.
*/
virtual void ShallowCopyAttributes(vtkMolecule* m);
/**
* Deep copies attributes (i.e. everything besides atoms and bonds) from
* @a m into @a this.
*/
virtual void DeepCopyAttributes(vtkMolecule* m);
//@{
/**
* Obtain the plane that passes through the indicated bond with the given
* normal. If the plane is set successfully, the function returns true.
* If the normal is not orthogonal to the bond, a new normal will be
* constructed in such a way that the plane will be orthogonal to
* the plane spanned by the bond vector and the input normal vector.
* This ensures that the plane passes through the bond, and the
* normal is more of a "hint" indicating the orientation of the plane.
* The new normal (n) is defined as the input normal vector (n_i) minus
* the projection of itself (proj[n_i]_v) onto the bond vector (v):
* @verbatim
* v ^
* | n = (n_i - proj[n_j]_v)
* proj[n_i]_v ^ |----x
* | | /
* | | / n_i
* | | /
* | |/
* @endverbatim
* If n_i is parallel to v, a warning will be printed and no plane will be
* added. Obviously, n_i must not be parallel to v.
*/
static bool GetPlaneFromBond(const vtkBond& bond, const vtkVector3f& normal, vtkPlane* plane);
static bool GetPlaneFromBond(
const vtkAtom& atom1, const vtkAtom& atom2, const vtkVector3f& normal, vtkPlane* plane);
//@}
/**
* Return true if a unit cell lattice is defined.
*/
bool HasLattice();
/**
* Remove any unit cell lattice information from the molecule.
*/
void ClearLattice();
//@{
/**
* The unit cell vectors. The matrix is stored using a row-major layout, with
* the vectors encoded as columns.
*/
void SetLattice(vtkMatrix3x3* matrix);
void SetLattice(const vtkVector3d& a, const vtkVector3d& b, const vtkVector3d& c);
//@}
/**
* Get the unit cell lattice vectors. The matrix is stored using a row-major
* layout, with the vectors encoded as columns. Will return nullptr if no
* unit cell information is available.
* @sa GetLatticeOrigin
*/
vtkMatrix3x3* GetLattice();
//@{
/**
* Get the unit cell lattice vectors, and optionally, the origin.
*/
void GetLattice(vtkVector3d& a, vtkVector3d& b, vtkVector3d& c);
void GetLattice(vtkVector3d& a, vtkVector3d& b, vtkVector3d& c, vtkVector3d& origin);
//@}
//@{
/**
* Get the unit cell origin (for rendering purposes).
*/
vtkGetMacro(LatticeOrigin, vtkVector3d);
vtkSetMacro(LatticeOrigin, vtkVector3d);
//@}
/**
* Get the array that defines the ghost type of each atom.
*/
vtkUnsignedCharArray* GetAtomGhostArray();
/**
* Allocate ghost array for atoms.
*/
void AllocateAtomGhostArray();
/**
* Get the array that defines the ghost type of each bond.
*/
vtkUnsignedCharArray* GetBondGhostArray();
/**
* Allocate ghost array for bonds.
*/
void AllocateBondGhostArray();
/**
* Initialize a molecule with an atom per input point.
* Parameters atomPositions and atomicNumberArray should have the same size.
*/
int Initialize(
vtkPoints* atomPositions, vtkDataArray* atomicNumberArray, vtkDataSetAttributes* atomData);
/**
* Overloads Initialize method.
*/
int Initialize(vtkPoints* atomPositions, vtkDataSetAttributes* atomData)
{
return this->Initialize(atomPositions, nullptr, atomData);
}
/**
* Use input molecule points, atomic number and atomic data to initialize the new molecule.
*/
int Initialize(vtkMolecule* molecule);
//@{
/**
* Retrieve a molecule from an information vector.
*/
static vtkMolecule* GetData(vtkInformation* info);
static vtkMolecule* GetData(vtkInformationVector* v, int i = 0);
//@}
/**
* Return the VertexData of the underlying graph
*/
vtkDataSetAttributes* GetAtomData() { return this->GetVertexData(); }
/**
* Return the EdgeData of the underlying graph
*/
vtkDataSetAttributes* GetBondData() { return this->GetEdgeData(); }
/**
* Return the edge id from the underlying graph.
*/
vtkIdType GetBondId(vtkIdType a, vtkIdType b) { return this->GetEdgeId(a, b); }
//@{
/**
* Get/Set the atomic number array name.
*/
vtkSetStringMacro(AtomicNumberArrayName);
vtkGetStringMacro(AtomicNumberArrayName);
//@}
//@{
/**
* Get/Set the bond orders array name.
*/
vtkSetStringMacro(BondOrdersArrayName);
vtkGetStringMacro(BondOrdersArrayName);
//@}
/**
* Return the actual size of the data in kibibytes (1024 bytes). This number
* is valid only after the pipeline has updated. The memory size
* returned is guaranteed to be greater than or equal to the
* memory required to represent the data (e.g., extra space in
* arrays, etc. are not included in the return value).
*/
unsigned long GetActualMemorySize() override;
protected:
vtkMolecule();
~vtkMolecule() override;
/**
* Copy bonds and atoms.
*/
virtual void CopyStructureInternal(vtkMolecule* m, bool deep);
/**
* Copy everything but bonds and atoms.
*/
virtual void CopyAttributesInternal(vtkMolecule* m, bool deep);
//@{
/**
* The graph superclass does not provide fast random access to the
* edge (bond) data. All random access is performed using a lookup
* table that must be rebuilt periodically. These allow for lazy
* building of the lookup table
*/
bool BondListIsDirty;
void SetBondListDirty() { this->BondListIsDirty = true; }
void UpdateBondList();
vtkIdTypeArray* GetBondList();
//@}
friend class vtkAtom;
friend class vtkBond;
vtkAbstractElectronicData* ElectronicData;
vtkSmartPointer<vtkMatrix3x3> Lattice;
vtkVector3d LatticeOrigin;
vtkUnsignedCharArray* AtomGhostArray;
vtkUnsignedCharArray* BondGhostArray;
char* AtomicNumberArrayName;
char* BondOrdersArrayName;
private:
vtkMolecule(const vtkMolecule&) = delete;
void operator=(const vtkMolecule&) = delete;
};
#endif