1 /**********************************************************************
2 Primitive - Wrapper class around the OpenBabel classes
4 Copyright (C) 2007 Donald Ephraim Curtis
6 This file is part of the Avogadro molecular editor project.
7 For more information, see <http://avogadro.sourceforge.net/>
9 Avogadro is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 Avogadro is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 **********************************************************************/
27 #include <avogadro/primitive.h>
28 #include <eigen/regression.h>
30 #include <QReadWriteLock>
32 using namespace OpenBabel
;
36 class PrimitivePrivate
{
38 PrimitivePrivate() : type(Primitive::OtherType
) {};
40 enum Primitive::Type type
;
44 Primitive::Primitive(QObject
*parent
) : QObject(parent
), d_ptr(new PrimitivePrivate
) {}
46 Primitive::Primitive(enum Type type
, QObject
*parent
) : QObject(parent
), d_ptr(new PrimitivePrivate
)
52 Primitive::Primitive(PrimitivePrivate
&dd
, QObject
*parent
) : QObject(parent
), d_ptr(&dd
) {}
54 Primitive::Primitive(PrimitivePrivate
&dd
, enum Type type
, QObject
*parent
) : QObject(parent
), d_ptr(&dd
)
60 Primitive::~Primitive()
65 enum Primitive::Type
Primitive::type() const
71 QReadWriteLock
*Primitive::lock()
77 void Primitive::update()
82 class MoleculePrivate
: public PrimitivePrivate
{
84 MoleculePrivate() : PrimitivePrivate(), farthestAtom(0), invalidGeomInfo(true) {}
85 mutable Eigen::Vector3d center
;
86 mutable Eigen::Vector3d normalVector
;
87 mutable double radius
;
88 mutable Atom
* farthestAtom
;
89 mutable bool invalidGeomInfo
;
92 Molecule::Molecule(QObject
*parent
) : Primitive(*new MoleculePrivate
, MoleculeType
, parent
), OpenBabel::OBMol()
94 connect(this, SIGNAL(updated()), this, SLOT(updatePrimitive()));
97 Molecule::Molecule(const Molecule
&other
) : Primitive(*new MoleculePrivate
, MoleculeType
, other
.parent()), OpenBabel::OBMol(other
)
99 connect(this, SIGNAL(updated()), this, SLOT(updatePrimitive()));
102 Molecule::~Molecule()
106 Atom
* Molecule::CreateAtom()
108 Atom
*atom
= new Atom(this);
109 connect(atom
, SIGNAL(updated()), this, SLOT(updatePrimitive()));
110 emit
primitiveAdded(atom
);
114 Bond
* Molecule::CreateBond()
116 Bond
*bond
= new Bond(this);
117 connect(bond
, SIGNAL(updated()), this, SLOT(updatePrimitive()));
118 emit
primitiveAdded(bond
);
122 Residue
* Molecule::CreateResidue()
124 Residue
*residue
= new Residue(this);
125 connect(residue
, SIGNAL(updated()), this, SLOT(updatePrimitive()));
126 emit
primitiveAdded(residue
);
130 void Molecule::DestroyAtom(OpenBabel::OBAtom
*obatom
)
132 Atom
*atom
= static_cast<Atom
*>(obatom
);
134 emit
primitiveRemoved(atom
);
139 void Molecule::DestroyBond(OpenBabel::OBBond
*obbond
)
141 Bond
*bond
= static_cast<Bond
*>(obbond
);
143 emit
primitiveRemoved(bond
);
148 void Molecule::DestroyResidue(OpenBabel::OBResidue
*obresidue
)
150 Residue
*residue
= static_cast<Residue
*>(obresidue
);
152 emit
primitiveRemoved(residue
);
153 residue
->deleteLater();
157 void Molecule::updatePrimitive()
160 Primitive
*primitive
= qobject_cast
<Primitive
*>(sender());
161 d
->invalidGeomInfo
= true;
162 emit
primitiveUpdated(primitive
);
165 void Molecule::update()
168 d
->invalidGeomInfo
= true;
172 const Eigen::Vector3d
& Molecule::center() const
175 if( d
->invalidGeomInfo
) computeGeomInfo();
179 const Eigen::Vector3d
& Molecule::normalVector() const
182 if( d
->invalidGeomInfo
) computeGeomInfo();
183 return d
->normalVector
;
186 const double & Molecule::radius() const
189 if( d
->invalidGeomInfo
) computeGeomInfo();
193 const Atom
* Molecule::farthestAtom() const
196 if( d
->invalidGeomInfo
) computeGeomInfo();
197 return d
->farthestAtom
;
200 Molecule
&Molecule::operator=(const Molecule
& other
)
202 OpenBabel::OBMol::operator=(other
);
206 Molecule
&Molecule::operator+=(const Molecule
& other
)
208 OpenBabel::OBMol::operator+=(other
);
213 void Molecule::computeGeomInfo() const
215 // MoleculePrivate *d = reinterpret_cast<MoleculePrivate *>(d_ptr);
217 d
->invalidGeomInfo
= true;
219 d
->center
.loadZero();
220 d
->normalVector
.loadZero();
222 if( NumAtoms() != 0 )
225 std::vector
< OpenBabel::OBAtom
* >::iterator atom_iterator
;
226 for( Atom
* atom
= (Atom
*) const_cast<Molecule
*>(this)->BeginAtom(atom_iterator
); atom
; atom
= (Atom
*) const_cast<Molecule
*>(this)->NextAtom(atom_iterator
) )
228 d
->center
+= atom
->pos();
230 d
->center
/= NumAtoms();
232 // compute the normal vector to the molecule's best-fitting plane
233 Eigen::Vector3d
* atomPositions
= new Eigen::Vector3d
[NumAtoms()];
235 for( Atom
* atom
= (Atom
*) const_cast<Molecule
*>(this)->BeginAtom(atom_iterator
); atom
; atom
= (Atom
*) const_cast<Molecule
*>(this)->NextAtom(atom_iterator
) )
237 atomPositions
[i
++] = atom
->pos();
239 Eigen::Vector4d planeCoeffs
;
240 Eigen::computeFittingHyperplane( NumAtoms(), atomPositions
, &planeCoeffs
);
241 delete[] atomPositions
;
242 d
->normalVector
= Eigen::Vector3d( planeCoeffs
.x(), planeCoeffs
.y(), planeCoeffs
.z() );
243 d
->normalVector
.normalize();
245 // compute radius and the farthest atom
246 d
->radius
= -1.0; // so that ( squaredDistanceToCenter > d->radius ) is true for at least one atom.
247 for( Atom
* atom
= (Atom
*) const_cast<Molecule
*>(this)->BeginAtom(atom_iterator
); atom
; atom
= (Atom
*) const_cast<Molecule
*>(this)->NextAtom(atom_iterator
) )
249 double distanceToCenter
= (atom
->pos() - d
->center
).norm();
250 if( distanceToCenter
> d
->radius
)
252 d
->radius
= distanceToCenter
;
253 d
->farthestAtom
= atom
;
257 d
->invalidGeomInfo
= false;
262 #include "primitive.moc"