package org.biojava.nbio.structure.symmetry.internal;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.List;
import javax.vecmath.AxisAngle4d;
import javax.vecmath.Matrix4d;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import org.biojava.nbio.structure.symmetry.internal.CESymmParameters.SymmetryType;
import org.biojava.nbio.structure.symmetry.internal.SymmetryAxes.Axis;
import org.junit.Test;
public class TestSymmetryAxes {
@Test
public void testClosedCase() {
// D4 case
SymmetryAxes axes = new SymmetryAxes();
// Level 1 is C4 along Z
Matrix4d r90 = new Matrix4d();
r90.set(new AxisAngle4d(0, 0, 1, -Math.PI/2));
axes.addAxis(r90, 4, SymmetryType.CLOSED);
// Level 2 is C2 along X
Matrix4d r180 = new Matrix4d();
r180.set(new AxisAngle4d(1, 0, 0, Math.PI));
axes.addAxis(r180, 2, SymmetryType.CLOSED);
assertEquals(2,axes.getElementaryAxes().size());
Matrix4d expectedEven = new Matrix4d();
expectedEven.setIdentity();
Matrix4d expectedOdd = new Matrix4d(r180);
assertEquals(expectedEven, axes.getRepeatTransform(0));
assertEquals(expectedOdd, axes.getRepeatTransform(1));
expectedEven.mul(r90);
expectedOdd.mul(r180,expectedEven);
assertEquals(expectedEven, axes.getRepeatTransform(2));
assertEquals(expectedOdd, axes.getRepeatTransform(3));
expectedEven.mul(r90);
expectedOdd.mul(r180,expectedEven);
assertEquals(expectedEven, axes.getRepeatTransform(4));
assertEquals(expectedOdd, axes.getRepeatTransform(5));
expectedEven.mul(r90);
expectedOdd.mul(r180,expectedEven);
assertEquals(expectedEven, axes.getRepeatTransform(6));
assertEquals(expectedOdd, axes.getRepeatTransform(7));
// Test Cauchy Form
List<List<Integer>> relation = Arrays.asList(
Arrays.asList(0,1,2,3,4,5,6,7),
Arrays.asList(2,3,4,5,6,7,0,1)
);
assertEquals(relation,axes.getRepeatRelation(0));
relation = Arrays.asList(
Arrays.asList(0,1),
Arrays.asList(1,0)
);
assertEquals(relation,axes.getRepeatRelation(1));
relation = Arrays.asList(
Arrays.asList(2,3),
Arrays.asList(3,2)
);
assertEquals(relation,axes.getRepeatRelation(1,2));
try {
axes.getRepeatRelation(2);
fail("Invalid level");
} catch(IndexOutOfBoundsException e) {}
try {
axes.getRepeatRelation(1,1);
fail("Invalid firstRepeat");
} catch(IllegalArgumentException e) {}
// Test Cyclic Form
relation = Arrays.asList(
Arrays.asList(0,2,4,6),
Arrays.asList(1,3,5,7)
);
assertEquals(relation,axes.getRepeatsCyclicForm(0));
relation = Arrays.asList(
Arrays.asList(0,1)
);
assertEquals(relation,axes.getRepeatsCyclicForm(1));
relation = Arrays.asList(
Arrays.asList(2,3)
);
assertEquals(relation,axes.getRepeatsCyclicForm(1,2));
try {
axes.getRepeatsCyclicForm(2);
fail("Invalid level");
} catch(IndexOutOfBoundsException e) {}
try {
axes.getRepeatsCyclicForm(1,1);
fail("Invalid firstRepeat");
} catch(IllegalArgumentException e) {}
// Expected location of each repeat
Point3d[] repeats = new Point3d[] {
new Point3d(1,1,1),
new Point3d(1,-1,-1),
new Point3d(-1,1,1),
new Point3d(1,1,-1),
new Point3d(-1,-1,1),
new Point3d(-1,1,-1),
new Point3d(1,-1,1),
new Point3d(-1,-1,-1)
};
// Inverse of (1,1,1) should give above points
for(int i=0;i<8;i++) {
Matrix4d m = axes.getRepeatTransform(i);
m.invert();
Point3d x = new Point3d(repeats[0]);
m.transform(x);
assertTrue("Transformation "+i+"^-1 of "+repeats[0]+ "="+x+" not "+repeats[i],x.epsilonEquals(repeats[i], 1e-5));
}
// Forward should map the above points onto the first one
for(int i=0;i<8;i++) {
Matrix4d m = axes.getRepeatTransform(i);
Point3d x = new Point3d(repeats[i]);
m.transform(x);
assertTrue("Transformation "+i+" of "+repeats[i]+ "="+x+" not 1,1,1",x.epsilonEquals(repeats[0], 1e-5));
}
Point3d x;
List<Axis> symmetryAxes = axes.getSymmetryAxes();
assertEquals(5,symmetryAxes.size());
int axisNum = 0;
// Repeat 2 -> 0 (90 deg around z)
x = new Point3d(repeats[2]);
symmetryAxes.get(axisNum).getOperator().transform(x);
assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[2]),round(x),round(repeats[0])),x.epsilonEquals(repeats[0], 1e-5));
assertEquals(0,symmetryAxes.get(axisNum).getFirstRepeat());
axisNum++;
// Repeat 1 -> 0 (180 deg around x)
x = new Point3d(repeats[1]);
symmetryAxes.get(axisNum).getOperator().transform(x);
assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[1]),round(x),round(repeats[0])),x.epsilonEquals(repeats[0], 1e-5));
assertEquals(0,symmetryAxes.get(axisNum).getFirstRepeat());
axisNum++;
// Repeat 3 -> 2 (180 deg around y)
x = new Point3d(repeats[3]);
symmetryAxes.get(axisNum).getOperator().transform(x);
assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[3]),round(x),round(repeats[2])),x.epsilonEquals(repeats[2], 1e-5));
assertEquals(2,symmetryAxes.get(axisNum).getFirstRepeat());
axisNum++;
// Repeat 5 -> 4 (180 deg around x)
x = new Point3d(repeats[5]);
symmetryAxes.get(axisNum).getOperator().transform(x);
assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[5]),round(x),round(repeats[4])),x.epsilonEquals(repeats[4], 1e-5));
assertEquals(4,symmetryAxes.get(axisNum).getFirstRepeat());
axisNum++;
// Repeat 7 -> 6 (180 deg around y)
x = new Point3d(repeats[7]);
symmetryAxes.get(axisNum).getOperator().transform(x);
assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[7]),round(x),round(repeats[6])),x.epsilonEquals(repeats[6], 1e-5));
assertEquals(6,symmetryAxes.get(axisNum).getFirstRepeat());
axisNum++;
}
private static Point3d round(Point3d p) {
return new Point3d(Math.round(p.x*100)/100.,Math.round(p.y*100)/100.,Math.round(p.z*100)/100.);
}
@Test
public void testOpenCase() {
// D4 case
SymmetryAxes axes = new SymmetryAxes();
// Level 1 is R4 along X
Matrix4d t10 = new Matrix4d();
t10.set(1,new Vector3d(-10,0,0));
axes.addAxis(t10, 4, SymmetryType.OPEN);
// Level 2 is C2 along X
Matrix4d r180 = new Matrix4d();
r180.set(new AxisAngle4d(1, 0, 0, Math.PI));
axes.addAxis(r180, 2, SymmetryType.CLOSED);
assertEquals(2,axes.getElementaryAxes().size());
Matrix4d expectedEven = new Matrix4d();
expectedEven.setIdentity();
Matrix4d expectedOdd = new Matrix4d(r180);
assertEquals(expectedEven, axes.getRepeatTransform(0));
assertEquals(expectedOdd, axes.getRepeatTransform(1));
expectedEven.mul(t10);
expectedOdd.mul(r180,expectedEven);
assertEquals(expectedEven, axes.getRepeatTransform(2));
assertEquals(expectedOdd, axes.getRepeatTransform(3));
expectedEven.mul(t10);
expectedOdd.mul(r180,expectedEven);
assertEquals(expectedEven, axes.getRepeatTransform(4));
assertEquals(expectedOdd, axes.getRepeatTransform(5));
expectedEven.mul(t10);
expectedOdd.mul(r180,expectedEven);
assertEquals(expectedEven, axes.getRepeatTransform(6));
assertEquals(expectedOdd, axes.getRepeatTransform(7));
// Test Cauchy Form
List<List<Integer>> relation = Arrays.asList(
Arrays.asList(0,1,2,3,4,5),
Arrays.asList(2,3,4,5,6,7)
);
assertEquals(relation,axes.getRepeatRelation(0));
relation = Arrays.asList(
Arrays.asList(0,1),
Arrays.asList(1,0)
);
assertEquals(relation,axes.getRepeatRelation(1));
try {
axes.getRepeatRelation(2);
fail("Invalid level");
} catch(IndexOutOfBoundsException e) {}
// Test Cyclic Form
relation = Arrays.asList(
Arrays.asList(0,2,4,6),
Arrays.asList(1,3,5,7)
);
assertEquals(relation,axes.getRepeatsCyclicForm(0));
relation = Arrays.asList(
Arrays.asList(0,1)
);
assertEquals(relation,axes.getRepeatsCyclicForm(1));
relation = Arrays.asList(
Arrays.asList(2,3)
);
assertEquals(relation,axes.getRepeatsCyclicForm(1,2));
try {
axes.getRepeatsCyclicForm(2);
fail("Invalid level");
} catch(IndexOutOfBoundsException e) {}
try {
axes.getRepeatsCyclicForm(1,1);
fail("Invalid firstRepeat");
} catch(IllegalArgumentException e) {}
// Expected location of each repeat
Point3d[] repeats = new Point3d[] {
new Point3d(-15,1,1),
new Point3d(-15,-1,-1),
new Point3d( -5,1,1),
new Point3d( -5,-1,-1),
new Point3d( 5,1,1),
new Point3d( 5,-1,-1),
new Point3d( 15,1,1),
new Point3d( 15,-1,-1),
};
// Inverse of first point should give above points
for(int i=0;i<8;i++) {
Matrix4d m = axes.getRepeatTransform(i);
m.invert();
Point3d x = new Point3d(repeats[0]);
m.transform(x);
assertTrue("Transformation "+i+"^-1 of "+repeats[0]+ "="+x+" not "+repeats[i],x.epsilonEquals(repeats[i], 1e-5));
}
// Forward should map the above points onto the first one
for(int i=0;i<8;i++) {
Matrix4d m = axes.getRepeatTransform(i);
Point3d x = new Point3d(repeats[i]);
m.transform(x);
assertTrue("Transformation "+i+" of "+repeats[i]+ "="+x+" not "+repeats[0],x.epsilonEquals(repeats[0], 1e-5));
}
Point3d x;
List<Axis> symmetryAxes = axes.getSymmetryAxes();
assertEquals(5,symmetryAxes.size());
int axisNum = 0;
// Repeat 2 -> 0 (shift 1)
x = new Point3d(repeats[2]);
symmetryAxes.get(axisNum).getOperator().transform(x);
assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[2]),round(x),round(repeats[0])),x.epsilonEquals(repeats[0], 1e-5));
axisNum++;
// All of these are actually equivalent
// Repeat 1 -> 0 (180 deg around x)
x = new Point3d(repeats[1]);
symmetryAxes.get(axisNum).getOperator().transform(x);
assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[1]),round(x),round(repeats[0])),x.epsilonEquals(repeats[0], 1e-5));
axisNum++;
// Repeat 3 -> 2 (180 deg around x)
x = new Point3d(repeats[3]);
symmetryAxes.get(axisNum).getOperator().transform(x);
assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[3]),round(x),round(repeats[2])),x.epsilonEquals(repeats[2], 1e-5));
axisNum++;
// Repeat 5 -> 4 (180 deg around x)
x = new Point3d(repeats[5]);
symmetryAxes.get(axisNum).getOperator().transform(x);
assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[5]),round(x),round(repeats[4])),x.epsilonEquals(repeats[4], 1e-5));
axisNum++;
// Repeat 7 -> 6 (180 deg around x)
x = new Point3d(repeats[7]);
symmetryAxes.get(axisNum).getOperator().transform(x);
assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[7]),round(x),round(repeats[6])),x.epsilonEquals(repeats[6], 1e-5));
axisNum++;
}
/**
* Test that the deprecated addAxis still works
*/
@SuppressWarnings("deprecation")
@Test
public void testOpenCaseOld() {
// D4 case
SymmetryAxes axes = new SymmetryAxes();
// Level 1 is R4 along X
Matrix4d t10 = new Matrix4d();
t10.set(1,new Vector3d(1,0,0));
List<Integer> repeats = Arrays.asList(0,0,1,1,2,2,3,3);
List<List<Integer>> superposition = Arrays.asList(
Arrays.asList(0,1,2,3,4,5),
Arrays.asList(2,3,4,5,6,7));
axes.addAxis(t10, superposition, repeats, 4);
// Level 2 is C2 along X
Matrix4d r180 = new Matrix4d();
r180.set(new AxisAngle4d(1, 0, 0, Math.PI));
repeats = Arrays.asList(0,1,0,1,0,1,0,1);
superposition = Arrays.asList(
Arrays.asList(0,1),
Arrays.asList(1,0));
axes.addAxis(r180, superposition, repeats, 2);
assertEquals(2,axes.getElementaryAxes().size());
Matrix4d expectedEven = new Matrix4d();
expectedEven.setIdentity();
Matrix4d expectedOdd = new Matrix4d(r180);
assertEquals(expectedEven, axes.getRepeatTransform(0));
assertEquals(expectedOdd, axes.getRepeatTransform(1));
expectedEven.mul(t10);
expectedOdd.mul(r180,expectedEven);
assertEquals(expectedEven, axes.getRepeatTransform(2));
assertEquals(expectedOdd, axes.getRepeatTransform(3));
expectedEven.mul(t10);
expectedOdd.mul(r180,expectedEven);
assertEquals(expectedEven, axes.getRepeatTransform(4));
assertEquals(expectedOdd, axes.getRepeatTransform(5));
expectedEven.mul(t10);
expectedOdd.mul(r180,expectedEven);
assertEquals(expectedEven, axes.getRepeatTransform(6));
assertEquals(expectedOdd, axes.getRepeatTransform(7));
List<List<Integer>> relation = Arrays.asList(
Arrays.asList(0,1,2,3,4,5),
Arrays.asList(2,3,4,5,6,7)
);
assertEquals(relation,axes.getRepeatRelation(0));
relation = Arrays.asList(
Arrays.asList(0,1),
Arrays.asList(1,0)
);
assertEquals(relation,axes.getRepeatRelation(1));
try {
axes.getRepeatRelation(2);
fail("Invalid level");
} catch(IndexOutOfBoundsException e) {}
}
}