Hi List,
Avogadro is ported to Eigen 2, as of r1568.
You’ll need to check out Eigen2 from kdesupport, at the same place as
usual except that ‘eigen’ becomes ‘eigen2’ :
svn co svn:://anonsvn.kde.org/home/kde/trunk/kdesupport/eigen2
To install Eigen2, do:
mkdir eigen2-build
cd eigen2-build
cmake -DCMAKE_INSTALL_PREFIX=/your/prefix …/eigen2
make install
Now you should be able to build Avogadro. If cmake ever fails to find
Eigen2, use -DEIGEN2_INCLUDE_DIR=/path/to/eigen2 (the directory
containing the Eigen subdirectory).
There now is a WITH_SSE2 cmake option, which is explained in the
top-level CMakeLists.
Let me know if you have trouble with any aspect of Eigen2. If you
build the docs from SVN (cmake -DBUILD_DOC=ON, make), you’ll see the
beginning of a “Quick Start Guide”. Even without building docs
yourself, you can see the API docs of alpha7 there:
http://eigen.tuxfamily.org/api
I’d like to show you one of the places that benefited dramatically from
the move from Eigen 1 to Eigen 2. I hope this helps you take full
advantage of Eigen 2.
Let’s go to libavogadro/src/cylinder.cpp:
Here is the old Cylinder::draw() using Eigen 1:
{
Vector3d axis = end2 - end1;
Vector3d axisNormalized = axis.normalized();
Vector3d ortho1, ortho2;
ortho1.loadOrtho(axisNormalized);
ortho1 *= radius;
axisNormalized.cross( ortho1, &ortho2 );
// construct the 4D transformation matrix
Matrix4d matrix;
matrix(0, 0) = ortho1(0);
matrix(1, 0) = ortho1(1);
matrix(2, 0) = ortho1(2);
matrix(3, 0) = 0.0;
matrix(0, 1) = ortho2(0);
matrix(1, 1) = ortho2(1);
matrix(2, 1) = ortho2(2);
matrix(3, 1) = 0.0;
matrix(0, 2) = axis(0);
matrix(1, 2) = axis(1);
matrix(2, 2) = axis(2);
matrix(3, 2) = 0.0;
matrix(0, 3) = end1(0);
matrix(1, 3) = end1(1);
matrix(2, 3) = end1(2);
matrix(3, 3) = 1.0;
//now we can do the actual drawing !
glPushMatrix();
glMultMatrixd( matrix.array() );
glCallList( d->displayList );
glPopMatrix();
}
Here is the new Cylinder::draw() using Eigen 2. Notice how expression
templates allow to perform all vector operations in place, directly on
the blocks of the matrix, removing the need to first construct these
vectors and then copy them to blocks of the matrix.
{
// construct the 4D transformation matrix
Eigen::Matrix4d matrix;
matrix.row(3) << 0, 0, 0, 1;
matrix.block<3,1>(0,2) = end2 - end1; // the axis
Vector3d axisNormalized = matrix.block<3,1>(0,2).normalized();
matrix.block<3,1>(0,0) = axisNormalized.unitOrthogonal() * radius;
matrix.block<3,1>(0,1) = axisNormalized.cross(matrix.block<3,1>(0,0));
matrix.block<3,1>(0,3) = end1;
//now we can do the actual drawing !
glPushMatrix();
glMultMatrixd( matrix.data() );
glCallList( d->displayList );
glPopMatrix();
}
OK, finally, I’d like to take this occasion to draw your attention on
a couple of misc things that I fixed.
a) in Color, we were using glColor4fv in the apply() method but the
components were not stored as an array, hence there was no guarantee
that they would be adjacent in memory. My fault really, I wrote that
code a long time ago.
b) in GLPainter, you often used the gl methods like glVertex3d()
instead of glVertex3dv(). Remember, the ‘v’ variants are faster! Since
our data is generally stored as vectors, they’re also easier to call
and less error-prone.
By the way, i also made GLPainter use more Color::apply() instead of
glColor4f(r,g,b,a).
c) In order to apply a translation to a vector, you don’t need to
construct a 4x4 transformation matrix and multiply your vector by it.
I saw a lot of that in our source code. Applying a translation is just
adding two vectors. If you have a vector Position and want to apply to
it a translation by vector Displacement, the result is just Position +
Displacement. That’s just 3 FLOPs instead of about 30.
Cheers,
Benoit
This message was sent using IMP, the Internet Messaging Program.