private void setHeading(Point3f pt, Vector3f vNorm, int nSeconds) {
// general trick here is to save the original orientation,
// then do all the changes and save the new orientation.
// Then just do a timed restore.
Orientation o1 = viewer.getOrientation();
// move to point
viewer.navigate(0, pt);
Point3f toPts = new Point3f();
// get screen point along normal
Point3f toPt = new Point3f(vNorm);
//viewer.script("draw test2 vector " + Escape.escape(pt) + " " + Escape.escape(toPt));
toPt.add(pt);
viewer.transformPoint(toPt, toPts);
// subtract the navigation point to get a relative point
// that we can project into the xy plane by setting z = 0
Point3f navPt = new Point3f(viewer.getNavigationOffset());
toPts.sub(navPt);
toPts.z = 0;
// set the directed angle and rotate normal into yz plane,
// less 20 degrees for the normal upward sloping view
float angle = Measure.computeTorsion(JmolConstants.axisNY,
JmolConstants.center, JmolConstants.axisZ, toPts, true);
viewer.navigate(0, JmolConstants.axisZ, angle);
toPt.set(vNorm);
toPt.add(pt);
viewer.transformPoint(toPt, toPts);
toPts.sub(navPt);
angle = Measure.computeTorsion(JmolConstants.axisNY,
JmolConstants.center, JmolConstants.axisX, toPts, true);
viewer.navigate(0, JmolConstants.axisX, 20 - angle);
// save this orientation, restore the first, and then
// use TransformManager.moveto to smoothly transition to it
// a script is necessary here because otherwise the application
// would hang.
navPt = new Point3f(viewer.getNavigationOffset());
if (nSeconds <= 0)
return;
viewer.saveOrientation("_navsurf");
o1.restore(0, true);
viewer.script("restore orientation _navsurf " + nSeconds);
}