Skip to content

Commit 3b67d62

Browse files
committed
Refactored RotationAxis & added documentation
git-svn-id: http://code.open-bio.org/repos/biojava/biojava-live/trunk@10068 7c6358e6-4a41-0410-a743-a5b2a554c398
1 parent d002e8f commit 3b67d62

2 files changed

Lines changed: 165 additions & 122 deletions

File tree

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package demo;
2+
3+
import java.io.IOException;
4+
5+
import org.biojava.bio.structure.Atom;
6+
import org.biojava.bio.structure.StructureException;
7+
import org.biojava.bio.structure.align.StructureAlignment;
8+
import org.biojava.bio.structure.align.StructureAlignmentFactory;
9+
import org.biojava.bio.structure.align.ce.CeMain;
10+
import org.biojava.bio.structure.align.gui.jmol.StructureAlignmentJmol;
11+
import org.biojava.bio.structure.align.model.AFPChain;
12+
import org.biojava.bio.structure.align.util.AtomCache;
13+
import org.biojava.bio.structure.align.util.RotationAxis;
14+
import org.biojava.bio.structure.jama.Matrix;
15+
16+
/**
17+
* A demo for how to use {@link RotationAxis} to display the rotation for an
18+
* alignment. This is particularly useful for symmetric alignments, eg between
19+
* several chains of a symmetric or pseudo-symmetric complex.
20+
*
21+
* @author Spencer Bliven
22+
*
23+
*/
24+
public final class DemoRotationAxis {
25+
26+
public static void main(String[] args) {
27+
28+
// Compare two chains of a dimer to force CE to give a symmetric alignment.
29+
String name1 = "1AVD.A";
30+
String name2 = "1AVD.B";
31+
String display = "1AVD";
32+
33+
// name1 = "4HHB.A:,B:";
34+
// name2 = "4HHB.C:,D:";
35+
// display = "4HHB";
36+
37+
AtomCache cache = new AtomCache();
38+
try {
39+
// Get the structures
40+
Atom[] ca1 = cache.getAtoms(name1);
41+
Atom[] ca2 = cache.getAtoms(name2);
42+
Atom[] caD = cache.getAtoms(display);
43+
44+
// Perform the alignment
45+
StructureAlignment ce = StructureAlignmentFactory.getAlgorithm(CeMain.algorithmName);
46+
AFPChain afpChain = ce.align(ca1, ca2);
47+
48+
// Calculate the axis of rotation
49+
Matrix mat = afpChain.getBlockRotationMatrix()[0];
50+
Atom shift = afpChain.getBlockShiftVector()[0];
51+
RotationAxis axis = new RotationAxis(mat,shift);
52+
53+
// Print the angle of rotation
54+
double theta = Math.toDegrees(axis.getAngle());
55+
System.out.format("Angle: %f degrees%n",theta);
56+
57+
// Display the alignment with Jmol
58+
StructureAlignmentJmol jmolPanel = new StructureAlignmentJmol();
59+
jmolPanel.setAtoms(caD);
60+
61+
// Set some standard protein display properties
62+
jmolPanel.evalString("select * ; color chain;");
63+
jmolPanel.evalString("select nucleic; cartoon on;");
64+
jmolPanel.evalString("select *; spacefill off; wireframe off; cartoon on; ");
65+
66+
// draw axis
67+
String jmolString = axis.getJmolScript(caD);
68+
jmolPanel.evalString(jmolString);
69+
70+
71+
72+
/*
73+
// draw intermediate vectors for debugging
74+
double width = .5;
75+
Atom s = axis.getRotationPos();
76+
Atom u = axis.getRotationAxis();
77+
jmolPanel.evalString(String.format("draw ID s VECTOR {0,0,0} {%f,%f,%f} WIDTH %f COLOR orange \">s\";",
78+
s.getX(),s.getY(),s.getZ(), width ));
79+
80+
Atom perp = axis.getOtherTranslation();
81+
Atom screw = axis.getScrewTranslation();
82+
83+
double uScale = 10;
84+
jmolPanel.evalString(String.format("draw ID u VECTOR {0,0,0} {%f,%f,%f} WIDTH %f COLOR orange \">u\";",
85+
uScale*u.getX(),uScale*u.getY(),uScale*u.getZ(), width ));
86+
87+
jmolPanel.evalString(String.format("draw ID perp VECTOR {0,0,0} {%f,%f,%f} WIDTH %f COLOR yellow \">tPerp\";",
88+
perp.getX(),perp.getY(),perp.getZ(), width));
89+
jmolPanel.evalString(String.format("draw ID screw VECTOR {0,0,0} {%f,%f,%f} WIDTH %f COLOR yellow \">screw\";",
90+
screw.getX(),screw.getY(),screw.getZ(), width));
91+
92+
jmolPanel.evalString(String.format("draw ID t VECTOR {0,0,0} {%f,%f,%f} WIDTH %f COLOR yellow \">t\";",
93+
shift.getX(),shift.getY(),shift.getZ(), width));
94+
95+
// draw coordinate axes
96+
jmolPanel.evalString("draw ID x VECTOR {0,0,0} {5,0,0} WIDTH 0.5 COLOR red \">x\";");
97+
jmolPanel.evalString("draw ID y VECTOR {0,0,0} {0,5,0} WIDTH 0.5 COLOR green \">y\";");
98+
jmolPanel.evalString("draw ID z VECTOR {0,0,0} {0,0,5} WIDTH 0.5 COLOR blue \">z\";");
99+
*/
100+
101+
} catch (IOException e) {
102+
e.printStackTrace();
103+
} catch (StructureException e) {
104+
e.printStackTrace();
105+
}
106+
}
107+
}

biojava3-structure-gui/src/main/java/org/biojava/bio/structure/gui/RotationAxis.java renamed to biojava3-structure/src/main/java/org/biojava/bio/structure/align/util/RotationAxis.java

Lines changed: 58 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,38 @@
1-
package org.biojava.bio.structure.gui;
1+
package org.biojava.bio.structure.align.util;
22

3-
import java.io.IOException;
43
import java.io.StringWriter;
54

65
import org.biojava.bio.structure.Atom;
76
import org.biojava.bio.structure.AtomImpl;
87
import 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;
148
import org.biojava.bio.structure.align.model.AFPChain;
15-
import org.biojava.bio.structure.align.util.AtomCache;
169
import 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
*/
2332
public 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

Comments
 (0)