Revision: 5150
Author:   hansonr
Date:     2006-05-20 07:10:42 -0700 (Sat, 20 May 2006)
ViewCVS:  http://svn.sourceforge.net/jmol/?rev=5150&view=rev

Log Message:
-----------
bob200603 10.x.04 -- developers take note --

Finally!!! Full integration of spin and rotation. 

Modifications presented here completely integrate spin and rotation. 
Previous behavior is retained, but both commands now take a second
parameter -- in the case of spin, the number of degrees total to spin;
in the case of rotate, the frames per second to rotate. So it is
the same method -- spin or rotate -- going through the exact same
procedures. See detailed notes in Eval.rotate() for details. 

fully supports smooth internal- and fixed-frame rotation and spinning,
fully supports windowCentered off (Frieda switch)
with set windowCentered off the default is to protect the camera; 
adds an option to "set adjustCamera off" if that behavior is not desired.

Testing pages will be at 
http://www.stolaf.edu/people/hansonr/jmol/test/proto/fraction.htm

Modified Paths:
--------------
    branches/bob200603/Jmol/src/org/jmol/viewer/Eval.java
    branches/bob200603/Jmol/src/org/jmol/viewer/Frame.java
    branches/bob200603/Jmol/src/org/jmol/viewer/JmolConstants.java
    branches/bob200603/Jmol/src/org/jmol/viewer/ModelManager.java
    branches/bob200603/Jmol/src/org/jmol/viewer/TransformManager.java
    branches/bob200603/Jmol/src/org/jmol/viewer/Viewer.java
Modified: branches/bob200603/Jmol/src/org/jmol/viewer/Eval.java
===================================================================
--- branches/bob200603/Jmol/src/org/jmol/viewer/Eval.java       2006-05-20 
14:06:58 UTC (rev 5149)
+++ branches/bob200603/Jmol/src/org/jmol/viewer/Eval.java       2006-05-20 
14:10:42 UTC (rev 5150)
@@ -33,7 +33,6 @@
 import javax.vecmath.Point3f;
 import javax.vecmath.Vector3f;
 
-
 class Context {
   String filename;
 
@@ -120,7 +119,7 @@
   }
 
   synchronized void clearMyThread() {
-    myThread = null; 
+    myThread = null;
   }
 
   boolean isActive() {
@@ -357,7 +356,7 @@
     viewer.setTainted(true);
     viewer.popHoldRepaint();
   }
-  
+
   void instructionDispatchLoop() throws ScriptException {
     long timeBegin = 0;
     if (logMessages) {
@@ -498,7 +497,7 @@
         proteinShape(JmolConstants.SHAPE_ROCKETS);
         break;
       case Token.spin:
-        spin();
+        rotate(true);
         break;
       case Token.ssbond:
         ssbond();
@@ -603,7 +602,7 @@
     strbufLog.setLength(0);
     System.out.println(statement[0]);
     for (int i = 1; i < statementLength; ++i) {
-      strbufLog.append(statement[i]+"\n");
+      strbufLog.append(statement[i] + "\n");
       System.out.println(statement[i]);
     }
     strbufLog.append(statement[0].value.toString());
@@ -945,7 +944,7 @@
     case Token.decimal:
       float angstroms = floatParameter(2);
       if (angstroms < 0 || angstroms >= 2)
-        numberOutOfRange(0f,1.99999f);
+        numberOutOfRange(0f, 1.99999f);
       mad = (short) (angstroms * 1000 * 2);
       break;
     case Token.dotted:
@@ -985,7 +984,7 @@
     int sp = 0;
     boolean refreshed = false;
     pcLastExpressionInstruction = 1000;
-    
+
     if (logMessages)
       viewer.scriptStatus("start to evaluate expression");
     expression_loop: for (int pc = pcStart;; ++pc) {
@@ -1052,30 +1051,35 @@
         stack[sp++] = viewer.getAtomBits((String) instruction.value);
         break;
       case Token.spec_name_pattern:
-        stack[sp++] = viewer.getAtomBits("SpecName", (String) 
instruction.value);
+        stack[sp++] = viewer
+            .getAtomBits("SpecName", (String) instruction.value);
         break;
       case Token.spec_resid:
         stack[sp++] = viewer.getAtomBits("SpecResid", instruction.intValue);
         break;
       case Token.spec_seqcode:
-        stack[sp++] = viewer.getAtomBits("SpecSeqcode",instruction.intValue);
+        stack[sp++] = viewer.getAtomBits("SpecSeqcode", instruction.intValue);
         break;
       case Token.spec_seqcode_range:
         int seqcodeA = instruction.intValue;
         int seqcodeB = ((Integer) instruction.value).intValue();
-        stack[sp++] = viewer.getAtomBits("SpecSeqcodeRange", seqcodeA, 
seqcodeB);
+        stack[sp++] = viewer
+            .getAtomBits("SpecSeqcodeRange", seqcodeA, seqcodeB);
         break;
       case Token.spec_chain:
         stack[sp++] = viewer.getAtomBits("SpecChain", instruction.intValue);
         break;
       case Token.spec_atom:
-        stack[sp++] = viewer.getAtomBits("SpecAtom", (String) 
instruction.value);
+        stack[sp++] = viewer
+            .getAtomBits("SpecAtom", (String) instruction.value);
         break;
       case Token.spec_alternate:
-        stack[sp++] = viewer.getAtomBits("SpecAlternate", (String) 
instruction.value);
+        stack[sp++] = viewer.getAtomBits("SpecAlternate",
+            (String) instruction.value);
         break;
       case Token.spec_model:
-        stack[sp++] = viewer.getAtomBits("SpecModel", (String) 
instruction.value);
+        stack[sp++] = viewer.getAtomBits("SpecModel",
+            (String) instruction.value);
         break;
       case Token.y:
       case Token.amino:
@@ -1120,7 +1124,7 @@
     BitSet bsDefinedSet = lookupValue(identifier, false);
     if (bsDefinedSet != null)
       return copyBitSet(bsDefinedSet); // identifier had been previously
-                                        // defined
+    // defined
     // System.out.println("undefined & trying specname with:" + identifier);
     // determine number of leading alpha characters
     int alphaLen = 0;
@@ -1132,7 +1136,8 @@
     String potentialGroupName = identifier.substring(0, alphaLen);
     // System.out.println("potentialGroupName=" + potentialGroupName);
     // undefinedVariable();
-    BitSet bsName = viewer.getAtomBits("PotentialGroupName", 
potentialGroupName);
+    BitSet bsName = viewer
+        .getAtomBits("PotentialGroupName", potentialGroupName);
     if (bsName == null)
       undefinedVariable(identifier);
     if (alphaLen == len)
@@ -1355,7 +1360,7 @@
       viewer.setBackgroundArgb(getArgbOrNoneParam(1));
     else
       viewer.setShapePropertyArgb(getShapeType(tok), "bgcolor",
-                                  getArgbOrNoneParam(2));
+          getArgbOrNoneParam(2));
   }
 
   // mth - 2003 01
@@ -1386,8 +1391,9 @@
 
     viewer.setCenterBitSet(expression(statement, 1), true);
   }
-  
+
   boolean coordinatesAreFractional;
