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.align.multiple; 022 023import java.io.Serializable; 024import java.util.ArrayList; 025import java.util.List; 026 027import javax.vecmath.Matrix4d; 028 029/** 030 * A general implementation of a BlockSet to store a flexible part of a multiple 031 * alignment. 032 * 033 * @author Aleix Lafita 034 * @since 4.1.0 035 * 036 */ 037public class BlockSetImpl extends AbstractScoresCache implements Serializable, 038 BlockSet, Cloneable { 039 040 private static final long serialVersionUID = -1015791986000076089L; 041 042 // Member variables 043 private MultipleAlignment parent; 044 private List<Block> blocks; 045 046 // Cache variables (can be updated) 047 private List<Matrix4d> pose; // Transformation matrices 048 private int length; 049 private int coreLength; 050 private List<Integer> alignResCounts; 051 052 /** 053 * Constructor. Links also the parent to this instance by adding the 054 * BlockSet to the parent's List. 055 * 056 * @param alignment 057 * MultipleAlignment parent of the BlockSet. 058 */ 059 public BlockSetImpl(MultipleAlignment alignment) { 060 061 parent = alignment; 062 if (parent != null) 063 parent.getBlockSets().add(this); 064 blocks = null; 065 066 pose = null; 067 length = -1; // Value -1 reserved to indicate that has to be calculated 068 coreLength = -1; 069 alignResCounts = null; // Value null means not yet calculated 070 } 071 072 /** 073 * Copy constructor. Makes also a deep copy of all constituent {@link Block} 074 * s. 075 * 076 * @param bs 077 * BlockSet object to be copied. 078 */ 079 public BlockSetImpl(BlockSetImpl bs) { 080 081 super(bs); // This copies the cached scores 082 this.parent = bs.parent; 083 this.length = bs.length; 084 this.coreLength = bs.coreLength; 085 086 this.pose = null; 087 if (bs.pose != null) { 088 // Make a deep copy of everything 089 this.pose = new ArrayList<Matrix4d>(); 090 for (Matrix4d trans : bs.pose) { 091 Matrix4d newTrans = (Matrix4d) trans.clone(); 092 pose.add(newTrans); 093 } 094 } 095 096 blocks = null; 097 if (bs.blocks != null) { 098 // Make a deep copy of everything 099 this.blocks = new ArrayList<>(); 100 for (Block b : bs.blocks) { 101 Block newB = b.clone(); 102 newB.setBlockSet(this); 103 this.blocks.add(newB); 104 } 105 } 106 } 107 108 @Override 109 public void clear() { 110 super.clear(); 111 length = -1; 112 coreLength = -1; 113 alignResCounts = null; 114 pose = null; 115 for (Block a : getBlocks()) { 116 a.clear(); 117 } 118 } 119 120 @Override 121 public BlockSetImpl clone() { 122 return new BlockSetImpl(this); 123 } 124 125 @Override 126 public String toString() { 127 return "BlockSetImpl [blocks=" + blocks + ", pose=" + pose 128 + ", length=" + length + ", coreLength=" + coreLength + "]"; 129 } 130 131 @Override 132 public MultipleAlignment getMultipleAlignment() { 133 return parent; 134 } 135 136 @Override 137 public void setMultipleAlignment(MultipleAlignment parent) { 138 this.parent = parent; 139 } 140 141 @Override 142 public List<Block> getBlocks() { 143 if (blocks == null) 144 blocks = new ArrayList<>(); 145 return blocks; 146 } 147 148 @Override 149 public void setBlocks(List<Block> blocks) { 150 this.blocks = blocks; 151 for (Block b : blocks) { 152 b.setBlockSet(this); 153 } 154 } 155 156 @Override 157 public List<Matrix4d> getTransformations() { 158 return pose; 159 } 160 161 @Override 162 public void setTransformations(List<Matrix4d> transformations) { 163 if (size() != transformations.size()) { 164 throw new IllegalArgumentException( 165 "Wrong number of structures for this alignment"); 166 } 167 pose = transformations; 168 } 169 170 @Override 171 public int length() { 172 if (length == -1) 173 updateLength(); 174 return length; 175 } 176 177 @Override 178 public int size() { 179 // Get the size from the variables that can contain the information 180 if (parent != null) 181 return parent.size(); 182 else if (getBlocks().size() == 0) { 183 throw new IndexOutOfBoundsException( 184 "Empty BlockSet: number of Blocks == 0."); 185 } else 186 return blocks.get(0).size(); 187 } 188 189 @Override 190 public int getCoreLength() { 191 if (coreLength == -1) 192 updateCoreLength(); 193 return coreLength; 194 } 195 196 protected void updateLength() { 197 if (getBlocks().size() == 0) { 198 throw new IndexOutOfBoundsException( 199 "Empty BlockSet: number of Blocks == 0."); 200 } 201 // Try to calculate it from the Block information 202 else { 203 length = 0; 204 for (Block block : blocks) 205 length += block.length(); 206 } 207 } 208 209 protected void updateCoreLength() { 210 if (getBlocks().size() == 0) { 211 throw new IndexOutOfBoundsException( 212 "Empty BlockSet: number of Blocks == 0."); 213 } 214 // Try to calculate it from the Block information 215 else { 216 coreLength = 0; 217 for (Block block : blocks) 218 coreLength += block.getCoreLength(); 219 } 220 } 221 222 protected void updateCache() { 223 updateCoreLength(); 224 updateLength(); 225 } 226 227 @Override 228 public List<Integer> getAlignResCounts() { 229 230 if (alignResCounts != null) 231 return alignResCounts; 232 233 alignResCounts = new ArrayList<>(size()); 234 for (int s = 0; s < size(); s++) 235 alignResCounts.add(0); 236 237 for (Block b : blocks) { 238 List<Integer> bcounts = b.getAlignResCounts(); 239 for (int s = 0; s < size(); s++) 240 alignResCounts.set(s, alignResCounts.get(s) + bcounts.get(s)); 241 } 242 return alignResCounts; 243 } 244 245}