/* * BioJava development code * * This code may be freely distributed and modified under the * terms of the GNU Lesser General Public Licence. This should * be distributed with the code. If you do not have a copy, * see: * * http://www.gnu.org/copyleft/lesser.html * * Copyright for this code is held jointly by the individual * authors. These should be listed in @author doc comments. * * For more information on the BioJava project and its aims, * or to join the biojava-l mailing list, visit the home page * at: * * http://www.biojava.org/ * */ package org.biojava.nbio.structure.quaternary; import org.biojava.nbio.structure.xtal.CrystalCell; import org.biojava.nbio.structure.xtal.CrystalTransform; import org.biojava.nbio.core.util.PrettyXMLWriter; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import javax.vecmath.Matrix4d; import javax.vecmath.Point3d; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.*; import java.util.ArrayList; import java.util.List; /** * The transformation needed for generation of biological assemblies * from the contents of a PDB/mmCIF file. It contains both the actual * transformation (rotation+translation) and the chain identifier to * which it should be applied. * * @author Peter Rose * @author Andreas Prlic * @author rickb * @author Jose Duarte * @see CrystalTransform */ public class BiologicalAssemblyTransformation implements Cloneable, Serializable { private static final long serialVersionUID = -6388503076022480391L; private String id; private String chainId; private Matrix4d transformation; /** * Default Constructor */ public BiologicalAssemblyTransformation() { // we initialize to identity so that setting rotation and translation work properly transformation = new Matrix4d(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); } /** * Copy Constructor * * @param src */ public BiologicalAssemblyTransformation(final BiologicalAssemblyTransformation src) { this.transformation = new Matrix4d(src.transformation); this.id = src.getId(); this.chainId = src.getChainId(); } /** * Sets the identifier for this biological assembly transformation. This is usually * the model number used in the biological assembly files. * @param id */ public void setId(String id) { this.id = id; } /** * Returns the identifier for this biological assembly transformation. * @return biological assembly transformation identifier */ public String getId() { return id; } /** * Sets the chain identifier (asym id) that this transformation should be applied to. * @param chainId */ public void setChainId(String chainId) { this.chainId = chainId; } /** * Returns the chain identifier (asym id) that this transformation should be applied to. * @return chain identifier */ public String getChainId() { return this.chainId; } /** * Sets the transformation using a 4x4 transformation matrix * @param transformation */ public void setTransformationMatrix(Matrix4d transformation) { this.transformation = transformation; } /** * Return the transformation (both rotational and translational component) as a 4x4 transformation matrix. * The transformation is in orthonormal (cartesian coordinates). If required to be converted to * crystal coordinates then use {@link CrystalCell#transfToCrystal(Matrix4d)} * Note that this is a reference to the variable, thus it remains linked to this object's transformation field. * The user must deep copy it if need changing it. * @return 4x4 transformation matrix */ public Matrix4d getTransformationMatrix() { return transformation; } public void setRotationMatrix(double[][] m) { for (int i=0;i<3;i++) { for (int j=0;j<3;j++) { this.transformation.setElement(i, j, m[i][j]); } } } public void setTranslation(double[] t) { for (int i=0;i<3;i++) { this.transformation.setElement(i, 3, t[i]); } } /** * Applies the transformation to given point. */ public void transformPoint(final double[] point) { Point3d p = new Point3d(point[0],point[1],point[2]); transformation.transform(p); point[0] = p.x; point[1] = p.y; point[2] = p.z; } /** * Returns the combination (product) of two biological assembly transformations. * @param matrix1 * @param matrix2 * @return combined transformation */ public static BiologicalAssemblyTransformation combine(BiologicalAssemblyTransformation matrix1, BiologicalAssemblyTransformation matrix2) { Matrix4d transformation = new Matrix4d(matrix1.transformation); transformation.mul(matrix2.transformation); BiologicalAssemblyTransformation combined = new BiologicalAssemblyTransformation(); combined.setTransformationMatrix(transformation); return combined; } /** * Tells whether this transformation is in identity. * @return */ public boolean isIdentity() { return transformation.epsilonEquals(new Matrix4d(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1), 0.00000000001); } public String toXML() throws IOException{ StringWriter sw = new StringWriter(); PrintWriter writer = new PrintWriter(sw); PrettyXMLWriter xml = new PrettyXMLWriter(new PrintWriter(writer)); toXML(xml); xml.close(); writer.close(); sw.close(); return sw.toString(); } public void toXML(PrettyXMLWriter xml) throws IOException{ xml.openTag("transformation"); xml.attribute("index",id); xml.openTag("matrix"); for ( int i = 0 ; i<3 ; i++){ for ( int j = 0 ; j<3 ;j++){ xml.attribute("m" + (i+1) + (j+1), String.format("%.8f",transformation.getElement(i,j))); } } xml.closeTag("matrix"); xml.openTag("shift"); for ( int i = 0 ; i<3 ; i++) { xml.attribute("v"+(i+1),String.format("%.8f", transformation.getElement(i,3))); } xml.closeTag("shift"); xml.closeTag("transformation"); } public static BiologicalAssemblyTransformation fromXML(String xml) throws SAXException, IOException, ParserConfigurationException{ List<BiologicalAssemblyTransformation> transformations = fromMultiXML(xml); if ( transformations.size() > 0) return transformations.get(0); else return null; } public static List<BiologicalAssemblyTransformation> fromMultiXML(String xml) throws ParserConfigurationException, SAXException, IOException{ List<BiologicalAssemblyTransformation> transformations = new ArrayList<BiologicalAssemblyTransformation>(); // read the XML of a string and returns a ModelTransformationmatrix DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder db = factory.newDocumentBuilder(); InputSource inStream = new InputSource(); inStream.setCharacterStream(new StringReader(xml)); Document doc = db.parse(inStream); // normalize text representation doc.getDocumentElement().normalize();; NodeList listOfTransforms = doc.getElementsByTagName("transformation"); for(int pos=0; pos<listOfTransforms.getLength() ; pos++) { Node rootElement = listOfTransforms.item(pos); BiologicalAssemblyTransformation max = new BiologicalAssemblyTransformation(); max.id = getAttribute(rootElement,"index"); max.chainId = getAttribute(rootElement,"chainName"); NodeList listOfChildren = rootElement.getChildNodes(); for(int i=0; i<listOfChildren.getLength() ; i++) { // and now the matrix ... Node block = listOfChildren.item(i); // we only look at blocks. if ( block.getNodeName().equals("matrix")) max.setRotationMatrix(getMatrixFromXML(block)); if ( block.getNodeName().equals("shift")) max.setTranslation(getVectorFromXML(block)); } transformations.add(max); } return transformations; } private static double[] getVectorFromXML(Node block) { double[] d = new double[3]; for ( int i = 0 ; i<3 ; i++){ d[i] = Float.parseFloat(getAttribute(block, "v" + (i+1) )); } return d; } private static double[][] getMatrixFromXML(Node block) { double[][] m = new double[3][3]; for ( int i = 0 ; i<3 ; i++){ for ( int j = 0 ; j<3 ;j++){ // TODO check is this matrix is populated correctly String val = getAttribute(block, "m" + (j+1)+(i+1)); m[j][i] = Double.parseDouble(val); } } return m; } private static String getAttribute(Node node, String attr){ if( ! node.hasAttributes()) return null; NamedNodeMap atts = node.getAttributes(); if ( atts == null) return null; Node att = atts.getNamedItem(attr); if ( att == null) return null; String value = att.getTextContent(); return value; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "BiologicalAssemblyTransformation [id=" + id + ", chainId=" + chainId + ", rotation=" + rotMatrixToString(transformation) + ", translation=" + translVecToString(transformation) + "]"; } public static String rotMatrixToString(Matrix4d m) { return String.format("(%5.2f %5.2f %5.2f, %5.2f %5.2f %5.2f, %5.2f %5.2f %5.2f)", m.m00, m.m01, m.m02, m.m10, m.m11, m.m12, m.m20, m.m21, m.m22); } public static String translVecToString(Matrix4d m) { return String.format("(%5.2f %5.2f %5.2f)", m.m03, m.m13, m.m23); } }