+
   Point3f getCoordinate(int i, boolean allowFractional) throws ScriptException 
{
     // syntax:  {1/2, 1/2, 1/3} or {0.5/, 0.5, 0.5}
     // ONE fractional sign anywhere is enough to make ALL fractional;
@@ -1398,14 +1404,14 @@
       coordinateExpected();
     Point3f pt = new Point3f();
     for (int j = i; j + 1 < statement.length; j++) {
-        switch (statement[j].tok) {
-        case Token.slash:
-          coordinatesAreFractional = true;
-        case Token.rightbrace:          
-          break;
-        }
+      switch (statement[j].tok) {
+      case Token.slash:
+        coordinatesAreFractional = true;
+      case Token.rightbrace:
+        break;
+      }
     }
-    if (coordinatesAreFractional && ! allowFractional)
+    if (coordinatesAreFractional && !allowFractional)
       evalError("fractional coordinates are not allowed in this context");
     pt.x = coordinateValue(i);
     pt.y = coordinateValue(++pcLastExpressionInstruction);
@@ -1437,11 +1443,11 @@
     case Token.integer:
       return token.intValue;
     case Token.decimal:
-      return  ((Float) token.value).floatValue();
+      return ((Float) token.value).floatValue();
     }
     return 0;
   }
-  
+
   void color() throws ScriptException {
     if (statementLength > 5 || statementLength < 2)
       badArgumentCount();
@@ -1480,18 +1486,18 @@
       String str = (String) statement[1].value;
       int argb = getArgbOrNoneParam(2);
       if (str.equalsIgnoreCase("dotsConvex")) {
-        viewer.setShapePropertyArgb(JmolConstants.SHAPE_DOTS,
-                                    "colorConvex", argb);
+        viewer.setShapePropertyArgb(JmolConstants.SHAPE_DOTS, "colorConvex",
+            argb);
         return;
       }
       if (str.equalsIgnoreCase("dotsConcave")) {
-        viewer.setShapePropertyArgb(JmolConstants.SHAPE_DOTS,
-                                    "colorConcave", argb);
+        viewer.setShapePropertyArgb(JmolConstants.SHAPE_DOTS, "colorConcave",
+            argb);
         return;
       }
       if (str.equalsIgnoreCase("dotsSaddle")) {
-        viewer.setShapePropertyArgb(JmolConstants.SHAPE_DOTS,
-                                    "colorSaddle", argb);
+        viewer.setShapePropertyArgb(JmolConstants.SHAPE_DOTS, "colorSaddle",
+            argb);
         return;
       }
       if (str.equalsIgnoreCase("selectionHalo")) {
@@ -1499,8 +1505,7 @@
         return;
       }
       if (str.equalsIgnoreCase("unitcell")) {
-        viewer.setShapePropertyArgb(JmolConstants.SHAPE_UCCAGE,
-                                    "color", argb);
+        viewer.setShapePropertyArgb(JmolConstants.SHAPE_UCCAGE, "color", argb);
         return;
       }
       for (int i = JmolConstants.elementNames.length; --i >= 0;) {
@@ -1530,24 +1535,25 @@
     }
   }
 
