Aligning cylinder between two points

156 views
Skip to first unread message

rapodaca

unread,
Apr 1, 2011, 8:54:49 PM4/1/11
to PhiloGL
Greetings,

I'd like to thank everyone working on PhiloGL - it's really flattened
my learning curve with WebGL.

Now the problem: I'm writing a series of tutorials on building a
molecule viewer using PhiloGL:

http://blog.metamolecular.com/articles/2011/03/07/webgl-for-chemistry-part-1-introduction/

I've hit a snag when trying to align the endpoints of a Cylinder
between two points. PhiloGL.O3D.Cylinder can be rotated along the x,
y, and z axes. But I'd like to align the endpoints of the Cylinder
between to points.

How can I do this?

I've pushed my code to:

https://github.com/metamolecular/webgl-chem

The two relevant sections are:

view.js (line 99, 'drawBond'):

https://github.com/metamolecular/webgl-chem/blob/master/lessons/lesson-4/view.js

and

molfile_reader.js (beginning line 54, 'getRotation'):

https://github.com/metamolecular/webgl-chem/blob/master/lessons/lesson-4/molfile_reader.js

I know next to nothing about 3D graphics, matrices, and transforms, so
any information would be helpful.

Nicolas Garcia Belmonte

unread,
Apr 1, 2011, 9:21:30 PM4/1/11
to phi...@googlegroups.com
Hi,

Here's a code that does exactly what you're looking for... but it's
for another project:

https://github.com/philogb/jit/blob/master/Source/Geometry/O3D.js#L223

The main idea is to create a "normalized" cylinder (that would have,
say 1 of height and 0.5 or radius) and then apply the scaling,
rotation and translation based on the two points.

The scaling of the cylinder will be based on the distance between the
two points.
The translation of the cylinder will be to the middle point of the
line connecting the two points.
The rotation of the cylinder is the tricky part, and it's based on a
direction vector, and a rotation angle.

You can find how the vector and angle are found here:

https://github.com/philogb/jit/blob/master/Source/Geometry/O3D.js#L223

Then you can create the rotation matrix by using the method rotateAxis:

http://senchalabs.github.com/philogl/doc/math.html#Mat4:rotateAxis

Finally you set the rotation matrix, and apply the scaling and
translation and don't forget to update the object.

I hope this helps, let me know if you have any further questions.

--
Nicolas Garcia Belmonte - http://philogb.github.com/

rapodaca

unread,
Apr 11, 2011, 7:48:14 PM4/11/11
to PhiloGL
Hello Nicholas,

Thanks for the pointers. Unfortunately, I'm still not getting it.

In the code I posted, I can already place the scaled cylinders without
a problem. I'm just not sure how to get them rotated such that their
endpoints line up with the coordinates of the spheres.

The link you provided:

https://github.com/philogb/jit/blob/master/Source/Geometry/O3D.js#L223

looks interesting, but I'm not seeing anything in the 'updateEdge'
function that addresses the problem of rotating the axis of a cylinder
to lie on a line defined by two points. I'm probably missing something
key, but I'm pretty much a beginner at this.

I think I may be looking for something that explains how to generate
the rotation matrix in this particular case and then apply it. This
seems like something that should be trivial.

Any ideas?

Thanks,
Rich
> >http://blog.metamolecular.com/articles/2011/03/07/webgl-for-chemistry...
>
> > I've hit a snag when trying to align the endpoints of a Cylinder
> > between two points. PhiloGL.O3D.Cylinder can be rotated along the x,
> > y, and z axes. But I'd like to align the endpoints of the Cylinder
> > between to points.
>
> > How can I do this?
>
> > I've pushed my code to:
>
> >https://github.com/metamolecular/webgl-chem
>
> > The two relevant sections are:
>
> > view.js (line 99, 'drawBond'):
>
> >https://github.com/metamolecular/webgl-chem/blob/master/lessons/lesso...
>
> > and
>
> > molfile_reader.js (beginning line 54, 'getRotation'):
>
> >https://github.com/metamolecular/webgl-chem/blob/master/lessons/lesso...

Nicolas Garcia Belmonte

unread,
Apr 12, 2011, 1:56:55 PM4/12/11
to phi...@googlegroups.com
Hi,

The updateEdge method creates that same rotation matrix. In some sort
of non-tested PhiloGL pseudo-code the code to set the position,
scaling and rotation of the object would be:

//the two points where you want to align the cylinder
var p1 = new PhiloGL.Vec3(x1, y1, z1),
p2 = new PhiloGL.Vec3(x2, y2, z2),
//distance between the two points
dist = p1.distTo(p2),
//current direction of the cylinder (facing up)
currentDir = new PhiloGL.Vec3(0, 1, 0),
//middle point
mp = p1.add(p2).$scale(0.5),
//direction vector from p1 to p2
dv = p2.sub(p1).$unit();

//now create parameters to fill the rotation matrix
var c = dv.dot(currentDir),
rotAngle = Math.acos(c),
rotAxis = currentDir.$cross(dv).$unit();

//now set rotation translation and scaling to the model
var cylinderMatrix = cylinder.matrix;
//clear the matrix
cylinderMatrix.id();
//translate to the middle point
cylinderMatrix.$translate(mp.x, mp.y, mp.z);
//scale to the distance of the two points
cylinderMatrix.$scale(1, dist, 1);
//rotate around an angle and an axis
cylinderMatrix.$rotateAxis(rotAngle, rotAxis);

