From d407c9c79ad09e817b7e13fd94bc2e8bc405d503 Mon Sep 17 00:00:00 2001 From: smelia Date: Fri, 23 Mar 2018 11:26:10 +0100 Subject: [PATCH] Added getImageReverted method in ABITrace.java --- .../org/biojava/bio/program/abi/ABITrace.java | 1092 ++++++++++------- 1 file changed, 616 insertions(+), 476 deletions(-) diff --git a/sequencing/src/main/java/org/biojava/bio/program/abi/ABITrace.java b/sequencing/src/main/java/org/biojava/bio/program/abi/ABITrace.java index 1e181cd..bb8a2f3 100644 --- a/sequencing/src/main/java/org/biojava/bio/program/abi/ABITrace.java +++ b/sequencing/src/main/java/org/biojava/bio/program/abi/ABITrace.java @@ -58,365 +58,500 @@ * @author Matthew Pocock * @version 0.5alpha */ -public class ABITrace -{ +public class ABITrace { + //the next three lines are the important persistent data + private String sequence; + private int A[], G[], C[], T[], Basecalls[], Qcalls[]; + private int TraceLength, SeqLength; + + //This is the actual file data. + private byte[] TraceData; + + private final int maximum; + //the next four declaration lines comprise the file index information + //sometimes when macintosh files are + private int MacJunk; + //FTPed in binary form, they have 128 bytes + //of crap pre-pended to them. This constant + //allows ABITrace to handle that in a way that + //is invisible to the user. + private static final int ABS_INDEX_BASE = 26; //The file location of the Index pointer + private int IndexBase, PLOC, PCON; + + //the next declaration is for the actual file pointers + private int DATA9, DATA10, DATA11, DATA12, PBAS2, FWO; - //the next three lines are the important persistent data - private String sequence; - private int A[], G[], C[], T[], Basecalls[], Qcalls[]; - private int TraceLength, SeqLength; - - //This is the actual file data. - private byte[] TraceData; - - private int maximum = 0; - - //the next four declaration lines comprise the file index information - private int MacJunk=0; //sometimes when macintosh files are - //FTPed in binary form, they have 128 bytes - //of crap pre-pended to them. This constant - //allows ABITrace to handle that in a way that - //is invisible to the user. - private static int AbsIndexBase=26; //The file location of the Index pointer - private int IndexBase, PLOC, PCON; - - //the next declaration is for the actual file pointers - private int DATA9, DATA10, DATA11, DATA12, PBAS2, FWO; - -/** - * The File constructor opens a local ABI file and parses the content. - * @param ABIFile is a java.io.File on the local file system. - * @throws IOException if there is a problem reading the file. - * @throws IllegalArgumentException if the file is not a valid ABI file. - */ - public ABITrace( File ABIFile ) throws IOException - { - byte[] bytes = null; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - FileInputStream fis = new FileInputStream(ABIFile); - BufferedInputStream bis = new BufferedInputStream(fis); - int b; - while ((b = bis.read()) >= 0) - { - baos.write(b); + /** + * The File constructor opens a local ABI file and parses the content. + * + * @param ABIFile is a java.io.File on the local file system. + * @throws IOException if there is a problem reading the file. + * @throws IllegalArgumentException if the file is not a valid ABI file. + */ + public ABITrace(File ABIFile) throws IOException { + this.MacJunk = 0; + this.maximum = 0; + byte[] bytes = null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + FileInputStream fis = new FileInputStream(ABIFile); + BufferedInputStream bis = new BufferedInputStream(fis); + int b; + while ((b = bis.read()) >= 0) { + baos.write(b); + } + bis.close(); + fis.close(); + baos.close(); + bytes = baos.toByteArray(); + initData(bytes); } - bis.close(); fis.close(); baos.close(); - bytes = baos.toByteArray(); - initData(bytes); - } -/** - * The URL constructor opens an ABI file from any URL. - * @param ABIFile is a java.net.URL for an ABI trace file. - * @throws IOException if there is a problem reading from the URL. - * @throws IllegalArgumentException if the URL does not contain a valid ABI file. - */ - public ABITrace( URL ABIFile ) throws IOException - { - byte[] bytes = null; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - InputStream is = ABIFile.openStream(); - BufferedInputStream bis = new BufferedInputStream(is); - int b; - while ((b = bis.read()) >= 0) - { - baos.write(b); + /** + * The URL constructor opens an ABI file from any URL. + * + * @param ABIFile is a java.net.URL for an ABI trace file. + * @throws IOException if there is a problem reading from the URL. + * @throws IllegalArgumentException if the URL does not contain a valid ABI + * file. + */ + public ABITrace(URL ABIFile) throws IOException { + this.MacJunk = 0; + this.maximum = 0; + byte[] bytes = null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream is = ABIFile.openStream(); + BufferedInputStream bis = new BufferedInputStream(is); + int b; + while ((b = bis.read()) >= 0) { + baos.write(b); + } + bis.close(); + is.close(); + baos.close(); + bytes = baos.toByteArray(); + initData(bytes); } - bis.close(); is.close(); baos.close(); - bytes = baos.toByteArray(); - initData(bytes); - } -/** - * The byte[] constructor parses an ABI file represented as a byte array. - * @throws IllegalArgumentException if the data does not represent a valid ABI file. - */ - public ABITrace(byte[] ABIFileData) - { - initData(ABIFileData); - } - -/** - * Returns the length of the sequence (number of bases) in this trace. - */ - public int getSequenceLength() { return SeqLength; } + /** + * The byte[] constructor parses an ABI file represented as a + * byte array. + * + * @param ABIFileData + * @throws IllegalArgumentException if the data does not represent a valid + * ABI file. + */ + public ABITrace(byte[] ABIFileData) { + this.MacJunk = 0; + this.maximum = 0; + initData(ABIFileData); + } -/** - * Returns the length of the trace (number of x-coordinate points in the graph). - */ - public int getTraceLength() { return TraceLength; } + /** + * Returns the length of the sequence (number of bases) in this trace. + */ + public int getSequenceLength() { + return SeqLength; + } -/** - * Returns an int[] array that represents the basecalls - each int in the - * array corresponds to an x-coordinate point in the graph that is a peak (a base location). - */ - public int[] getBasecalls() { return Basecalls; } - - /** - * Returns an int[] array that represents the quality - each int in the - * array corresponds to an quality value 90-255) in the graph at a base location). - */ - public int[] getQcalls() { return Qcalls; } + /** + * Returns the length of the trace (number of x-coordinate points in the + * graph). + */ + public int getTraceLength() { + return TraceLength; + } -/** - * Returns the original programatically determined (unedited) sequence as a SymbolList. - */ - public SymbolList getSequence() throws BioError - { - try { - return DNATools.createDNA(sequence); + /** + * Returns an int[] array that represents the basecalls - each + * int in the array corresponds to an x-coordinate point in the graph that + * is a peak (a base location). + */ + public int[] getBasecalls() { + return Basecalls; } - catch (IllegalSymbolException ise) { - // this should be impossible! - throw new BioError(ise); + + /** + * Returns an int[] array that represents the quality - each + * int in the array corresponds to an quality value 90-255) in the graph at + * a base location). + */ + public int[] getQcalls() { + return Qcalls; } - } -/** - * Returns one of the four traces - all of the y-coordinate values, - * each of which correspond to a single x-coordinate relative to the - * position in the array, so that if element 4 in the array is 972, then - * x is 4 and y is 972 for that point. - * - * @param base the DNA AttomicSymbol to retrieve the trace values for - * @return an array of ints giving the entire trace for that base - * @throws IllegalSymbolException if the base is not valid - */ - public int[] getTrace (AtomicSymbol base) throws IllegalSymbolException - { - if (base == DNATools.a()) { - return A; - } else if (base == DNATools.c()) { - return C; - } else if (base == DNATools.g()) { - return G; - } else if (base == DNATools.t()) { - return T; - } else { - DNATools.getDNA().validate(base); - throw new IllegalSymbolException("Don't know symbol: " + base); + /** + * Returns the original programatically determined (unedited) sequence as a + * SymbolList. + */ + public String getSequence() { + return sequence; } - } -/** - * Returns a BufferedImage that represents the entire trace. The height can be set precisely in - * pixels, the width in pixels is determined by the scaling factor times the number - * of points in the trace (getTraceLength()). The entire trace is represented - * in the returned image. - * - * @param imageHeight is the desired height of the image in pixels. - * @param widthScale indiates how many horizontal pixels to use to represent a single x-coordinate (try 2). - */ - public BufferedImage getImage(int imageHeight, int widthScale) - { - BufferedImage out = new BufferedImage(TraceLength * widthScale, imageHeight, BufferedImage.TYPE_BYTE_INDEXED); - Graphics2D g = out.createGraphics(); - Color acolor = Color.green.darker(); - Color ccolor = Color.blue; - Color gcolor = Color.black; - Color tcolor = Color.red; - Color ncolor = Color.pink; - double scale = calculateScale(imageHeight); - int[] bc = Basecalls; - char[] seq = sequence.toCharArray(); - g.setBackground(Color.white); - g.clearRect(0, 0, TraceLength * widthScale, imageHeight); - int here = 0; - int basenum = 0; - for (int q = 1; q <= 5; q++) - { - for (int x = 0; x <= TraceLength - 2; x++) - { - if (q==1) - { - g.setColor(acolor); - g.drawLine(2*x, transmute(A[x], imageHeight, scale), - 2*(x + 1), transmute(A[x+1], imageHeight, scale)); - } - if (q==2) - { - g.setColor(ccolor); - g.drawLine(2*x, transmute(C[x], imageHeight, scale), - 2*(x + 1), transmute(C[x+1], imageHeight, scale)); - } - if (q==3) - { - g.setColor(tcolor); - g.drawLine(2*x, transmute(T[x], imageHeight, scale), - 2*(x + 1), transmute(T[x+1], imageHeight, scale)); + /** + * Returns one of the four traces - all of the y-coordinate values, each of + * which correspond to a single x-coordinate relative to the position in the + * array, so that if element 4 in the array is 972, then x is 4 and y is 972 + * for that point. + * + * @param base the DNA AttomicSymbol to retrieve the trace values for + * @return an array of ints giving the entire trace for that base + * @throws IllegalSymbolException if the base is not valid + */ + public int[] getTrace(char base) { + switch (base) { + case 'a': + return A; + case 'c': + return C; + case 'g': + return G; + case 't': + return T; + default: + throw new IllegalArgumentException("Don't know symbol: " + base); } - if (q==4) - { - g.setColor(gcolor); - g.drawLine(2*x, transmute(G[x], imageHeight, scale), - 2*(x + 1), transmute(G[x+1], imageHeight, scale)); + } + + /** + * Returns reverse representation of sequence. + * @param sequence + * @return + */ + private int[] getSequenceReverted(int[] sequence){ + for (int i = 0; i < sequence.length/2; i++) { + int s = sequence[i]; + sequence[i] = sequence[sequence.length - i - 1]; + sequence[sequence.length - i - 1] = s; } - if (q==5) - { - if ((here > bc.length-1) || (basenum > seq.length-1)) break; - if (bc[here] == x) - { - g.drawLine(2*x, transmute(-2, imageHeight, 1.0), - 2*x, transmute(-7, imageHeight, 1.0)); - if ((basenum+1)%10 == 0) //if the basecount is divisible by ten - //add a number - { - g.drawLine(2*x, transmute(-20, imageHeight, 1.0), - 2*x, transmute(-25, imageHeight, 1.0)); - g.drawString(Integer.toString(basenum+1), - 2*x-3, transmute(-36, imageHeight, 1.0)); + + return sequence; + } + + /** + * Returns a BufferedImage that represents the entire trace. The height can + * be set precisely in pixels, the width in pixels is determined by the + * scaling factor times the number of points in the trace + * (getTraceLength()). The entire trace is represented in the + * returned image. + * + * @param imageHeight is the desired height of the image in pixels. + * @param widthScale indiates how many horizontal pixels to use to represent + * a single x-coordinate (try 2). + * @return BufferedImage that represents the entire trace. + */ + public BufferedImage getImage(int imageHeight, int widthScale) { + BufferedImage out = new BufferedImage(TraceLength * widthScale, imageHeight, BufferedImage.TYPE_BYTE_INDEXED); + Graphics2D g = out.createGraphics(); + Color acolor = Color.green.darker(); + Color ccolor = Color.blue; + Color gcolor = Color.black; + Color tcolor = Color.red; + Color ncolor = Color.pink; + double scale = calculateScale(imageHeight); + int[] bc = Basecalls; + char[] seq = sequence.toCharArray(); + g.setBackground(Color.white); + g.clearRect(0, 0, TraceLength * widthScale, imageHeight); + int here = 0; + int basenum = 0; + for (int q = 1; q <= 5; q++) { + for (int x = 0; x <= TraceLength - 2; x++) { + if (q == 1) { + g.setColor(acolor); + g.drawLine(widthScale * x, transmute(A[x], imageHeight, scale), + widthScale * (x + 1), transmute(A[x + 1], imageHeight, scale)); + } + if (q == 2) { + g.setColor(ccolor); + g.drawLine(widthScale * x, transmute(C[x], imageHeight, scale), + widthScale * (x + 1), transmute(C[x + 1], imageHeight, scale)); + } + if (q == 3) { + g.setColor(tcolor); + g.drawLine(widthScale * x, transmute(T[x], imageHeight, scale), + widthScale * (x + 1), transmute(T[x + 1], imageHeight, scale)); + } + if (q == 4) { + g.setColor(gcolor); + g.drawLine(widthScale * x, transmute(G[x], imageHeight, scale), + widthScale * (x + 1), transmute(G[x + 1], imageHeight, scale)); + } + if (q == 5) { + if ((here > bc.length - 1) || (basenum > seq.length - 1)) { + break; + } + if (bc[here] == x) { + g.drawLine(widthScale * x, transmute(-2, imageHeight, 1.0), + widthScale * x, transmute(-7, imageHeight, 1.0)); + if ((basenum + 1) % 10 == 0) //if the basecount is divisible by ten + //add a number + { + g.drawLine(widthScale * x, transmute(-20, imageHeight, 1.0), + widthScale * x, transmute(-25, imageHeight, 1.0)); + g.drawString(Integer.toString(basenum + 1), + widthScale * x - 3, transmute(-36, imageHeight, 1.0)); + } + switch (seq[basenum]) { + case 'A': + case 'a': + g.setColor(acolor); + break; + case 'C': + case 'c': + g.setColor(ccolor); + break; + case 'G': + case 'g': + g.setColor(gcolor); + break; + case 'T': + case 't': + g.setColor(tcolor); + break; + default: + g.setColor(ncolor); + } + /*g.drawChars(seq, basenum, 1, + 2*x-3, transmute(-18, imageHeight, 1.0));*/ + g.setColor(Color.black); + here++; + basenum++; + } + } } - switch (seq[basenum]) - { - case 'A': case 'a': g.setColor(acolor); break; - case 'C': case 'c': g.setColor(ccolor); break; - case 'G': case 'g': g.setColor(gcolor); break; - case 'T': case 't': g.setColor(tcolor); break; - default: g.setColor(ncolor); + } + return out; + } + + /** + * Returns a BufferedImage that represents the Reverse Complement counterpart of entire trace. The height can + * be set precisely in pixels, the width in pixels is determined by the + * scaling factor times the number of points in the trace + * (getTraceLength()). The entire trace is represented in the + * returned image. + * + * @param imageHeight is the desired height of the image in pixels. + * @param widthScale indiates how many horizontal pixels to use to represent + * a single x-coordinate (try 2). + * @return BufferedImage that represents the Reverse Complement counterpart of entire trace. + */ + public BufferedImage getImageReverted(int imageHeight, int widthScale) { + BufferedImage out = new BufferedImage(TraceLength * widthScale, imageHeight, BufferedImage.TYPE_BYTE_INDEXED); + Graphics2D g = out.createGraphics(); + Color acolor = Color.green.darker(); + Color ccolor = Color.blue; + Color gcolor = Color.black; + Color tcolor = Color.red; + Color ncolor = Color.pink; + double scale = calculateScale(imageHeight); + int[] bc = getSequenceReverted(Basecalls); + char[] seq = sequence.toCharArray(); + int[] AR = getSequenceReverted(A); + int[] CR = getSequenceReverted(C); + int[] GR = getSequenceReverted(G); + int[] TR = getSequenceReverted(T); + g.setBackground(Color.white); + g.clearRect(0, 0, TraceLength * widthScale, imageHeight); + int here = 0; + int basenum = 0; + for (int q = 1; q <= 5; q++) { + for (int x = 0; x <= TraceLength - 2; x++) { + if (q == 1) { + g.setColor(acolor); + g.drawLine(widthScale * x, transmute(AR[x], imageHeight, scale), + widthScale * (x + 1), transmute(AR[x + 1], imageHeight, scale)); + } + if (q == 2) { + g.setColor(ccolor); + g.drawLine(widthScale * x, transmute(CR[x], imageHeight, scale), + widthScale * (x + 1), transmute(CR[x + 1], imageHeight, scale)); + } + if (q == 3) { + g.setColor(tcolor); + g.drawLine(widthScale * x, transmute(TR[x], imageHeight, scale), + widthScale * (x + 1), transmute(TR[x + 1], imageHeight, scale)); + } + if (q == 4) { + g.setColor(gcolor); + g.drawLine(widthScale * x, transmute(GR[x], imageHeight, scale), + widthScale * (x + 1), transmute(GR[x + 1], imageHeight, scale)); + } + if (q == 5) { + if ((here > bc.length - 1) || (basenum > seq.length - 1)) { + break; + } + if (TraceLength-bc[here] == x) { + g.drawLine(widthScale * x, transmute(-2, imageHeight, 1.0), + widthScale * x, transmute(-7, imageHeight, 1.0)); + if ((basenum + 1) % 10 == 0) //if the basecount is divisible by ten add a number + { + g.drawLine(widthScale * x, transmute(-20, imageHeight, 1.0), + widthScale * x, transmute(-25, imageHeight, 1.0)); + g.drawString(Integer.toString(basenum + 1), + widthScale * x - 3, transmute(-36, imageHeight, 1.0)); + } + switch (seq[basenum]) { + case 'A': + case 'a': + g.setColor(acolor); + break; + case 'C': + case 'c': + g.setColor(ccolor); + break; + case 'G': + case 'g': + g.setColor(gcolor); + break; + case 'T': + case 't': + g.setColor(tcolor); + break; + default: + g.setColor(ncolor); + } + g.setColor(Color.black); + here++; + basenum++; + } + } } - g.drawChars(seq, basenum, 1, - 2*x-3, transmute(-18, imageHeight, 1.0)); - g.setColor(Color.black); - here++; basenum++; - } } - } + return out; } - return out; - } -/** - * Initialize all of the data fields for this object. - * @throws IllegalArgumentException which will propagate to all of the constructors. - */ - private void initData(byte[] fileData) - { - TraceData = fileData; - if (isABI()) - { - setIndex(); - setBasecalls(); - setQcalls(); - setSeq(); - setTraces(); - } - else throw new IllegalArgumentException("Not a valid ABI file."); - } -/** - * A utility method which fills array b with data from the trace starting at traceDataOffset. - */ - private void getSubArray(byte[] b, int traceDataOffset) - { - for (int x=0; x<=b.length-1; x++) - { - b[x] = TraceData[traceDataOffset + x]; + /** + * Initialize all of the data fields for this object. + * + * @throws IllegalArgumentException which will propagate to all of the + * constructors. + */ + private void initData(byte[] fileData) { + TraceData = fileData; + if (isABI()) { + setIndex(); + setBasecalls(); + setQcalls(); + setSeq(); + setTraces(); + } else { + throw new IllegalArgumentException("Not a valid ABI file."); + } } - } -/** - * Shuffle the pointers to point to the proper spots in the trace, then load the - * traces into their arrays. - */ - private void setTraces() - { - int pointers[] = new int[4]; //alphabetical, 0=A, 1=C, 2=G, 3=T - int datas[] = new int[4]; - char order[] = new char[4]; - - datas[0] = DATA9; - datas[1] = DATA10; - datas[2] = DATA11; - datas[3] = DATA12; - - for (int i=0; i<=3; i++) - { - order[i]=(char) TraceData[FWO+i]; + /** + * A utility method which fills array b with data from the trace starting at + * traceDataOffset. + */ + private void getSubArray(byte[] b, int traceDataOffset) { + for (int x = 0; x <= b.length - 1; x++) { + b[x] = TraceData[traceDataOffset + x]; + } } - for (int i=0; i <=3; i++) - { - switch (order[i]) - { - case 'A': case 'a': - pointers[0] = datas[i]; - break; - case 'C': case 'c': - pointers[1] = datas[i]; - break; - case 'G': case 'g': - pointers[2] = datas[i]; - break; - case 'T': case 't': - pointers[3] = datas[i]; - break; - default: - throw new IllegalArgumentException("Trace contains illegal values."); - } - } + /** + * Shuffle the pointers to point to the proper spots in the trace, then load + * the traces into their arrays. + */ + private void setTraces() { + int pointers[] = new int[4]; //alphabetical, 0=A, 1=C, 2=G, 3=T + int datas[] = new int[4]; + char order[] = new char[4]; + + datas[0] = DATA9; + datas[1] = DATA10; + datas[2] = DATA11; + datas[3] = DATA12; + + for (int i = 0; i <= 3; i++) { + order[i] = (char) TraceData[FWO + i]; + } - A = new int[TraceLength]; - C = new int[TraceLength]; - G = new int[TraceLength]; - T = new int[TraceLength]; - - for (int i=0; i <=3; i++) - { - byte[] qq = new byte[TraceLength*2]; - getSubArray(qq, pointers[i]); - DataInputStream dis = new DataInputStream(new ByteArrayInputStream(qq)); - for (int x=0; x <=TraceLength - 1; x++) - { - try - { - if (i == 0) A[x] = (int) dis.readShort(); - if (i == 1) C[x] = (int) dis.readShort(); - if (i == 2) G[x] = (int) dis.readShort(); - if (i == 3) T[x] = (int) dis.readShort(); - }catch(IOException e)//This shouldn't happen. If it does something must be seriously wrong. - { - throw new IllegalStateException("Unexpected IOException encountered while manipulating internal streams."); + for (int i = 0; i <= 3; i++) { + switch (order[i]) { + case 'A': + case 'a': + pointers[0] = datas[i]; + break; + case 'C': + case 'c': + pointers[1] = datas[i]; + break; + case 'G': + case 'g': + pointers[2] = datas[i]; + break; + case 'T': + case 't': + pointers[3] = datas[i]; + break; + default: + throw new IllegalArgumentException("Trace contains illegal values."); + } } - } - } - return; - } -/** - * Fetch the sequence from the trace data. - */ - private void setSeq() - { - char tempseq[] = new char[SeqLength]; - for (int x = 0; x <= SeqLength - 1; ++x) - { - tempseq[x] = (char) TraceData[PBAS2 + x]; + A = new int[TraceLength]; + C = new int[TraceLength]; + G = new int[TraceLength]; + T = new int[TraceLength]; + + for (int i = 0; i <= 3; i++) { + byte[] qq = new byte[TraceLength * 2]; + getSubArray(qq, pointers[i]); + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(qq)); + for (int x = 0; x <= TraceLength - 1; x++) { + try { + if (i == 0) { + A[x] = (int) dis.readShort(); + } + if (i == 1) { + C[x] = (int) dis.readShort(); + } + if (i == 2) { + G[x] = (int) dis.readShort(); + } + if (i == 3) { + T[x] = (int) dis.readShort(); + } + } catch (IOException e)//This shouldn't happen. If it does something must be seriously wrong. + { + throw new IllegalStateException("Unexpected IOException encountered while manipulating internal streams."); + } + } + } + return; } - sequence = new String (tempseq); - } + /** + * Fetch the sequence from the trace data. + */ + private void setSeq() { + char tempseq[] = new char[SeqLength]; + for (int x = 0; x <= SeqLength - 1; ++x) { + tempseq[x] = (char) TraceData[PBAS2 + x]; + } + sequence = new String(tempseq); + } -/** - * Fetch the basecalls from the trace data. - */ - private void setBasecalls() - { - Basecalls = new int[SeqLength]; - byte[] qq = new byte[SeqLength*2]; - getSubArray(qq, PLOC); - DataInputStream dis = new DataInputStream(new ByteArrayInputStream(qq)); - for (int i = 0; i <= SeqLength -1; ++i) - { - try - { - Basecalls[i]=(int) dis.readShort(); - }catch(IOException e)//This shouldn't happen. If it does something must be seriously wrong. - { - throw new IllegalStateException("Unexpected IOException encountered while manipulating internal streams."); - } + /** + * Fetch the basecalls from the trace data. + */ + private void setBasecalls() { + Basecalls = new int[SeqLength]; + byte[] qq = new byte[SeqLength * 2]; + getSubArray(qq, PLOC); + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(qq)); + for (int i = 0; i <= SeqLength - 1; ++i) { + try { + Basecalls[i] = (int) dis.readShort(); + } catch (IOException e)//This shouldn't happen. If it does something must be seriously wrong. + { + throw new IllegalStateException("Unexpected IOException encountered while manipulating internal streams."); + } + } } - } - + /** * Fetch the quality calls from the trace data. */ @@ -435,162 +570,167 @@ private void setQcalls() { } } -/** - * Utility method to return an int beginning at pointer in the TraceData array. - */ - private int getIntAt(int pointer) - { - int out = 0; - byte[] temp = new byte[4]; - getSubArray(temp, pointer); - try - { - DataInputStream dis = new DataInputStream(new ByteArrayInputStream(temp)); - out = dis.readInt(); - }catch(IOException e) //This shouldn't happen. If it does something must be seriously wrong. - { - throw new IllegalStateException("Unexpected IOException encountered while manipulating internal streams."); + /** + * Utility method to return an int beginning at pointer in the + * TraceData array. + */ + private int getIntAt(int pointer) { + int out = 0; + byte[] temp = new byte[4]; + getSubArray(temp, pointer); + try { + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(temp)); + out = dis.readInt(); + } catch (IOException e) //This shouldn't happen. If it does something must be seriously wrong. + { + throw new IllegalStateException("Unexpected IOException encountered while manipulating internal streams."); + } + return out; } - return out; - } - -/** - * Utility method to translate y coordinates from graph space (where up is greater) - * to image space (where down is greater). - */ - private int transmute(int ya, int height, double scale) - { - return (height - 45 - (int) (ya * scale)); - } -/** - * Get the maximum height of any of the traces. The data is persisted for performance - * in the event of multiple calls, but it initialized lazily. - */ - private int getMaximum() - { - if (maximum > 0) return maximum; - int max = 0; - for (int x=0; x<=T.length-1; x++) - { - if (T[x] > max) max = T[x]; - if (A[x] > max) max = A[x]; - if (C[x] > max) max = C[x]; - if (G[x] > max) max = G[x]; + /** + * Utility method to translate y coordinates from graph space (where up is + * greater) to image space (where down is greater). + */ + private int transmute(int ya, int height, double scale) { + return (height - 45 - (int) (ya * scale)); } - return max; - } - //calculates the necessary scaling to allow the trace to fit vertically - //in the space specified. -/** - * Returns the scaling factor necessary to allow all of the traces to fit vertically - * into the specified space. - * @param height - the required height in pixels. - */ - private double calculateScale(int height) - { - double newScale = 0.0; - double max = (double)getMaximum(); - double ht = (double)height; - newScale = ((ht - 50.0))/max; - return newScale; - } + /** + * Get the maximum height of any of the traces. The data is persisted for + * performance in the event of multiple calls, but it initialized lazily. + */ + private int getMaximum() { + if (maximum > 0) { + return maximum; + } + int max = 0; + for (int x = 0; x <= T.length - 1; x++) { + if (T[x] > max) { + max = T[x]; + } + if (A[x] > max) { + max = A[x]; + } + if (C[x] > max) { + max = C[x]; + } + if (G[x] > max) { + max = G[x]; + } + } + return max; + } -/** - * Sets up all of the initial pointers to the important records in TraceData. - */ - private void setIndex() - { - int DataCounter, PBASCounter, PLOCCounter, PCONCounter, NumRecords; - byte[] RecNameArray = new byte[4]; - String RecName; - - DataCounter = 0; PBASCounter = 0; PLOCCounter = 0; PCONCounter = 0; - - IndexBase = getIntAt(AbsIndexBase + MacJunk); - NumRecords = getIntAt(AbsIndexBase - 8 + MacJunk); - - for (int record = 0; record <= NumRecords - 1; record++) - { - getSubArray(RecNameArray, (IndexBase + (record * 28))); - RecName = new String (RecNameArray); - if (RecName.equals("FWO_")) - FWO = IndexBase + (record * 28) + 20; - if (RecName.equals("DATA")) - { - ++DataCounter; - if (DataCounter == 9) - DATA9 = IndexBase + (record * 28) + 20; - if (DataCounter == 10) - DATA10 = IndexBase + (record * 28) + 20; - if (DataCounter == 11) - DATA11 = IndexBase + (record * 28) + 20; - if (DataCounter == 12) - DATA12 = IndexBase + (record * 28) + 20; - } - if (RecName.equals("PBAS")) - { - ++PBASCounter; - if (PBASCounter == 2) - PBAS2 = IndexBase + (record * 28) + 20; - } - if (RecName.equals("PLOC")) - { - ++PLOCCounter; - if (PLOCCounter == 2) - PLOC = IndexBase + (record * 28) + 20; - } - if (RecName.equals("PCON")) - { - ++PCONCounter; - if (PCONCounter == 2) - PCON = IndexBase + (record * 28) + 20; - } - - } //next record - TraceLength = getIntAt(DATA12 - 8); - SeqLength = getIntAt(PBAS2-4); - PLOC = getIntAt(PLOC) + MacJunk; - DATA9 = getIntAt(DATA9) + MacJunk; - DATA10 = getIntAt(DATA10) + MacJunk; - DATA11 = getIntAt(DATA11) + MacJunk; - DATA12 = getIntAt(DATA12) + MacJunk; - PBAS2 = getIntAt(PBAS2) + MacJunk; - PCON = getIntAt(PCON) + MacJunk; - } + //calculates the necessary scaling to allow the trace to fit vertically + //in the space specified. + /** + * Returns the scaling factor necessary to allow all of the traces to fit + * vertically into the specified space. + * + * @param height - the required height in pixels. + */ + private double calculateScale(int height) { + double newScale = 0.0; + double max = (double) getMaximum(); + double ht = (double) height; + newScale = ((ht - 50.0)) / max; + return newScale; + } -/** - * Test to see if the file is ABI format by checking to see that the first three bytes - * are "ABI". Also handle the special case where 128 bytes were prepended to the file - * due to binary FTP from an older macintosh system. - */ - private boolean isABI() - { - char ABI[] = new char[4]; + /** + * Sets up all of the initial pointers to the important records in + * TraceData. + */ + private void setIndex() { + int DataCounter, PBASCounter, PLOCCounter, PCONCounter, NumRecords; + byte[] RecNameArray = new byte[4]; + String RecName; + + DataCounter = 0; + PBASCounter = 0; + PLOCCounter = 0; + PCONCounter = 0; + + IndexBase = getIntAt(ABS_INDEX_BASE + MacJunk); + NumRecords = getIntAt(ABS_INDEX_BASE - 8 + MacJunk); + + for (int record = 0; record <= NumRecords - 1; record++) { + getSubArray(RecNameArray, (IndexBase + (record * 28))); + RecName = new String(RecNameArray); + if (RecName.equals("FWO_")) { + FWO = IndexBase + (record * 28) + 20; + } + if (RecName.equals("DATA")) { + ++DataCounter; + if (DataCounter == 9) { + DATA9 = IndexBase + (record * 28) + 20; + } + if (DataCounter == 10) { + DATA10 = IndexBase + (record * 28) + 20; + } + if (DataCounter == 11) { + DATA11 = IndexBase + (record * 28) + 20; + } + if (DataCounter == 12) { + DATA12 = IndexBase + (record * 28) + 20; + } + } + if (RecName.equals("PBAS")) { + ++PBASCounter; + if (PBASCounter == 2) { + PBAS2 = IndexBase + (record * 28) + 20; + } + } + if (RecName.equals("PLOC")) { + ++PLOCCounter; + if (PLOCCounter == 2) { + PLOC = IndexBase + (record * 28) + 20; + } + } + if (RecName.equals("PCON")) { + ++PCONCounter; + if (PCONCounter == 2) { + PCON = IndexBase + (record * 28) + 20; + } + } - for (int i=0; i<=2; i++) - { - ABI[i]=(char) TraceData[i]; + } //next record + TraceLength = getIntAt(DATA12 - 8); + SeqLength = getIntAt(PBAS2 - 4); + PLOC = getIntAt(PLOC) + MacJunk; + DATA9 = getIntAt(DATA9) + MacJunk; + DATA10 = getIntAt(DATA10) + MacJunk; + DATA11 = getIntAt(DATA11) + MacJunk; + DATA12 = getIntAt(DATA12) + MacJunk; + PBAS2 = getIntAt(PBAS2) + MacJunk; + PCON = getIntAt(PCON) + MacJunk; } - if (ABI[0] == 'A' && (ABI[1] == 'B' && ABI[2] == 'I')) - { - return true; - } - else - { - for (int i=128; i<=130; i++) - { - ABI[i]=(char) TraceData[i]; - } - if (ABI[0] == 'A' && (ABI[1] == 'B' && ABI[2] == 'I')) - { - MacJunk=128; - return true; - } - else - return false; - } - } + + /** + * Test to see if the file is ABI format by checking to see that the first + * three bytes are "ABI". Also handle the special case where 128 bytes were + * prepended to the file due to binary FTP from an older macintosh system. + */ + private boolean isABI() { + char ABI[] = new char[4]; + + for (int i = 0; i <= 2; i++) { + ABI[i] = (char) TraceData[i]; + } + if (ABI[0] == 'A' && (ABI[1] == 'B' && ABI[2] == 'I')) { + return true; + } else { + for (int i = 128; i <= 130; i++) { + ABI[i] = (char) TraceData[i]; + } + if (ABI[0] == 'A' && (ABI[1] == 'B' && ABI[2] == 'I')) { + MacJunk = 128; + return true; + } else { + return false; + } + } + } }