-  void colorIdentifiedObject(int index) throws ScriptException{
+  void colorIdentifiedObject(int index) throws ScriptException {
     // color $ whatever green
     String objectName = objectNameParameter(index);
     int shapeType = viewer.getShapeIdFromObjectName(objectName);
-    System.out.println("colorIdentifiedObject"+index+" "+shapeType+" 
"+objectName);
+    System.out.println("colorIdentifiedObject" + index + " " + shapeType + " "
+        + objectName);
     if (shapeType < 0)
       objectNameExpected();
     viewer.setShapeProperty(shapeType, "meshID", objectName);
     colorShape(shapeType, index + 1);
   }
-  
+
   void colorObject(int tokObject, int itoken) throws ScriptException {
     int shapeType = getShapeType(tokObject);
     colorShape(shapeType, itoken);
   }
 
   void colorShape(int shapeType, int itoken) throws ScriptException {
-   if (itoken >= statementLength)
+    if (itoken >= statementLength)
       badArgumentCount();
     String translucentOrOpaque = null;
     Object colorvalue = null;
@@ -1586,7 +1592,7 @@
       case Token.group:
         viewer.calcSelectedGroupsCount();
         break;
-      case Token.monomer: 
+      case Token.monomer:
         viewer.calcSelectedMonomersCount();
         break;
       case Token.molecule:
@@ -1664,7 +1670,7 @@
     // ignore optional file format
     String filename = "fileset";
     if (statementLength == 1)
-      filenameExpected();      
+      filenameExpected();
     if (statement[i].tok == Token.identifier)
       ++i;
     if (statement[i].tok != Token.string)
@@ -1673,7 +1679,8 @@
     if (statementLength == i + 1) {
       filename = (String) statement[i].value;
       viewer.openFile(filename, params);
-    } else if (statement[i + 1].tok == Token.leftbrace || statement[i + 1].tok 
== Token.integer) {
+    } else if (statement[i + 1].tok == Token.leftbrace
+        || statement[i + 1].tok == Token.integer) {
       filename = (String) statement[i++].value;
       if (statement[i].tok == Token.integer)
         params[0] = statement[i++].intValue;
@@ -1704,11 +1711,11 @@
     String defaultScript = viewer.getDefaultLoadScript();
     String msg = "";
     if (defaultScript.length() > 0)
-      msg += "\nUsing defaultLoadScript: "+defaultScript;
+      msg += "\nUsing defaultLoadScript: " + defaultScript;
     String script = viewer.getModelSetProperty("jmolscript");
     if (script != null) {
-      msg += "\nAdding embedded #jmolscript: "+script;
-      defaultScript+=";"+script;
+      msg += "\nAdding embedded #jmolscript: " + script;
+      defaultScript += ";" + script;
     }
     if (msg.length() > 0)
       System.out.println(msg);
@@ -1788,7 +1795,8 @@
     if (isAll) {
       if (rangeMinMax[1] < rangeMinMax[0]) {
         rangeMinMax[1] = rangeMinMax[0];
-        rangeMinMax[0] = (rangeMinMax[1] == Float.MAX_VALUE ? Float.MAX_VALUE 
: -200F);
+        rangeMinMax[0] = (rangeMinMax[1] == Float.MAX_VALUE ? Float.MAX_VALUE
+            : -200F);
       }
       viewer.defineMeasurement(monitorExpressions, rangeMinMax);
     } else {
@@ -1876,8 +1884,18 @@
      *
      */
 
-    int degrees = 10;
+    switch (statement[1].tok) {
+    case Token.on:
+      viewer.setSpinOn(true);
+      return;
+    case Token.off:
+      viewer.setSpinOn(false);
+      return;
+    }
+
+    float degrees = Float.MIN_VALUE;
     int nPoints = 0;
+    float endDegrees = Float.MAX_VALUE;
     boolean isAxisAngle = false;
     boolean isInternal = false;
     //rotate INTERNAL nDegrees (coord/atom expression) (coord/atomexpression)
@@ -1888,6 +1906,7 @@
     int direction = 1;
     boolean axesOrientationRasmol = viewer.getAxesOrientationRasmol();
 
+    
     for (int i = 0; i < 3; ++i)
       points[i] = new Point3f(0, 0, 0);
     for (int i = 1; i < statementLength; ++i) {
@@ -1950,10 +1969,20 @@
       case Token.opOr:
         break;
       case Token.integer:
-        degrees = token.intValue;
-        break;
+        statement[i].value = new Float(token.intValue);
       case Token.decimal:
-        degrees = (new Float(floatParameter(i))).intValue();
+        //spin: degrees per second followed by final value
+        //rotate: end degrees followed by degrees per second
+        //rotate is a full replacement for spin
+        //spin is DEPRECATED
+
+        if (degrees == Float.MIN_VALUE)
+          degrees = floatParameter(i);
+        else {
+          endDegrees = degrees;
+          degrees = floatParameter(i);
+          isSpin = true;
+        }
         break;
       case Token.expressionBegin:
         BitSet bs = expression(statement, i + 1);
@@ -1979,8 +2008,10 @@
       // rotate x 10 (atoms)
       // rotate x 10 $object
       // rotate x 10 
-      System.out.println("rotating externally: " + rotCenter + rotAxis);
-      viewer.rotateAxisAngleAtCenter(rotCenter, rotAxis, degrees, isSpin);
+      if (degrees == Integer.MIN_VALUE)
+        degrees = 10;
+      viewer.rotateAxisAngleAtCenter(rotCenter, rotAxis, degrees, endDegrees,
+          isSpin);
       return;
     }
     if (nPoints < 2) {
@@ -1998,11 +2029,12 @@
 
     if (points[0].distance(points[1]) == 0)
       rotationPointsIdentical();
+    if (degrees == Integer.MIN_VALUE)
+      degrees = 10;
+    viewer.rotateAboutPointsInternal(points[0], points[1], degrees, endDegrees,
+        isSpin);
+  }
 
-    System.out.println("rotating internally: " + points[0] + points[1]);
-    viewer.rotateAboutPointsInternal(points[0], points[1], degrees, isSpin);
-  }
-  
   void pushContext() throws ScriptException {
     if (scriptLevel == scriptLevelMax)
       evalError("too many script levels");
@@ -2043,11 +2075,11 @@
 
   void select() throws ScriptException {
     // NOTE this is called by restrict()
-    viewer.select(statementLength == 1? null : expression(statement, 1));
+    viewer.select(statementLength == 1 ? null : expression(statement, 1));
   }
 
   void translate() throws ScriptException {
-    if (statementLength <3)
+    if (statementLength < 3)
       badArgumentCount();
     if (statement[2].tok != Token.integer)
       integerExpected();
@@ -2125,9 +2157,11 @@
   void move() throws ScriptException {
     if (statementLength < 10 || statementLength > 12)
       badArgumentCount();
-    Vector3f dRot = new Vector3f(floatParameter(1), floatParameter(2), 
floatParameter(3));
+    Vector3f dRot = new Vector3f(floatParameter(1), floatParameter(2),
+        floatParameter(3));
     int dZoom = intParameter(4);
-    Vector3f dTrans = new Vector3f(intParameter(5), intParameter(6), 
intParameter(7));
+    Vector3f dTrans = new Vector3f(intParameter(5), intParameter(6),
+        intParameter(7));
     int dSlab = intParameter(8);
     float floatSecondsTotal = floatParameter(9);
     int fps = 30/* , maxAccel = 5 */;
@@ -2187,13 +2221,13 @@
       if (statementLength == 2) {
         if (radiusRasMol >= 750 || radiusRasMol < -100)
           numberOutOfRange(-100, 749);
-        mad = (short)radiusRasMol;
+        mad = (short) radiusRasMol;
         if (radiusRasMol > 0)
           mad *= 4 * 2;
       } else {
         if (radiusRasMol < 0 || radiusRasMol > 100)
           numberOutOfRange(0, 100);
-        mad = (short)-radiusRasMol; // use a negative number to specify %vdw
+        mad = (short) -radiusRasMol; // use a negative number to specify %vdw
       }
       break;
     case Token.decimal:
@@ -2237,13 +2271,13 @@
       if (statementLength == 2) {
         if (radiusRasMol >= 750 || radiusRasMol < -200)
           numberOutOfRange(-200, 749);
-        mad = (short)radiusRasMol;
+        mad = (short) radiusRasMol;
         if (radiusRasMol > 0)
           mad *= 4 * 2;
       } else {
         if (radiusRasMol < 0 || radiusRasMol > 200)
           numberOutOfRange(0, 200);
-        mad = (short)-radiusRasMol; // use a negative number to specify %vdw
+        mad = (short) -radiusRasMol; // use a negative number to specify %vdw
       }
       break;
     case Token.decimal:
@@ -2331,7 +2365,7 @@
       viewer.autoHbond(bsConformations, bsConformations);
     viewer.setSelectionSet(bsConformations);
   }
-  
+
   void vector() throws ScriptException {
     short mad = 1;
     if (statementLength > 1) {
@@ -2375,7 +2409,6 @@
     viewer.setVectorScale(scale);
   }
 
-
   void dipole() throws ScriptException {
     //dipole intWidth floatMagnitude OFFSET floatOffset {atom1} {atom2}
     viewer.loadShape(JmolConstants.SHAPE_DIPOLES);
@@ -2637,23 +2670,6 @@
     viewer.setShapeSize(shapeType, mad);
   }
 
-  void spin() throws ScriptException {
-    boolean spinOn = false;
-    if (statementLength == 1) {
-      rotate(true);
-      return;
-    }
-    switch (statement[1].tok) {
-    case Token.on:
-      spinOn = true;
-    case Token.off:
-      viewer.setSpinOn(spinOn);
-      break;
-    default:
-      rotate(true);
-    }
-  }
-
   void animation() throws ScriptException {
     if (statementLength < 2)
       subcommandExpected();
@@ -2687,7 +2703,7 @@
 
   void frame(int offset, boolean useModelNumber) throws ScriptException {
     useModelNumber = true; // for now -- as before -- remove to implement
-                            // frame/model difference
+    // frame/model difference
     if (statementLength <= offset)
       badArgumentCount();
     if (statement[offset].tok == Token.hyphen) {
@@ -2789,8 +2805,8 @@
       Token.dots, Token.backbone, Token.trace, Token.cartoon, Token.strands,
       Token.meshRibbon, Token.ribbon, Token.rocket, Token.star, Token.axes,
       Token.boundbox, Token.unitcell, Token.frank, Token.echo, Token.hover,
-      Token.polyhedra, Token.prueba, 
-      Token.pmesh,  Token.sasurface, Token.isosurface, Token.draw, 
Token.dipole};
+      Token.polyhedra, Token.prueba, Token.pmesh, Token.sasurface,
+      Token.isosurface, Token.draw, Token.dipole };
 
   static {
     if (shapeToks.length != JmolConstants.SHAPE_MAX) {
@@ -2952,7 +2968,7 @@
       notImplemented(1);
       break;
     case Token.identifier:
-      if (((String)statement[1].value).equalsIgnoreCase("defaultLattice")) {
+      if (((String) statement[1].value).equalsIgnoreCase("defaultLattice")) {
         if (statement.length < 3)
           badArgumentCount();
         Point3f pt;
@@ -2963,9 +2979,10 @@
           pt = getCoordinate(2, false);
         }
         viewer.setDefaultLattice(pt);
-      } else if 
(((String)statement[1].value).equalsIgnoreCase("defaultLoadScript")) {
+      } else if (((String) statement[1].value)
+          .equalsIgnoreCase("defaultLoadScript")) {
         checkLength3();
-        if (statement[2].tok != Token.string) 
+        if (statement[2].tok != Token.string)
           stringExpected();
         viewer.setDefaultLoadScript((String) statement[2].value);
       } else {
@@ -3167,8 +3184,8 @@
       if (strandCount < 0 || strandCount > 20)
         numberOutOfRange(0, 20);
     }
-    viewer.setShapeProperty(JmolConstants.SHAPE_STRANDS,
-                            "strandCount", new Integer(strandCount));
+    viewer.setShapeProperty(JmolConstants.SHAPE_STRANDS, "strandCount",
+        new Integer(strandCount));
   }
 
   void setSpecular() throws ScriptException {
@@ -3318,7 +3335,7 @@
         pickingMode = JmolConstants.PICKING_SPIN;
         int rate = 10;
         if (statementLength == 4) {
-            rate = intParameter(3);
+          rate = intParameter(3);
         }
         viewer.setPickingSpinRate(rate);
         break;
@@ -3361,7 +3378,7 @@
       invalidArgument();
     }
   }
-  
+
   /* 
****************************************************************************
    * ============================================================== SHOW
    * implementations
@@ -3441,12 +3458,13 @@
   }
 
   void showMeasurements() {
-    showString(viewer.getMeasurementInfoAsString());  
+    showString(viewer.getMeasurementInfoAsString());
   }
- 
+
   void showSymmetry() {
-    showString(viewer.getSymmetryInfoAsString());    
+    showString(viewer.getSymmetryInfoAsString());
   }
+
   void showFile() throws ScriptException {
     System.out.println("showFile && statementLength=" + statementLength);
     if (statementLength == 2) {
@@ -3516,7 +3534,7 @@
       yTrans = intParameter(i++);
     viewer.moveTo(floatSecondsTotal, pt, degrees, zoom, xTrans, yTrans);
   }
-  
+
   void bondorder() throws ScriptException {
     Token tokenArg = statement[1];
     short order = 0;
@@ -3625,8 +3643,8 @@
       default:
         invalidArgument();
       }
-      viewer.setShapeProperty(JmolConstants.SHAPE_PMESH,
-                              propertyName, propertyValue);
+      viewer.setShapeProperty(JmolConstants.SHAPE_PMESH, propertyName,
+          propertyValue);
     }
   }
 
@@ -3634,7 +3652,7 @@
     viewer.loadShape(JmolConstants.SHAPE_DRAW);
     viewer.setShapeProperty(JmolConstants.SHAPE_DRAW, "meshID", null);
     boolean havePoints = false;
-    
+
     boolean isInitialized = false;
     int intScale = 0;
     boolean isFixed = false;
@@ -3653,22 +3671,22 @@
           continue;
         }
         if (((String) propertyValue).equalsIgnoreCase("PLANE")) {
-          propertyName = "plane";  
+          propertyName = "plane";
         }
         if (((String) propertyValue).equalsIgnoreCase("CROSSED")) {
-          propertyName = "crossed";  
+          propertyName = "crossed";
         }
         if (((String) propertyValue).equalsIgnoreCase("VERTICES")) {
           propertyName = "vertices";
         }
         if (((String) propertyValue).equalsIgnoreCase("REVERSE")) {
-          propertyName = "reverse";  
+          propertyName = "reverse";
         }
         if (((String) propertyValue).equalsIgnoreCase("ROTATE45")) {
-          propertyName = "rotate45";  
+          propertyName = "rotate45";
         }
-        if (((String) propertyValue).equalsIgnoreCase("PERP") ||
-            ((String) propertyValue).equalsIgnoreCase("PERPENDICULAR")) {
+        if (((String) propertyValue).equalsIgnoreCase("PERP")
+            || ((String) propertyValue).equalsIgnoreCase("PERPENDICULAR")) {
           propertyName = "perp";
         }
         break;
@@ -3737,7 +3755,7 @@
       }
       if (propertyName != null)
         viewer.setShapeProperty(JmolConstants.SHAPE_DRAW, propertyName,
-          propertyValue);
+            propertyValue);
     }
     if (havePoints) {
       viewer.setShapeProperty(JmolConstants.SHAPE_DRAW, "set", null);
@@ -3776,7 +3794,8 @@
         } else if (propertyName.equalsIgnoreCase("to")) {
           isChange = true;
           iHaveVertexExpression = true;
-          if (++i == statementLength || statement[i].tok != 
Token.expressionBegin)
+          if (++i == statementLength
+              || statement[i].tok != Token.expressionBegin)
             expressionExpected();
           propertyValue = expression(statement, ++i);
           i = pcLastExpressionInstruction;
@@ -3801,10 +3820,10 @@
         propertyName = (String) token.value;
         break;
       case Token.expressionBegin:
-        if (iHaveVertexExpression || ! iHaveCenterExpression) { 
+        if (iHaveVertexExpression || !iHaveCenterExpression) {
           propertyName = "centers";
           iHaveCenterExpression = true;
-        } else { 
+        } else {
           propertyName = "to";
           iHaveVertexExpression = true;
         }
@@ -3832,13 +3851,13 @@
       switch (token.tok) {
       case Token.identifier:
         propertyValue = token.value;
-        // fall into
+      // fall into
       case Token.all:
         propertyName = "surfaceID";
         break;
       case Token.on:
       case Token.off:
-        propertyName = (String)token.value;
+        propertyName = (String) token.value;
         break;
       case Token.delete:
         propertyName = "delete";
@@ -3846,8 +3865,8 @@
       default:
         invalidArgument();
       }
-      viewer.setShapeProperty(JmolConstants.SHAPE_SASURFACE,
-                              propertyName, propertyValue);
+      viewer.setShapeProperty(JmolConstants.SHAPE_SASURFACE, propertyName,
+          propertyValue);
     }
   }
 
@@ -3892,7 +3911,7 @@
       Token token = statement[i];
       switch (token.tok) {
       case Token.identifier:
-        if (((String)token.value).equalsIgnoreCase("fileIndex")) {
+        if (((String) token.value).equalsIgnoreCase("fileIndex")) {
           fileIndexPt = i + 1;
           break;
         }
@@ -3901,12 +3920,12 @@
         propertyName = "meshID";
         break;
       case Token.string:
-        String filename = (String)token.value;
+        String filename = (String) token.value;
         if (filename.length() == 0)
           filename = viewer.getFullPathName();
         System.out.println("reading isosurface data from " + filename);
-        Object t =
-          viewer.getUnzippedBufferedReaderOrErrorMessageFromName(filename);
+        Object t = viewer
+            .getUnzippedBufferedReaderOrErrorMessageFromName(filename);
         if (t instanceof String)
           fileNotFoundException(filename + ":" + t);
         propertyName = colorSeen ? "colorReader" : "bufferedReader";
@@ -3920,10 +3939,10 @@
           propertyValue = token.value;
           break;
         }
-        // fall into
+      // fall into
       case Token.integer:
         if (i == fileIndexPt) {
-          if (token.tok != Token.integer) 
+          if (token.tok != Token.integer)
             integerExpected();
           propertyName = "fileIndex";
           propertyValue = new Integer(token.intValue);
@@ -3952,7 +3971,7 @@
         break;
       case Token.on:
       case Token.off:
-        propertyName = (String)token.value;
+        propertyName = (String) token.value;
         break;
       case Token.delete:
         propertyName = "delete";
@@ -3968,8 +3987,8 @@
         invalidArgument();
       }
       if (propertyName != null)
-        viewer.setShapeProperty(JmolConstants.SHAPE_ISOSURFACE,
-                                propertyName, propertyValue);
+        viewer.setShapeProperty(JmolConstants.SHAPE_ISOSURFACE, propertyName,
+            propertyValue);
     }
   }
 
@@ -3993,8 +4012,8 @@
         break;
       case Token.identifier:
         String id = (String) statement[i].value;
-        if (! degreesSeen)
-            degrees = 3;
+        if (!degreesSeen)
+          degrees = 3;
         if (id.equalsIgnoreCase("redblue")) {
           stereoMode = JmolConstants.STEREO_REDBLUE;
           break;
@@ -4007,7 +4026,7 @@
           stereoMode = JmolConstants.STEREO_REDGREEN;
           break;
         }
-        // fall into
+      // fall into
       default:
         booleanOrNumberExpected();
       }
@@ -4028,7 +4047,6 @@
     evalError("insufficient arguments");
   }
 
-
   void connect() throws ScriptException {
     boolean haveType = false;
     int nAtomSets = 0;
@@ -4038,25 +4056,24 @@
      *             [<=1 bond type] [<=1 operation]
      * 
      */
-    
+
     viewer.setShapeProperty(JmolConstants.SHAPE_STICKS,
-                            "resetConnectParameters", null);
+        "resetConnectParameters", null);
     if (statementLength == 1) {
       viewer.setShapeProperty(JmolConstants.SHAPE_STICKS,
-                              "rasmolCompatibleConnect", null);
+          "rasmolCompatibleConnect", null);
       return;
     }
     for (int i = 1; i < statementLength; ++i) {
       String propertyName = null;
       Object propertyValue = null;
-      switch_tag:
-      switch (statement[i].tok) {
+      switch_tag: switch (statement[i].tok) {
       case Token.on:
       case Token.off:
-        if (statementLength != 2) 
+        if (statementLength != 2)
           badArgumentCount();
         viewer.setShapeProperty(JmolConstants.SHAPE_STICKS,
-                                "rasmolCompatibleConnect", null);
+            "rasmolCompatibleConnect", null);
         return;
       case Token.integer:
       case Token.decimal:
@@ -4078,8 +4095,8 @@
         break;
       case Token.identifier:
       case Token.hbond:
-        String cmd = (String)statement[i].value;
-        for (int j =  JmolConstants.bondOrderNames.length; --j >= 0; ) {
+        String cmd = (String) statement[i].value;
+        for (int j = JmolConstants.bondOrderNames.length; --j >= 0;) {
           if (cmd.equalsIgnoreCase(JmolConstants.bondOrderNames[j])) {
             if (haveType)
               incompatibleArguments();
@@ -4114,15 +4131,13 @@
       default:
         invalidArgument();
       }
-      viewer.setShapeProperty(JmolConstants.SHAPE_STICKS,
-                              propertyName, propertyValue);
+      viewer.setShapeProperty(JmolConstants.SHAPE_STICKS, propertyName,
+          propertyValue);
     }
     viewer.setShapeProperty(JmolConstants.SHAPE_STICKS,
-                            "applyConnectParameters", null);
+        "applyConnectParameters", null);
   }
 
-
-  
   void connect10_0_99() throws ScriptException {
     boolean haveType = false;
     int nAtomSets = 0;
@@ -4132,25 +4147,24 @@
      *             [<=1 bond type] [<=1 operation]
      * 
      */
-    
+
     viewer.setShapeProperty(JmolConstants.SHAPE_STICKS,
-                            "resetConnectParameters", null);
+        "resetConnectParameters", null);
     if (statementLength == 1) {
       viewer.setShapeProperty(JmolConstants.SHAPE_STICKS,
-                              "rasmolCompatibleConnect", null);
+          "rasmolCompatibleConnect", null);
       return;
     }
     for (int i = 1; i < statementLength; ++i) {
       String propertyName = null;
       Object propertyValue = null;
-      switch_tag:
-      switch (statement[i].tok) {
+      switch_tag: switch (statement[i].tok) {
       case Token.on:
       case Token.off:
-        if (statementLength != 2) 
+        if (statementLength != 2)
           badArgumentCount();
         viewer.setShapeProperty(JmolConstants.SHAPE_STICKS,
-                                "rasmolCompatibleConnect", null);
+            "rasmolCompatibleConnect", null);
         return;
       case Token.integer:
       case Token.decimal:
@@ -4168,14 +4182,14 @@
           invalidParameterOrder();
         propertyName = "connectSet";
         propertyValue = expression(statement, i);
-//        i = pcLastExpressionInstruction; // the for loop will increment i
+        //        i = pcLastExpressionInstruction; // the for loop will 
increment i
         i = pcLastExpressionInstruction;
 
         break;
       case Token.identifier:
       case Token.hbond:
-        String cmd = (String)statement[i].value;
-        for (int j =  JmolConstants.bondOrderNames.length; --j >= 0; ) {
+        String cmd = (String) statement[i].value;
+        for (int j = JmolConstants.bondOrderNames.length; --j >= 0;) {
           if (cmd.equalsIgnoreCase(JmolConstants.bondOrderNames[j])) {
             if (haveType)
               incompatibleArguments();
@@ -4210,16 +4224,15 @@
       default:
         invalidArgument();
       }
-      viewer.setShapeProperty(JmolConstants.SHAPE_STICKS,
-                              propertyName, propertyValue);
+      viewer.setShapeProperty(JmolConstants.SHAPE_STICKS, propertyName,
+          propertyValue);
     }
     viewer.setShapeProperty(JmolConstants.SHAPE_STICKS,
-                            "applyConnectParameters", null);
+        "applyConnectParameters", null);
   }
 
   void connectOLD() throws ScriptException {
-    viewer.setShapeProperty(JmolConstants.SHAPE_STICKS,
-        "initConnect", null);
+    viewer.setShapeProperty(JmolConstants.SHAPE_STICKS, "initConnect", null);
     if (statementLength == 1) {
       viewer.rebond();
       return;
@@ -4262,12 +4275,10 @@
         break;
       case Token.identifier:
       case Token.hbond:
-        String cmd = ((String)token.value).toLowerCase();
-        if (cmd.equals("single") ||
-            cmd.equals("double") ||
-            cmd.equals("triple") ||
-            cmd.equals("aromatic") ||
-            cmd.equals("hbond")) {
+        String cmd = ((String) token.value).toLowerCase();
+        if (cmd.equals("single") || cmd.equals("double")
+            || cmd.equals("triple") || cmd.equals("aromatic")
+            || cmd.equals("hbond")) {
           propertyName = "connectBondOrder";
           propertyValue = cmd;
           nNumeric = 2;
@@ -4283,22 +4294,21 @@
         break;
       case Token.delete:
         propertyName = "connectBondOrder";
-        propertyValue = new Short((short)0);
+        propertyValue = new Short((short) 0);
         break;
       default:
         invalidArgument();
       }
-      viewer.setShapeProperty(JmolConstants.SHAPE_STICKS,
-                              propertyName, propertyValue);
+      viewer.setShapeProperty(JmolConstants.SHAPE_STICKS, propertyName,
+          propertyValue);
     }
   }
-  
+
   void getProperty() {
     String retValue = "";
-    String property =  (statementLength < 2 ? "" : (String) 
statement[1].value);
+    String property = (statementLength < 2 ? "" : (String) statement[1].value);
     String param = (statementLength < 3 ? "" : (String) statement[2].value);
-    retValue = (String)viewer.getProperty("readable", property, param);
+    retValue = (String) viewer.getProperty("readable", property, param);
     viewer.scriptEcho(retValue);
   }
 }
-

Modified: branches/bob200603/Jmol/src/org/jmol/viewer/Frame.java
===================================================================
--- branches/bob200603/Jmol/src/org/jmol/viewer/Frame.java      2006-05-20 
14:06:58 UTC (rev 5149)
+++ branches/bob200603/Jmol/src/org/jmol/viewer/Frame.java      2006-05-20 
14:10:42 UTC (rev 5150)
@@ -2696,8 +2696,9 @@
   void convertFractionalCoordinates(int modelIndex, Point3f pt) {
     if (modelIndex < 0)
       modelIndex = 0;
-    if (modelIndex >= cellInfo.length || cellInfo[modelIndex] == null) return;
-System.out.print(pt+"--->");
+    if (modelIndex >= cellInfo.length || cellInfo[modelIndex] == null)
+      return;
+    System.out.print("Frame convertFractional " + pt + "--->");
     cellInfo[modelIndex].transform(pt);
     System.out.println(pt);
   }

Modified: branches/bob200603/Jmol/src/org/jmol/viewer/JmolConstants.java
===================================================================
--- branches/bob200603/Jmol/src/org/jmol/viewer/JmolConstants.java      
2006-05-20 14:06:58 UTC (rev 5149)
+++ branches/bob200603/Jmol/src/org/jmol/viewer/JmolConstants.java      
2006-05-20 14:10:42 UTC (rev 5150)
@@ -42,7 +42,7 @@
   // for now, just update this by hand
   // perhaps use ant filter later ... but mth doesn't like it :-(
   public final static String copyright = "(C) 2006 Jmol Development";
-  public final static String version = "10.x.03(branch bob200603)";
+  public final static String version = "10.x.04(branch bob200603)";
   public final static String cvsDate = "$Date$";
   public final static String date = cvsDate.substring(7, 23);
 

Modified: branches/bob200603/Jmol/src/org/jmol/viewer/ModelManager.java
===================================================================
--- branches/bob200603/Jmol/src/org/jmol/viewer/ModelManager.java       
2006-05-20 14:06:58 UTC (rev 5149)
+++ branches/bob200603/Jmol/src/org/jmol/viewer/ModelManager.java       
2006-05-20 14:10:42 UTC (rev 5150)
@@ -329,6 +329,10 @@
     return (frame == null ? null : frame.getRotationCenter());
   }
 
+  Point3f getRotationCenterDefault() {
+    return (frame == null ? null : frame.getRotationCenterDefault());
+  }
+
   private final Point3f pointT = new Point3f();
   Point3f setCenterBitSet(BitSet bsCenter, boolean doScale) {
     if (frame == null)

Modified: branches/bob200603/Jmol/src/org/jmol/viewer/TransformManager.java
===================================================================
--- branches/bob200603/Jmol/src/org/jmol/viewer/TransformManager.java   
2006-05-20 14:06:58 UTC (rev 5149)
+++ branches/bob200603/Jmol/src/org/jmol/viewer/TransformManager.java   
2006-05-20 14:10:42 UTC (rev 5150)
@@ -55,7 +55,7 @@
   }
 
   final static float twoPI = (float) (2 * Math.PI);
-  int spinX, spinY = 30, spinZ, spinW, spinFps = 30;
+  float spinX, spinY = 30f, spinZ, spinW, spinFps = 30f;
   Point3f fixedRotationCenter = new Point3f(0, 0, 0);
   AxisAngle4f fixedRotationAxis;
   float fixedRotationAngle = 0;
@@ -110,7 +110,7 @@
     translateCenterTo(newCenterScreen.x, newCenterScreen.y);
   }
 
-  float setRotateInternal(Point3f center, Vector3f axis, int degrees) {
+  float setRotateInternal(Point3f center, Vector3f axis, float degrees) {
     isInternal = true;
     checkFixedRotationCenter();
     internalRotationCenter.set(center);
@@ -121,7 +121,7 @@
     return radians;
   }
 
-  float setRotateFixed(Point3f center, Vector3f axis, int degrees) {
+  float setRotateFixed(Point3f center, Vector3f axis, float degrees) {
     spinW = degrees; //turns off old-stype spinX, spinY, spinZ
     //spinX = spinY = spinZ = 0;
     isFixed = true;
@@ -136,6 +136,7 @@
   }
 
   void rotateXYBy(int xDelta, int yDelta) {
+    // from mouse action
     rotateXRadians(yDelta * radiansPerDegree);
     rotateYRadians(xDelta * radiansPerDegree);
   }
@@ -180,6 +181,7 @@
   }
 
   void rotateAxisAngle(Vector3f rotAxis, int degrees) {
+    //not used 
     axisangleT.set(rotAxis, degrees * radiansPerDegree);
     rotateAxisAngle(axisangleT);
   }
@@ -213,16 +215,22 @@
    ****************************************************************/
 
   void rotateAxisAngleAtCenter(Point3f rotCenter, Vector3f rotAxis,
-                               int degrees, boolean isSpin) {
+                               float degrees, float endDegrees, boolean 
isSpin) {
 
     //*THE* Viewer FIXED frame rotation/spinning entry point
 
+    System.out.println("rotateatcenter "+degrees+" "+endDegrees+" "+isSpin);
+    setSpinOn(false);
+
+    if (degrees == 0)
+      return;
+    
     if (rotCenter != null) {
       setRotationPointXY(rotCenter);
     }
     float angle = setRotateFixed(rotCenter, rotAxis, degrees);
     if (isSpin) {
-      setSpinOn(true);
+      setSpinOn(true, endDegrees);
       return;
     }
     rotateAxisAngleRadiansFixed(angle);
@@ -240,11 +248,19 @@
    * INTERNAL ROTATIONS
    ****************************************************************/
 
-  void rotateAboutPointsInternal(Point3f point1, Point3f point2, int degrees,
-                                 boolean isClockwise, boolean isSpin) {
+  void rotateAboutPointsInternal(Point3f point1, Point3f point2, float degrees,
+                                 float endDegrees, boolean isClockwise,
+                                 boolean isSpin) {
 
     // *THE* Viewer INTERNAL frame rotation entry point
 
+    System.out.println("rotateAboutPointsInternal "+degrees+" "+endDegrees+" 
"+isSpin);
+
+    setSpinOn(false);
+
+    if (degrees == 0)
+      return;
+    
     Vector3f axis = new Vector3f(point1);
     axis.sub(point2);
     if (isClockwise)
@@ -252,7 +268,7 @@
     float angle = setRotateInternal(point1, axis, degrees);
 
     if (isSpin) {
-      setSpinOn(true);
+      setSpinOn(true, endDegrees);
       return;
     }
     rotateAxisAngleRadiansInternal(angle);
@@ -266,18 +282,16 @@
     // and then save the angle for generating a new fixed point later
 
     internalRotationAngle = radians;
-    // System.out.println("rotate RadiansInternal " + internalRotationAngle);
-
     vectorT.set(internalRotationAxis.x, internalRotationAxis.y,
         internalRotationAxis.z);
     matrixRotate.transform(vectorT, vectorT2);
     axisangleT.set(vectorT2, radians);
-
+    
     // NOW apply that rotation  
 
     matrixTemp3.set(axisangleT);
     matrixRotate.mul(matrixTemp3, matrixRotate);
-
+    getNewFixedRotationCenter();
   }
 
   void getNewFixedRotationCenter() {
@@ -319,7 +333,6 @@
     // it is the new fixed rotation center!
 
     fixedRotationCenter.set(pointT);
-    // System.out.println("getNew Now: " + fixedRotationCenter);
     viewer.setCenterFromInternalRotation(fixedRotationCenter);
   }
 
@@ -330,6 +343,7 @@
   float yFixedTranslation;
 
   void translateXYBy(int xDelta, int yDelta) {
+    // mouse action only
     xFixedTranslation += xDelta;
     yFixedTranslation += yDelta;
   }
@@ -783,30 +797,63 @@
     return increaseRotationRadius;
   }
   
-  int minimumZ;
+  float minimumZ;
 
   synchronized void finalizeTransformParameters() {
-    //from frame renderer just before all transformPoint() calls
-    if (isInternal) {
-      getNewFixedRotationCenter();
-      isInternal = spinOn; //one pass if not spinning
-    }
     calcTransformMatrix();
     calcSlabAndDepthValues();
     viewer.setSlabAndDepthValues(slabValue, depthValue);
     increaseRotationRadius = false;
-    minimumZ = Integer.MAX_VALUE;
+    minimumZ = Float.MAX_VALUE;
     haveNotifiedNaN = false;
-    haveNotifiedCamera = false;    
-    //System.out.println("\n\nfinalizeTransform");
-    //for testing: transformPoint(fixedRotationCenter);
+    haveNotifiedCamera = false;   
+    setPerspectiveOffset();
+
+    /*System.out.println("\n\nfinalizeTransform");  
+    transformPoint(fixedRotationCenter);//for testing only
+    System.out.println(fixedRotationCenter+" "+point3fScreenTemp+" 
"+point3iScreenTemp);
+    */
   }
 
+  Vector3f perspectiveOffset = new Vector3f(0, 0, 0);
+  void setPerspectiveOffset() {
+    // lock in the perspective so that when you change
+    // centers there is no jump
+    if(!viewer.isWindowCentered()) {
+      matrixTransform.transform(viewer.getRotationCenterDefault(), pointT);
+      matrixTransform.transform(viewer.getRotationCenter(), pointT2);
+      perspectiveOffset.sub(pointT, pointT2);
+    }
+    perspectiveOffset.x = xFixedTranslation; 
+    perspectiveOffset.y = yFixedTranslation;
+    
+    if (!viewer.isCameraAdjustable())
+      perspectiveOffset.z = 0;
+    /*
+     * Note that the effect of this modification is restricted to the 
+     * (undocumented) specialized circumstances when both
+     * 
+     * (a) set windowCentered is false (formerly "set frieda on")
+     * 
+     *  AND
+     *
+     * (b) the center has been changed to something other than the default
+     * rotation center, either using "set picking center" followed by a user
+     * click of an atom, or by a scripted "center (atom expression)".
+     * 
+     * This adjustment has no effect whatsoever on general use.
+     * 
+     * Bob Hanson 4/06
+     *  
+     */
+    //System.out.println("\nsetPerspectiveOffset "+perspectiveOffset);
+  }
+ 
   float getRotationRadiusIncrease() {
     //System.out.println("TransformManager.getRotationRadiusIncrease()");
     //System.out.println("minimumZ=" + minimumZ);
     // add one more pixel just for good luck;
-    int backupDistance = cameraDistance - minimumZ + 1;
+    float backupDistance = cameraDistance - minimumZ + 1f;
     float angstromsIncrease = backupDistance / scalePixelsPerAngstrom;
     //System.out.println("angstromsIncrease=" + angstromsIncrease);
     return angstromsIncrease;
@@ -880,7 +927,11 @@
 
   synchronized Point3i transformPoint(Point3f pointAngstroms) {
     matrixTransform.transform(pointAngstroms, point3fScreenTemp);
-    int z = (int) point3fScreenTemp.z;
+    return adjustedTemporaryScreenPoint(pointAngstroms);
+  }
+  
+  Point3i adjustedTemporaryScreenPoint(Point3f pointAngstroms) {
+    float z = (point3fScreenTemp.z - perspectiveOffset.z);
     if (z < cameraDistance) {
       if (Float.isNaN(point3fScreenTemp.z)) {
         //removed for extending pmesh to points and lines  BH 2/25/06 
@@ -908,7 +959,7 @@
         }
       }
     }
-    point3iScreenTemp.z = z;
+    point3fScreenTemp.z = z;
     if (perspectiveDepth) {
       float perspectiveFactor = cameraDistanceFloat / z;
       point3fScreenTemp.x *= perspectiveFactor;
@@ -917,44 +968,27 @@
 
     //higher resolution here for spin control. 
 
-    float newXPt = point3fScreenTemp.x + xFixedTranslation;
-    float newYPt = point3fScreenTemp.y + yFixedTranslation;
-    if (Float.isNaN(newXPt) && !haveNotifiedNaN) {
+    point3fScreenTemp.x += perspectiveOffset.x;
+    point3fScreenTemp.y += perspectiveOffset.y;
+    if (Float.isNaN(point3fScreenTemp.x) && !haveNotifiedNaN) {
       System.out.println("NaN found in transformPoint ");
       haveNotifiedNaN = true;
     }
 
-    point3iScreenTemp.x = (int) (newXPt);
-    point3iScreenTemp.y = (int) (newYPt);
-  // system.out.println(pointAngstroms + " " + point3iScreenTemp);
+    //System.out.println(pointAngstroms + " " + point3fScreenTemp);
+    point3iScreenTemp.x = (int) point3fScreenTemp.x;
+    point3iScreenTemp.y = (int) point3fScreenTemp.y;
+    point3iScreenTemp.z = (int) point3fScreenTemp.z;
     return point3iScreenTemp;
   }
 
   void transformPoint(Point3f pointAngstroms, Point3f screen) {
-    matrixTransform.transform(pointAngstroms, screen);
-
-    float z = screen.z;
-    if (z < cameraDistance) {
-      if (!spinOn)
-        System.out.println("need to back up the camera");
-      increaseRotationRadius = true;
-      if (z < minimumZ)
-        minimumZ = (int) z;
-      if (z <= 0) {
-        if (!spinOn)
-          System.out.println("WARNING! DANGER! z <= 0! transformPoint()");
-        z = 1;
-      }
-    }
-    screen.z = z;
-    if (perspectiveDepth) {
-      float perspectiveFactor = cameraDistanceFloat / z;
-      screen.x = screen.x * perspectiveFactor + xFixedTranslation;
-      screen.y = screen.y * perspectiveFactor + yFixedTranslation;
-    } else {
-      screen.x += xFixedTranslation;
-      screen.y += yFixedTranslation;
-    }
+    
+    //used solely by RocketsRenderer
+    
+    matrixTransform.transform(pointAngstroms, point3fScreenTemp);
+    adjustedTemporaryScreenPoint(pointAngstroms);
+    screen.set(point3fScreenTemp);
   }
 
   Point3i transformPoint(Point3f pointAngstroms, Vector3f vibrationVector) {
@@ -965,29 +999,7 @@
           pointAngstroms);
       matrixTransform.transform(point3fVibrationTemp, point3fScreenTemp);
     }
-
-    int z = (int) point3fScreenTemp.z;
-    if (z < cameraDistance) {
-      if (! spinOn)
-        System.out.println("need to back up the camera");
-      increaseRotationRadius = true;
-      if (z < minimumZ)
-        minimumZ = z;
-      if (z <= 0) {
-        if (! spinOn)
-          System.out.println("WARNING! DANGER! z <= 0! transformPoint()");
-        z = 1;
-      }
-    }
-    point3iScreenTemp.z = z;
-    if (perspectiveDepth) {
-      float perspectiveFactor = cameraDistanceFloat / z;
-      point3fScreenTemp.x *= perspectiveFactor;
-      point3fScreenTemp.y *= perspectiveFactor;
-    }
-    point3iScreenTemp.x = (int) (point3fScreenTemp.x + xFixedTranslation);
-    point3iScreenTemp.y = (int) (point3fScreenTemp.y + yFixedTranslation);
-    return point3iScreenTemp;
+    return adjustedTemporaryScreenPoint(pointAngstroms);
   }
 
   void transformPoint(Point3f pointAngstroms, Vector3f vibrationVector,
@@ -1329,21 +1341,21 @@
    * Spin support
    ****************************************************************/
 
-  void setSpinX(int degrees) {
+  void setSpinX(float degrees) {
     spinX = degrees;
     spinW = 0;
     if (isInternal)
       setSpinOn(false);
   }
 
-  void setSpinY(int degrees) {
+  void setSpinY(float degrees) {
     spinY = degrees;
     spinW = 0;
     if (isInternal)
       setSpinOn(false);
   }
 
-  void setSpinZ(int degrees) {
+  void setSpinZ(float degrees) {
     spinZ = degrees;
     spinW = 0;
     if (isInternal)
@@ -1366,11 +1378,15 @@
   SpinThread spinThread;
 
   void setSpinOn(boolean spinOn) {
+    setSpinOn(spinOn, Float.MAX_VALUE);
+  }
+
+  void setSpinOn(boolean spinOn, float endDegrees) {
     this.spinOn = spinOn;
     //System.out.println("setSpinOn " + spinOn);
     if (spinOn) {
       if (spinThread == null) {
-        spinThread = new SpinThread();
+        spinThread = new SpinThread(endDegrees);
         spinThread.start();
       }
     } else {
@@ -1384,31 +1400,43 @@
   }
 
   class SpinThread extends Thread implements Runnable {
+    float endDegrees;
+    float nDegrees = 0;
+    SpinThread (float endDegrees) {
+      this.endDegrees = Math.abs(endDegrees);
+    }
     public void run() {
-      int myFps = spinFps;
+      float myFps = spinFps;
       int i = 0;
       long timeBegin = System.currentTimeMillis();
-      //System.out.println("spin thread run started");
       while (!isInterrupted()) {
         if (myFps != spinFps) {
           myFps = spinFps;
           i = 0;
           timeBegin = System.currentTimeMillis();
         }
+        if (myFps == 0 || !spinOn) {
+          setSpinOn(false);
+          return;
+        }
         boolean refreshNeeded = (isInternal && internalRotationAxis.angle != 0
             || isFixed && fixedRotationAxis != null && fixedRotationAxis.angle 
!= 0 
             || !isFixed && !isInternal && (spinX + spinY + spinZ != 0));
         ++i;
-        int targetTime = i * 1000 / myFps;
+        int targetTime = (int) (i * 1000 / myFps);
         int currentTime = (int) (System.currentTimeMillis() - timeBegin);
         int sleepTime = targetTime - currentTime;
         if (sleepTime > 0) {
           if (refreshNeeded && spinOn) {
-
-            if (isInternal) {
-              rotateAxisAngleRadiansInternal(internalRotationAxis.angle / 
myFps);
-            } else if (isFixed) {
-              rotateAxisAngleRadiansFixed(fixedRotationAxis.angle / myFps);
+            float angle = 0;
+            if (isInternal || isFixed) {
+              angle = (isInternal ? internalRotationAxis : 
fixedRotationAxis).angle/ myFps;
+              if (isInternal) {
+                rotateAxisAngleRadiansInternal(angle);
+              } else {
+                rotateAxisAngleRadiansFixed(angle);
+              }
+              nDegrees += Math.abs(angle / twoPI * 360f);
             } else { // old way: Rx * Ry * Rz
               if (spinX != 0) {
                 rotateXRadians(spinX * radiansPerDegree / myFps);
@@ -1420,8 +1448,9 @@
                 rotateZRadians(spinZ * radiansPerDegree / myFps);
               }
             }
-
             viewer.refresh(1, "TransformationManager:SpinThread:run()");
+            if (nDegrees >= endDegrees - 0.00001)
+              setSpinOn(false);
           }
           try {
             Thread.sleep(sleepTime);

Modified: branches/bob200603/Jmol/src/org/jmol/viewer/Viewer.java
===================================================================
--- branches/bob200603/Jmol/src/org/jmol/viewer/Viewer.java     2006-05-20 
14:06:58 UTC (rev 5149)
+++ branches/bob200603/Jmol/src/org/jmol/viewer/Viewer.java     2006-05-20 
14:10:42 UTC (rev 5150)
@@ -646,7 +646,7 @@
     transformManager.setSpinX(value);
   }
 
-  int getSpinX() {
+  float getSpinX() {
     return transformManager.spinX;
   }
 
@@ -654,7 +654,7 @@
     transformManager.setSpinY(value);
   }
 
-  int getSpinY() {
+  float getSpinY() {
     return transformManager.spinY;
   }
 
@@ -662,7 +662,7 @@
     transformManager.setSpinZ(value);
   }
 
-  int getSpinZ() {
+  float getSpinZ() {
     return transformManager.spinZ;
   }
 
@@ -670,7 +670,7 @@
     transformManager.setSpinFps(value);
   }
 
-  int getSpinFps() {
+  float getSpinFps() {
     return transformManager.spinFps;
   }
 
@@ -1281,6 +1281,10 @@
     return modelManager.getRotationCenter();
   }
 
+  Point3f getRotationCenterDefault() {
+    return modelManager.getRotationCenterDefault();
+  }
+
   Point3f getBoundBoxCenter() {
     return modelManager.getBoundBoxCenter();
   }
@@ -1460,6 +1464,16 @@
     windowCenteredFlag = TF;
   }
 
+  boolean adjustCameraFlag = true;
+
+  boolean isCameraAdjustable() {
+    return adjustCameraFlag;
+  }
+
+  void setAdjustCamera(boolean TF) {
+    adjustCameraFlag = TF;
+  }
+
   boolean rangeSelected = false;
 
   boolean isRangeSelected() {
@@ -2480,6 +2494,10 @@
       setWindowCentered(value);
       return;
     }
+    if (key.equalsIgnoreCase("adjustCamera")) {
+      setAdjustCamera(value);
+      return;
+    }
     if (key.equalsIgnoreCase("rangeSelected")) {
       setRangeSelected(value);
       return;
@@ -3072,20 +3090,20 @@
    * ********************************************************/
 
   void rotateAxisAngleAtCenter(Point3f rotCenter, Vector3f rotAxis,
-                               int degrees, boolean isSpin) {
+                               float degrees, float endDegrees, boolean 
isSpin) {
     // Eval: rotate FIXED
     if (rotCenter != null)
       moveRotationCenter(rotCenter);
 
     transformManager.rotateAxisAngleAtCenter(rotCenter, rotAxis, degrees,
-        isSpin);
+        endDegrees, isSpin);
   }
 
-  void rotateAboutPointsInternal(Point3f point1, Point3f point2, int nDegrees,
-                                 boolean isSpin) {
+  void rotateAboutPointsInternal(Point3f point1, Point3f point2, float 
nDegrees,
+                                 float endDegrees, boolean isSpin) {
     // Eval: rotate INTERNAL
-    transformManager.rotateAboutPointsInternal(point1, point2, nDegrees, false,
-        isSpin);
+    transformManager.rotateAboutPointsInternal(point1, point2, nDegrees,
+        endDegrees, false, isSpin);
   }
 
   int pickingSpinRate = 10;
@@ -3110,7 +3128,7 @@
       return;
     }
     transformManager.rotateAboutPointsInternal(pt1, pt2, pickingSpinRate,
-        isClockwise, true);
+        Float.MAX_VALUE, isClockwise, true);
   }
 
   Point3f getDrawObjectCenter(String axisID) {


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



-------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Jmol-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jmol-commits

Reply via email to