001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.nbio.structure.symmetry.internal; 022 023import static java.lang.Math.*; 024 025import org.biojava.nbio.structure.Atom; 026import org.biojava.nbio.structure.align.model.AFPChain; 027import org.biojava.nbio.structure.align.util.RotationAxis; 028import org.biojava.nbio.structure.symmetry.internal.OrderDetector; 029import org.biojava.nbio.structure.symmetry.internal.RefinerFailedException; 030 031/** 032 * Guesses an order of rotational symmetry from the angle. 033 * <p> 034 * Improves upon the AngleOrderDetector used in the paper by checking all 035 * rotations, not just the base one. 036 * 037 * @author Spencer Bliven 038 * @since 4.2.0 039 * 040 */ 041public class AngleOrderDetectorPlus implements OrderDetector { 042 043 private int maxOrder; 044 private final double error; 045 private boolean normalizeError; 046 047 /** 048 * @param error 049 * maximum angular error, in radians 050 */ 051 public AngleOrderDetectorPlus(double angleError) { 052 this(8, angleError, false); 053 } 054 055 public AngleOrderDetectorPlus(int maxOrder) { 056 // PI is the max error for C1 057 this(maxOrder, PI, false); 058 } 059 060 /** 061 * 062 * @param maxOrder 063 * maximum order to consider 064 * @param error 065 * maximum angular error, in radians 066 */ 067 public AngleOrderDetectorPlus(int maxOrder, double angleError) { 068 this(maxOrder, angleError, false); 069 } 070 071 /** 072 * Determine order by finding the order (up to the maxOrder) which has the 073 * closest rotation angle to the observed rotation. 074 * 075 * If normalized is false, then the error is taken to be the absolute error 076 * from the closest ideal angle (in radians). If normalized is true, error 077 * is taken to be relative to the fundamental rotation for a given order. 078 * For instance, for an error of .25, C2 order would be accepted for angles 079 * within .25*pi radians of 0 or pi, while C3 order would be acceptable 080 * within .25*2pi/3 radians of 0, 2pi/3, or 4pi/3. In the normalized case, 081 * numbers between 0 and .5 are sensible for error. 082 * 083 * @param maxOrder 084 * maximum order to consider 085 * @param error 086 * maximum angular error 087 * @param normalize 088 * indicates whether error should be normalized by the order 089 */ 090 public AngleOrderDetectorPlus(int maxOrder, double angleError, 091 boolean normalize) { 092 super(); 093 this.maxOrder = maxOrder; 094 this.error = angleError; 095 this.normalizeError = normalize; 096 } 097 098 @Override 099 public int calculateOrder(AFPChain afpChain, Atom[] ca) 100 throws RefinerFailedException { 101 final double tol = 1e-6; // tolerance to floating point errors 102 try { 103 RotationAxis axis = new RotationAxis(afpChain); 104 double theta = axis.getAngle(); 105 106 double bestDelta = error; 107 int bestOrder = 1; 108 for (int order = 1; order <= maxOrder; order++) { 109 // Triangle wave starting at 0 with period 2pi/order 110 double delta = abs(abs(theta * order / (2 * PI) - .5) % 1.0 - .5); 111 // Triangle waves have amplitude 1, so need to un-normalize 112 if (!normalizeError) 113 delta *= 2 * PI / order; 114 115 if (delta < bestDelta - tol) { 116 bestOrder = order; 117 bestDelta = delta; 118 } 119 } 120 return bestOrder; 121 } catch (Exception e) { 122 throw new RefinerFailedException(e); 123 } 124 } 125 126 @Override 127 public String toString() { 128 return getClass().getSimpleName() + "[maxOrder=" + maxOrder 129 + ", error=" + error + ", normalizeError=" + normalizeError 130 + "]"; 131 } 132 133}