Camera/Navigate documentation & code

Hi all,

I am writing to provide you a problem with your documentation and
implementation of the Avogadro::Navigate.rotate().
I have searched why I could not realize a rotation of 90° (like mention in
the documentationhttp://avogadro.openmolecules.net/api/dev/classAvogadro_1_1Navigate.html#f4a985234398cafacb2167cac4e19fdc).
After having checked and tested the code,
to get a rotation with the wanted angle, it is necessary to :

  • convert degree into radian ;
  • divise by Avogadro::ROTATION_SPEED .

Example :

            rotCamAxeXDeg = 90 ; // Degree.
            rotCamAxeXDeg = 0 ;

    [...]
    rotCamAxeXRad = (rotCamAxeXDeg*PI/180) / Avogadro::ROTATION_SPEED ;
    rotCamAxeYRad = (rotCamAxeYDeg*PI/180) / Avogadro::ROTATION_SPEED ;

    Navigate::rotate( m_widget, myRef, rotCamAxeXRad, rotCamAxeYRad ) ;

So,

  • Avogadro::ROTATION_SPEED ?
  • The documentation never refers to the Radian unit.

And,

Mickaël Gadroy

P.S. : The version of the
documentationhttp://avogadro.openmolecules.net/api/dev/index.htmlis
not the same as the last release version.

On Jul 16, 2010, at 10:01 AM, Mickaël Gadroy wrote:

Hi all,

I am writing to provide you a problem with your documentation and implementation of the Avogadro::Navigate.rotate().
I have searched why I could not realize a rotation of 90° (like mention in the documentation). After having checked and tested the code,
to get a rotation with the wanted angle, it is necessary to :

  • convert degree into radian ;
  • divise by Avogadro::ROTATION_SPEED .

Ah. Yes, this is a good point. I think this was done for the mouse-tools, but it’s clearly bad for external API use.

global.h: const double ROTATION_SPEED = 0.005;

I think the best solution will be to revise the API to allow rotations using radians and do the ROTATION_SPEED calculations in the mouse tools themselves.

Example :

  • If I want to translate the camera to 2 Angström on the X-axis, do I have to calculate a vector to get “the amount” I’d like to ? What do you mean (the unit) by an “amount”, a “deltaX”, a “deltaY” ?
  • In the documentation, what are the axes (backTransformedAxis and transformedAxis) ?
    Are the scene’s coordinate system (backTransform*) and the space coordinate system (transformed*) identical ?
  • Does OpenGL space correspond to the global space coord (the universe) ?

I can certainly answer the last one. Yes.

Benoit handled much of the camera transformation code, so I will defer to him about the axes.

-Geoff

Thanks for CC’ing me; but actually it’s purely incidental that I read
this email now, as my gmail filter still put it in my avogadro
directory which I don’t check too frequently. Need to improve my
filters. Just letting you know in case I don’t reply some day.

2010/8/9 Geoffrey Hutchison geoff.hutchison@gmail.com:

On Jul 16, 2010, at 10:01 AM, Mickaël Gadroy wrote:

Hi all,

I am writing to provide you a problem with your documentation and
implementation of the Avogadro::Navigate.rotate().
I have searched why I could not realize a rotation of 90° (like mention in
the documentation). After having checked and tested the code,
to get a rotation with the wanted angle, it is necessary to :

  • convert degree into radian ;
  • divise by Avogadro::ROTATION_SPEED .

Ah. Yes, this is a good point. I think this was done for the mouse-tools,
but it’s clearly bad for external API use.
global.h: const double ROTATION_SPEED = 0.005;

I think the best solution will be to revise the API to allow rotations using
radians and do the ROTATION_SPEED calculations in the mouse tools
themselves.

Example :

  • If I want to translate the camera to 2 Angström on the X-axis, do I have
    to calculate a vector to get “the amount” I’d like to ? What do you mean
    (the unit) by an “amount”, a “deltaX”, a “deltaY” ?

Right, this documentation is crappy, so let’s look at the source code:

which calls Camera stuff in:

for example the Navigate::translate() code is:

void Navigate::translate(GLWidget *widget, const Eigen::Vector3d &what,
double deltaX, double deltaY)
{
Vector3d fromPos = widget->camera()->unProject(QPoint(0, 0), what);
Vector3d toPos = widget->camera()->unProject(QPoint(int(deltaX),
int(deltaY)), what);
widget->camera()->translate(toPos - fromPos);
}

so we see that deltaX and deltaY here are screen-coordinates pixel
deltas. They are first transformed to world-coordinates using
Camera::unProject() and then the camera is translated by that (note
that Camera::translate() multiplies the modelview matrix on the
right
i.e. it works in world coordinates).

Perhaps the ‘what’ argument deserves an additional explanation. In 3D
graphics, there’s no unique way to convert from screen coordinates to
world coordinates: for farther away objects, a given screen coords
delta will result in a bigger world coords delta. Basically,
unProject() needs to know which plane in 3D space you want to map your
screen to. So it takes this ‘what’ argument telling it to consider the
plane passing through that point, and facing the camera.

  • In the documentation, what are the axes (backTransformedAxis and
    transformed
    Axis) ?

Have you looked at the docs?
http://avogadro.openmolecules.net/api/dev/classAvogadro_1_1Camera.html#76fda73b7cb676619a93b050aece1e24

However, again it doesn’t hurt to look at source code in camera.cpp.
For example:

Eigen::Vector3d Camera::backTransformedXAxis() const
{
return d->modelview.linear().row(0).transpose();
}

linear() returns the top-left 3x3 block which is the linear
transformation component of the modelview matrix. So in practice this
is a rotation, so the inverse rotation is just the transpose, so the
row 0 there is the same as the column 0 in the inverse rotation. Since
the column 0 in a matrix is the image, under that matrix, of the
elementary unit vector in the positive X direction, we see that
d->modelview.linear().row(0) indeed does return the back-transformed X
axis.

Finally, the .transpose() there is because the above returns a
row-vector, and we want a column-vector instead.

  Are the scene's coordinate system (backTransform*) and the space

coordinate system (transformed*) identical ?

I don’t understand the question, sorry. There’s not much
avogadro-specific in that stuff, just the standard 3d math you’ll find
in any opengl app. The camera matrix is just the usual modelview
matrix. The backTransformed/transformedxxx methods, as explained
above, are just helpers to address parts of the modelview matrix. The
“scene coordinates”, “world coordinates”, etc, idioms, are sometimes
helpful to help understand stuff, but ultimately all there is is the
modelview matrix.

Benoit

  • Does OpenGL space correspond to the global space coord (the universe) ?

I can certainly answer the last one. Yes.
Benoit handled much of the camera transformation code, so I will defer to
him about the axes.
-Geoff

2010/8/10 Benoit Jacob jacob.benoit.1@gmail.com:

Thanks for CC’ing me; but actually it’s purely incidental that I read
this email now, as my gmail filter still put it in my avogadro
directory which I don’t check too frequently. Need to improve my
filters. Just letting you know in case I don’t reply some day.

2010/8/9 Geoffrey Hutchison geoff.hutchison@gmail.com:

On Jul 16, 2010, at 10:01 AM, Mickaël Gadroy wrote:

Hi all,

I am writing to provide you a problem with your documentation and
implementation of the Avogadro::Navigate.rotate().
I have searched why I could not realize a rotation of 90° (like mention in
the documentation). After having checked and tested the code,
to get a rotation with the wanted angle, it is necessary to :

  • convert degree into radian ;
  • divise by Avogadro::ROTATION_SPEED .

Ah. Yes, this is a good point. I think this was done for the mouse-tools,
but it’s clearly bad for external API use.
global.h: const double ROTATION_SPEED = 0.005;

I think the best solution will be to revise the API to allow rotations using
radians and do the ROTATION_SPEED calculations in the mouse tools
themselves.

Example :

  • If I want to translate the camera to 2 Angström on the X-axis, do I have
    to calculate a vector to get “the amount” I’d like to ? What do you mean
    (the unit) by an “amount”, a “deltaX”, a “deltaY” ?

Right, this documentation is crappy, so let’s look at the source code:

avogadro/libavogadro/src/navigate.cpp at master · cryos/avogadro · GitHub

which calls Camera stuff in:

avogadro/libavogadro/src/camera.cpp at master · cryos/avogadro · GitHub

for example the Navigate::translate() code is:

void Navigate::translate(GLWidget *widget, const Eigen::Vector3d &what,
double deltaX, double deltaY)
{
Vector3d fromPos = widget->camera()->unProject(QPoint(0, 0), what);
Vector3d toPos = widget->camera()->unProject(QPoint(int(deltaX),
int(deltaY)), what);
widget->camera()->translate(toPos - fromPos);
}

so we see that deltaX and deltaY here are screen-coordinates pixel
deltas. They are first transformed to world-coordinates using
Camera::unProject() and then the camera is translated by that (note
that Camera::translate() multiplies the modelview matrix on the
right
i.e. it works in world coordinates).

Woops, I got confused myself. Replace ‘world coords’ by ‘object
coords’ in above paragraph.

Anyway, like I said below, the only way I’ve ever found of wrapping my
mind around opengl transformations is to treat the transformations as
the primary object of interest, rather than the various implicit
coordinate systems.

Benoit

Perhaps the ‘what’ argument deserves an additional explanation. In 3D
graphics, there’s no unique way to convert from screen coordinates to
world coordinates: for farther away objects, a given screen coords
delta will result in a bigger world coords delta. Basically,
unProject() needs to know which plane in 3D space you want to map your
screen to. So it takes this ‘what’ argument telling it to consider the
plane passing through that point, and facing the camera.

  • In the documentation, what are the axes (backTransformedAxis and
    transformed
    Axis) ?

Have you looked at the docs?
Avogadro: Avogadro::Camera Class Reference

However, again it doesn’t hurt to look at source code in camera.cpp.
For example:

Eigen::Vector3d Camera::backTransformedXAxis() const
{
return d->modelview.linear().row(0).transpose();
}

linear() returns the top-left 3x3 block which is the linear
transformation component of the modelview matrix. So in practice this
is a rotation, so the inverse rotation is just the transpose, so the
row 0 there is the same as the column 0 in the inverse rotation. Since
the column 0 in a matrix is the image, under that matrix, of the
elementary unit vector in the positive X direction, we see that
d->modelview.linear().row(0) indeed does return the back-transformed X
axis.

Finally, the .transpose() there is because the above returns a
row-vector, and we want a column-vector instead.

  Are the scene's coordinate system (backTransform*) and the space

coordinate system (transformed*) identical ?

I don’t understand the question, sorry. There’s not much
avogadro-specific in that stuff, just the standard 3d math you’ll find
in any opengl app. The camera matrix is just the usual modelview
matrix. The backTransformed/transformedxxx methods, as explained
above, are just helpers to address parts of the modelview matrix. The
“scene coordinates”, “world coordinates”, etc, idioms, are sometimes
helpful to help understand stuff, but ultimately all there is is the
modelview matrix.

Benoit

  • Does OpenGL space correspond to the global space coord (the universe) ?

I can certainly answer the last one. Yes.
Benoit handled much of the camera transformation code, so I will defer to
him about the axes.
-Geoff

Thank you very much for all this explanation. This is much clearer. When I
read the code with the modelview matrix the next time, I’ll understand
better.

Regards.

Mickaël Gadroy

2010/8/10 Benoit Jacob jacob.benoit.1@gmail.com

2010/8/10 Benoit Jacob jacob.benoit.1@gmail.com:

Thanks for CC’ing me; but actually it’s purely incidental that I read
this email now, as my gmail filter still put it in my avogadro
directory which I don’t check too frequently. Need to improve my
filters. Just letting you know in case I don’t reply some day.

2010/8/9 Geoffrey Hutchison geoff.hutchison@gmail.com:

On Jul 16, 2010, at 10:01 AM, Mickaël Gadroy wrote:

Hi all,

I am writing to provide you a problem with your documentation and
implementation of the Avogadro::Navigate.rotate().
I have searched why I could not realize a rotation of 90° (like
mention in
the documentation). After having checked and tested the code,
to get a rotation with the wanted angle, it is necessary to :

  • convert degree into radian ;
  • divise by Avogadro::ROTATION_SPEED .

Ah. Yes, this is a good point. I think this was done for the
mouse-tools,
but it’s clearly bad for external API use.
global.h: const double ROTATION_SPEED = 0.005;

I think the best solution will be to revise the API to allow rotations
using
radians and do the ROTATION_SPEED calculations in the mouse tools
themselves.

Example :

  • If I want to translate the camera to 2 Angström on the X-axis, do I
    have
    to calculate a vector to get “the amount” I’d like to ? What do you mean
    (the unit) by an “amount”, a “deltaX”, a “deltaY” ?

Right, this documentation is crappy, so let’s look at the source code:

avogadro/libavogadro/src/navigate.cpp at master · cryos/avogadro · GitHub

which calls Camera stuff in:

avogadro/libavogadro/src/camera.cpp at master · cryos/avogadro · GitHub

for example the Navigate::translate() code is:

void Navigate::translate(GLWidget *widget, const Eigen::Vector3d &what,
double deltaX, double deltaY)
{
Vector3d fromPos = widget->camera()->unProject(QPoint(0, 0), what);
Vector3d toPos = widget->camera()->unProject(QPoint(int(deltaX),
int(deltaY)), what);
widget->camera()->translate(toPos - fromPos);
}

so we see that deltaX and deltaY here are screen-coordinates pixel
deltas. They are first transformed to world-coordinates using
Camera::unProject() and then the camera is translated by that (note
that Camera::translate() multiplies the modelview matrix on the
right
i.e. it works in world coordinates).

Woops, I got confused myself. Replace ‘world coords’ by ‘object
coords’ in above paragraph.

Anyway, like I said below, the only way I’ve ever found of wrapping my
mind around opengl transformations is to treat the transformations as
the primary object of interest, rather than the various implicit
coordinate systems.

Benoit

Perhaps the ‘what’ argument deserves an additional explanation. In 3D
graphics, there’s no unique way to convert from screen coordinates to
world coordinates: for farther away objects, a given screen coords
delta will result in a bigger world coords delta. Basically,
unProject() needs to know which plane in 3D space you want to map your
screen to. So it takes this ‘what’ argument telling it to consider the
plane passing through that point, and facing the camera.

  • In the documentation, what are the axes (backTransformedAxis and
    transformed
    Axis) ?

Have you looked at the docs?

Avogadro: Avogadro::Camera Class Reference

However, again it doesn’t hurt to look at source code in camera.cpp.
For example:

Eigen::Vector3d Camera::backTransformedXAxis() const
{
return d->modelview.linear().row(0).transpose();
}

linear() returns the top-left 3x3 block which is the linear
transformation component of the modelview matrix. So in practice this
is a rotation, so the inverse rotation is just the transpose, so the
row 0 there is the same as the column 0 in the inverse rotation. Since
the column 0 in a matrix is the image, under that matrix, of the
elementary unit vector in the positive X direction, we see that
d->modelview.linear().row(0) indeed does return the back-transformed X
axis.

Finally, the .transpose() there is because the above returns a
row-vector, and we want a column-vector instead.

  Are the scene's coordinate system (backTransform*) and the space

coordinate system (transformed*) identical ?

I don’t understand the question, sorry. There’s not much
avogadro-specific in that stuff, just the standard 3d math you’ll find
in any opengl app. The camera matrix is just the usual modelview
matrix. The backTransformed/transformedxxx methods, as explained
above, are just helpers to address parts of the modelview matrix. The
“scene coordinates”, “world coordinates”, etc, idioms, are sometimes
helpful to help understand stuff, but ultimately all there is is the
modelview matrix.

Benoit

  • Does OpenGL space correspond to the global space coord (the
    universe) ?

I can certainly answer the last one. Yes.
Benoit handled much of the camera transformation code, so I will defer
to
him about the axes.
-Geoff