This should do the trick. Remember to have cylinders of length 1. Let
me know how it goes.

var rot = new Matrix4();
rot.n11 = t * x * x + c;
rot.n12 = t * x * y - s * z;
rot.n13 = t * x * z + s * y;
rot.n21 = t * x * y + s * z;
rot.n22 = t * y * y + c;
rot.n23 = t * y * z - s * x;
rot.n31 = t * x * z - s * y;
rot.n32 = t * y * z + s * x;
rot.n33 = t * z * z + c;

--

rapodaca

unread,
Apr 12, 2011, 8:01:12 PM4/12/11
to PhiloGL
Hello Nicholas,

Many thanks - really appreciate the help. This is the right track, but
somehow I can't get it to work.

I've pushed my code here:

https://github.com/metamolecular/webgl-chem

The relevant function is m3d.View#drawBond (see below).

When I view the result, it appears that the modifications to the
matrix are not being applied. The cylinder is still at (0, 0, 0) and
pointed in its original direction:

http://i.imgur.com/CUUL7.png

Any ideas?

Rich

/**
* @param {object} bond The bond to draw
*/
m3d.View.prototype.drawBond = function(bond) {
var cylinder = new PhiloGL.O3D.Cylinder({ radius: 0.1, height: 1});
var p1 = bond.source.position;
var p2 = bond.target.position;

//distance between the two points
var dist = p1.distTo(p2);
//current direction of the cylinder (facing up)
var currentDir = new PhiloGL.Vec3(0, 1, 0);
//middle point
var mp = p1.add(p2).$scale(0.5);
//direction vector from p1 to p2
var dv = p2.sub(p1).$unit();

//now create parameters to fill the rotation matrix
var c = dv.dot(currentDir);
var rotAngle = Math.acos(c);
var rotAxis = currentDir.$cross(dv).$unit();

//now set rotation translation and scaling to the model
var cylinderMatrix = cylinder.matrix;
//clear the matrix
cylinderMatrix.id();
//translate to the middle point
cylinderMatrix.$translate(mp.x, mp.y, mp.z);
//scale to the distance of the two points
cylinderMatrix.$scale(1, dist, 1);
//rotate around an angle and an axis
cylinderMatrix.$rotateAxis(rotAngle, rotAxis);

cylinder.update();

this.scene_.add(cylinder);
};

On Apr 12, 10:56 am, Nicolas Garcia Belmonte <phil...@gmail.com>
wrote:
> Hi,
>

Nicolas Garcia Belmonte

unread,
Apr 12, 2011, 11:51:20 PM4/12/11
to phi...@googlegroups.com

Do not call update on the model, you're already updating the matrix manually by doing what I wrote before :)

Nicolas Garcia Belmonte

unread,
Apr 13, 2011, 12:24:33 AM4/13/11
to phi...@googlegroups.com

rapodaca

unread,
Apr 13, 2011, 1:30:20 AM4/13/11
to PhiloGL
Hello Nicolas,

Success! Thanks again for the help.

Here's what ended up working:

/**
* @param {object} bond The bond to draw
*/
m3d.View.prototype.drawBond = function(bond) {
var cylinder = new PhiloGL.O3D.Cylinder({ radius: 0.2, height:
bond.getLength()});
var p1 = bond.source.position;
var p2 = bond.target.position;

//current direction of the cylinder (facing up)
var currentDir = new PhiloGL.Vec3(0, 1, 0);
//middle point
var mp = p1.add(p2).$scale(0.5);
//direction vector from p1 to p2
var dv = p2.sub(p1).$unit();

//now create parameters to fill the rotation matrix
var c = dv.dot(currentDir);
var rotAngle = Math.acos(c);
var rotAxis = currentDir.$cross(dv).$unit();

//now set rotation translation and scaling to the model
var cylinderMatrix = cylinder.matrix;
//clear the matrix
cylinderMatrix.id();
//translate to the middle point
cylinderMatrix.$translate(mp.x, mp.y, mp.z);
//rotate around an angle and an axis
cylinderMatrix.$rotateAxis(rotAngle, rotAxis);

this.scene_.add(cylinder);
};

On Apr 12, 9:24 pm, Nicolas Garcia Belmonte <phil...@gmail.com> wrote:
> i.e try removing :
>
> https://github.com/metamolecular/webgl-chem/blob/master/lessons/lesso...
>
> that line
>
> On Wed, Apr 13, 2011 at 12:51 AM, Nicolas Garcia Belmonte
>
>
>
>
>
> <phil...@gmail.com> wrote:
> > Do not call update on the model, you're already updating the matrix manually
> > by doing what I wrote before :)
>

Nicolas Garcia Belmonte

unread,
Apr 13, 2011, 9:17:16 AM4/13/11
to phi...@googlegroups.com
Let me know when you have the article with the end result, would love
to read it :)

--

rapodaca

unread,
Apr 13, 2011, 12:46:14 PM4/13/11
to PhiloGL
Hello Nicolas,

Here it is:

http://blog.metamolecular.com/articles/2011/04/13/bond-james-bond/

Thanks again for the help - it was key to being able to move forward.

Rich
Reply all
Reply to author
Forward
0 new messages