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 */ 021 022package org.biojava.bio.gui.sequence; 023 024import java.awt.Graphics2D; 025import java.awt.event.MouseEvent; 026import java.util.Iterator; 027import java.util.List; 028 029import org.biojava.bio.seq.DNATools; 030import org.biojava.bio.seq.StrandedFeature; 031import org.biojava.bio.symbol.RangeLocation; 032import org.biojava.bio.symbol.SymbolList; 033 034// The graphics model in Java 035// drawing space -> applet space -> device space 036// All operations are cumulative, including translates 037// translates will move drawing rightward/downward for any supplied value 038 039/** 040 * Compute sites of stop codons. It uses a child renderer to 041 * do actual drawing. 042 * 043 * @author David Huen 044 */ 045 046 047public class StopRenderer implements SequenceRenderer { 048 private double scaleThreshold = 0.005; 049 private SixFrameRenderer pane; 050 private int moduloFrame; 051 private StrandedFeature.Strand strand; 052 053 public StopRenderer( 054 SixFrameRenderer pane, 055 int moduloFrame, 056 StrandedFeature.Strand strand) { 057 this.pane = pane; 058 this.moduloFrame = moduloFrame; 059 this.strand = strand; 060 } 061 062 public double getDepth(SequenceRenderContext src) { 063 // an arbitrary limit is set here to prevent excessive sequence 064 // download. 065 if (src.getScale() < scaleThreshold) return 0; 066 else return pane.getDepth(src); 067 } 068 069 public double getMinimumLeader(SequenceRenderContext src) { 070 return 0.0; 071 } 072 073 public double getMinimumTrailer(SequenceRenderContext src) { 074 return 0.0; 075 } 076 077 private boolean isStop(SymbolList seq, 078 int base, 079 StrandedFeature.Strand strand) { 080 // tests whether there is a stop at given location. 081 // the triplet is either base, +1, +2 or -1, -2 082 // depending on the strand searched 083 if (strand == StrandedFeature.POSITIVE) { 084 // check that search does not exceed bounds 085 if (base + 2 > seq.length()) return false; 086 087 // search top strand 088 // first base must be t 089 if (seq.symbolAt(base) != DNATools.t()) return false; 090 091 // second base cannot be c or t 092 if (seq.symbolAt(base+1) == DNATools.c()) return false; 093 if (seq.symbolAt(base+1) == DNATools.t()) return false; 094 095 // if second base is g, the third must be a 096 if (seq.symbolAt(base+1) == DNATools.g()) { 097 if (seq.symbolAt(base+2) != DNATools.a()) return false; 098 } 099 else { 100 // second base is a: third must be a or g. 101 if (seq.symbolAt(base+2) == DNATools.c()) return false; 102 if (seq.symbolAt(base+2) == DNATools.t()) return false; 103 } 104 105 // oh well, must be a stop, innit? 106 return true; 107 108 } else { 109 // check bounds 110 if (base - 2 < 1) return false; 111 112 // search bottom strand 113 // first base must be t 114 if (seq.symbolAt(base) != DNATools.a()) return false; 115 116 // second base cannot be c or t on reverse strand 117 if (seq.symbolAt(base-1) == DNATools.a()) return false; 118 if (seq.symbolAt(base-1) == DNATools.g()) return false; 119 120 // if second base is g, the third must be a 121 if (seq.symbolAt(base-1) == DNATools.c()) { 122 if (seq.symbolAt(base-2) != DNATools.t()) return false; 123 } 124 else { 125 // second base is a: third must be a or g. 126 if (seq.symbolAt(base-2) == DNATools.a()) return false; 127 if (seq.symbolAt(base-2) == DNATools.g()) return false; 128 } 129 130 // ach! a stop! 131 return true; 132 } 133 } 134 135 private void renderOneFrame( 136 Graphics2D g, 137 SequenceRenderContext src, 138 RangeLocation range, 139 boolean onceOnly) { 140 // method to draw by checking succeeding triplets for 141 // stop codons. 142 // write it for horizontal rendering first. 143 SymbolList seq = src.getSymbols(); 144 145 // get extent of sequence to render 146 // hope it agrees with clip region! 147 int minS = range.getMin(); 148 int maxS = range.getMax(); 149 150 // we start at the first triplet whose first base is within 151 // the range. 152 if (minS%3 > moduloFrame) { 153 // first triplet of my frame is in next mod-zero triplet 154 minS = (minS/3 + 1) * 3 + moduloFrame; 155 } 156 else if (minS%3 != moduloFrame) { 157 // first triplet is in current mod-zero triplet 158 minS = (minS/3) * 3 + moduloFrame; 159 } 160 161 // now we search every triplet from minS upward seeking stops. 162 for (int base = minS; base <= maxS; base += 3) { 163 // check for stop 164 if (!isStop(seq, base, strand)) continue; 165 166 // we have a stop, render a line 167 pane.drawLine(g, src, base, strand); 168 169 // do I call it quits now? 170 if (onceOnly) return; 171 } 172 } 173 174 public void paint( 175 Graphics2D g, 176 SequenceRenderContext src 177 ) { 178 double scale = src.getScale(); 179 180 // this is a completely arbitrary limit to stop my viewer 181 // from attempting to trigger the download of HUGE amounts 182 // of sequence. 183 if (scale < scaleThreshold) return; 184 185 // could we get more than one stop per pixel at the current 186 // scale? 187 if (scale < 0.05) { 188 // yes, we can. Iterate thru' graphics space. 189 Iterator extentsI = pane.sequenceExtentOfPixels(src).iterator(); 190 191 // check each extent for stops 192 while (extentsI.hasNext()) { 193 RangeLocation range = (RangeLocation) extentsI.next(); 194 renderOneFrame(g, src, range, true); 195 } 196 } 197 else { 198 // no we can't. Iterate thru' sequence. 199 renderOneFrame(g, src, src.getRange(), false); 200 } 201 } 202 203 public SequenceViewerEvent processMouseEvent( 204 SequenceRenderContext src, 205 MouseEvent me, 206 List path 207 ) { 208 path.add(this); 209 int sPos = src.graphicsToSequence(me.getPoint()); 210 return new SequenceViewerEvent(this, null, sPos, me, path); 211 } 212}