1- package org .biojava .bio .structure .gui ;
1+ package org .biojava .bio .structure .align . util ;
22
3- import java .io .IOException ;
43import java .io .StringWriter ;
54
65import org .biojava .bio .structure .Atom ;
76import org .biojava .bio .structure .AtomImpl ;
87import org .biojava .bio .structure .Calc ;
9- import org .biojava .bio .structure .StructureException ;
10- import org .biojava .bio .structure .align .StructureAlignment ;
11- import org .biojava .bio .structure .align .StructureAlignmentFactory ;
12- import org .biojava .bio .structure .align .ce .CeMain ;
13- import org .biojava .bio .structure .align .gui .jmol .StructureAlignmentJmol ;
148import org .biojava .bio .structure .align .model .AFPChain ;
15- import org .biojava .bio .structure .align .util .AtomCache ;
169import org .biojava .bio .structure .jama .Matrix ;
1710
1811/**
1912 * Calculates the rotation axis for an alignment
13+ *
14+ * <p>A superposition of two structures is generally represented as a rotation
15+ * matrix plus a translation vector. However, it can also be represented as an
16+ * axis of rotation plus some translation.
17+ *
18+ * <p>This class calculates the rotation axis and stores it as four properties:
19+ * <ul><li>A unit vector parallel to the rotation axis ({@link #getRotationAxis()})
20+ * <li>The angle of rotation ({@link #getAngle()})
21+ * <li>A point on the rotation axis ({@link #getRotationPos()})
22+ * <li>Some translation parallel to the axis ({@link #getScrewTranslation()})
23+ * </ul>
24+ *
25+ * <p>The axis of rotation is poorly defined and numerically unstable for small
26+ * angles. Therefor it's direction is left as null for angles less than
27+ * {@link #MIN_ANGLE}.
28+ *
2029 * @author Spencer Bliven
2130 *
2231 */
2332public final class RotationAxis {
33+ /**
34+ * Minimum angle to calculate rotation axes. 5 degrees.
35+ */
2436 static final double MIN_ANGLE = Math .toRadians (5. );
2537
2638 private double theta ;
@@ -31,9 +43,9 @@ public final class RotationAxis {
3143
3244 /**
3345 * The rotation angle
34- * @return theta
46+ * @return the angle, in radians
3547 */
36- public double getTheta () {
48+ public double getAngle () {
3749 return theta ;
3850 }
3951
@@ -64,16 +76,20 @@ public Atom getScrewTranslation() {
6476 }
6577
6678 /**
67- * Get the component of translation perpendicular to the axis of rotation
79+ * Get the component of translation perpendicular to the axis of rotation.
80+ * This isn't particularly meaningful, but is calculated internally and
81+ * was useful for debugging.
6882 * @return
6983 */
84+ @ Deprecated
7085 public Atom getOtherTranslation () {
7186 return otherTranslation ;
7287 }
7388
7489 /**
90+ * Calculate the rotation axis for the first block of an AFPChain
7591 * @param afpChain
76- * @throws NullPointerException of afpChain does not contain a valid rotation matrix and shift vector
92+ * @throws NullPointerException if afpChain does not contain a valid rotation matrix and shift vector
7793 */
7894 public RotationAxis (AFPChain afpChain ) {
7995 this (afpChain .getBlockRotationMatrix ()[0 ],afpChain .getBlockShiftVector ()[0 ]);
@@ -101,6 +117,13 @@ public RotationAxis(Matrix rotation, Atom translation) {
101117 }
102118 }
103119
120+ /**
121+ * Calculate the rotation axis for the normal case, where there is a
122+ * significant rotation angle
123+ * @param rotation
124+ * @param translation
125+ * @param c
126+ */
104127 private void calculateRotationalAxis (Matrix rotation , Atom translation ,
105128 double c ) {
106129 // Calculate magnitude of rotationAxis components, but not signs
@@ -171,6 +194,11 @@ private void calculateRotationalAxis(Matrix rotation, Atom translation,
171194 rotationPos = Calc .scaleAdd (.5 ,otherTranslation , hypot );
172195 }
173196
197+ /**
198+ * Handle cases with small angles of rotation
199+ * @param rotation
200+ * @param translation
201+ */
174202 private void calculateTranslationalAxis (Matrix rotation , Atom translation ) {
175203 // set axis parallel to translation
176204 rotationAxis = Calc .scale (translation , 1. /Calc .amount (translation ));
@@ -183,6 +211,20 @@ private void calculateTranslationalAxis(Matrix rotation, Atom translation) {
183211 otherTranslation .setCoords (new double [] {0 ,0 ,0 });
184212 }
185213
214+ /**
215+ * Returns a Jmol script which will display the axis of rotation. This
216+ * consists of a cyan arrow along the axis, plus an arc showing the angle
217+ * of rotation.
218+ *
219+ * <p>As the rotation angle gets smaller, the axis of rotation becomes poorly
220+ * defined and would need to get farther and farther away from the protein.
221+ * This is not particularly useful, so we arbitrarily draw it parallel to
222+ * the translation and omit the arc.
223+ * @param atoms Some atoms from the protein, used for determining the bounds
224+ * of the axis.
225+ * @return The Jmol script, suitable for calls to
226+ * {@link org.biojava.bio.structure.align.gui.jmol.StructureAlignmentJmol#evalString() jmol.evalString()}
227+ */
186228 public String getJmolScript (Atom [] atoms ){
187229 final double width =.5 ;// width of JMol object
188230
@@ -205,20 +247,12 @@ public String getJmolScript(Atom[] atoms){
205247 Atom axialPt ;
206248 if (rotationPos == null ) {
207249 Atom center = Calc .centerOfMass (atoms );
208- // jmolPanel.evalString(String.format("draw ID center ARROW {0,0,0} {%f,%f,%f} WIDTH %f COLOR orange \">center\";",
209- // center.getX(),center.getY(),center.getZ(), width ));
210-
211250
212251 // Project center onto the axis
213252 Atom centerOnAxis = Calc .scale (rotationAxis , Calc .skalarProduct (center , rotationAxis ));
214- // jmolPanel.evalString(String.format("draw ID centerOnAxis VECTOR {%f,%f,%f} {%f,%f,%f} WIDTH %f COLOR red \">onU\";",
215- // center.getX(),center.getY(),center.getZ(),
216- // centerOnAxis.getX(),centerOnAxis.getY(),centerOnAxis.getZ(), width ));
217253
218254 // Remainder is projection of origin onto axis
219255 axialPt = Calc .subtract (center , centerOnAxis );
220- // jmolPanel.evalString(String.format("draw ID axialPt ARROW {0,0,0} {%f,%f,%f} WIDTH %f COLOR yellow \">axialPt\";",
221- // axialPt.getX(),axialPt.getY(),axialPt.getZ(), width ));
222256
223257 } else {
224258 axialPt = rotationPos ;
@@ -231,6 +265,9 @@ public String getJmolScript(Atom[] atoms){
231265
232266
233267 StringWriter result = new StringWriter ();
268+ // set arrow heads to a reasonable length
269+ result .append ("set defaultDrawArrowScale 2.0;" );
270+
234271 // draw axis of rotation
235272 result .append (
236273 String .format ("draw ID rot ARROW {%f,%f,%f} {%f,%f,%f} WIDTH %f COLOR cyan ;" ,
@@ -239,113 +276,12 @@ public String getJmolScript(Atom[] atoms){
239276
240277 if (rotationPos != null ) {
241278 result .append (System .getProperty ("line.separator" ));
242- result .append (String .format ("draw ID rotArc ARROW ARC {%f,%f,%f} {%f,%f,%f} {0,0,0} {0,%f,1} SCALE 500 DIAMETER %f COLOR cyan;" ,
279+ result .append (String .format ("draw ID rotArc ARC {%f,%f,%f} {%f,%f,%f} {0,0,0} {0,%f,1} SCALE 500 DIAMETER %f COLOR cyan;" ,
243280 axisMin .getX (),axisMin .getY (),axisMin .getZ (),
244281 axisMax .getX (),axisMax .getY (),axisMax .getZ (),
245282 Math .toDegrees (theta ), width ));
246283 }
247284
248285 return result .toString ();
249286 }
250-
251- public void displayRotationAxis (StructureAlignmentJmol jmolPanel , Atom [] atoms ) {
252-
253- // Atom axisMean = (Atom) axialPt.clone();
254- // Calc.scaleAdd(mean,rotationAxis, axisMean);
255-
256- // draw coordinate axes
257- // jmolPanel.evalString("draw ID x VECTOR {0,0,0} {5,0,0} WIDTH 0.5 COLOR red \">x\";");
258- // jmolPanel.evalString("draw ID y VECTOR {0,0,0} {0,5,0} WIDTH 0.5 COLOR green \">y\";");
259- // jmolPanel.evalString("draw ID z VECTOR {0,0,0} {0,0,5} WIDTH 0.5 COLOR blue \">z\";");
260-
261-
262- String jmolString = getJmolScript (atoms );
263- jmolPanel .evalString (jmolString );
264-
265-
266-
267-
268- // double uScale = 10;
269- // jmolPanel.evalString(String.format("draw ID u VECTOR {0,0,0} {%f,%f,%f} WIDTH %f COLOR orange \">u\";",
270- // uScale*rotationAxis.getX(),uScale*rotationAxis.getY(),uScale*rotationAxis.getZ(), width ));
271-
272- }
273-
274- public static void main (String [] args ) {
275-
276- // Compare two chains of a dimer to force CE to give a symmetric alignment.
277- String name1 = "1AVD.A" ;
278- String name2 = "1AVD.B" ;
279- String display = "1AVD" ;
280-
281- // name1 = "4HHB.A:,B:";
282- // name2 = "4HHB.C:,D:";
283- // display = "4HHB";
284-
285- AtomCache cache = new AtomCache ();
286- try {
287- Atom [] ca1 = cache .getAtoms (name1 );
288- Atom [] ca2 = cache .getAtoms (name2 );
289- Atom [] caD = cache .getAtoms (display );
290-
291- StructureAlignment ce = StructureAlignmentFactory .getAlgorithm (CeMain .algorithmName );
292-
293- AFPChain afpChain = ce .align (ca1 , ca2 );
294- Matrix mat = afpChain .getBlockRotationMatrix ()[0 ];
295- Atom shift = afpChain .getBlockShiftVector ()[0 ];
296-
297- System .out .println ("Shift:" );
298- System .out .println (shift );
299- System .out .println ("Matrix:" );
300- System .out .println (mat );
301-
302- RotationAxis axis = new RotationAxis (mat ,shift );
303-
304- double theta = Math .toDegrees (axis .getTheta ());
305- System .out .format ("Angle: %f degrees%n" ,theta );
306-
307- //StructureAlignmentJmol jmolPanel = StructureAlignmentDisplay.display(afpChain, caD, caD);
308- StructureAlignmentJmol jmolPanel = new StructureAlignmentJmol ();
309- jmolPanel .setAtoms (caD );
310-
311- jmolPanel .evalString ("select * ; color chain;" );
312- jmolPanel .evalString ("select nucleic; cartoon on;" );
313- jmolPanel .evalString ("select *; spacefill off; wireframe off; cartoon on; " );
314-
315- // draw coordinate axes
316- jmolPanel .evalString ("draw ID x VECTOR {0,0,0} {5,0,0} WIDTH 0.5 COLOR red \" >x\" ;" );
317- jmolPanel .evalString ("draw ID y VECTOR {0,0,0} {0,5,0} WIDTH 0.5 COLOR green \" >y\" ;" );
318- jmolPanel .evalString ("draw ID z VECTOR {0,0,0} {0,0,5} WIDTH 0.5 COLOR blue \" >z\" ;" );
319-
320- // draw axis
321- axis .displayRotationAxis (jmolPanel , caD );
322-
323- /*
324- // draw intermediate vectors for debugging
325- jmolPanel.evalString(String.format("draw ID s VECTOR {0,0,0} {%f,%f,%f} WIDTH %f COLOR orange \">s\";",
326- s.getX(),s.getY(),s.getZ(), width ));
327-
328- Atom perp = axis.getOtherTranslation();
329- Atom screw = axis.getScrewTranslation();
330-
331- double uScale = 10;
332- jmolPanel.evalString(String.format("draw ID u VECTOR {0,0,0} {%f,%f,%f} WIDTH %f COLOR orange \">u\";",
333- uScale*u.getX(),uScale*u.getY(),uScale*u.getZ(), width ));
334-
335- jmolPanel.evalString(String.format("draw ID perp VECTOR {0,0,0} {%f,%f,%f} WIDTH %f COLOR yellow \">tPerp\";",
336- perp.getX(),perp.getY(),perp.getZ(), width));
337- jmolPanel.evalString(String.format("draw ID screw VECTOR {0,0,0} {%f,%f,%f} WIDTH %f COLOR yellow \">screw\";",
338- screw.getX(),screw.getY(),screw.getZ(), width));
339-
340- jmolPanel.evalString(String.format("draw ID t VECTOR {0,0,0} {%f,%f,%f} WIDTH %f COLOR yellow \">t\";",
341- shift.getX(),shift.getY(),shift.getZ(), width));
342- */
343- } catch (IOException e ) {
344- // TODO Auto-generated catch block
345- e .printStackTrace ();
346- } catch (StructureException e ) {
347- // TODO Auto-generated catch block
348- e .printStackTrace ();
349- }
350- }
351287}
0 commit comments