View Javadoc

1   /*--------------------------------------------------------------------------
2    *  Copyright 2007 utgenome.org
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   *--------------------------------------------------------------------------*/
16  //--------------------------------------
17  // GenomeBrowser Project
18  //
19  // TrackWindow.java
20  // Since: Jun 12, 2007
21  //
22  // $URL$ 
23  // $Author$
24  //--------------------------------------
25  package org.utgenome.gwt.utgb.client.track;
26  
27  import java.io.Serializable;
28  
29  import org.utgenome.gwt.utgb.client.bio.OnGenome;
30  
31  /**
32   * {@link TrackWindow} manages a track-window size and a region on the genome displayed in the window. An instance of
33   * TrackWindow is immutable, so you can safely copy a reference of TrackWindow to preserve a current track window state.
34   * 
35   * @author leo
36   * 
37   */
38  public class TrackWindow implements Serializable, Comparable<TrackWindow> {
39  
40  	private static final long serialVersionUID = 1L;
41  
42  	private final int pixelWidth;
43  	private final int startIndexOnGenome;
44  	private final int endIndexOnGenome;
45  
46  	public TrackWindow() {
47  		this.pixelWidth = -1;
48  		this.startIndexOnGenome = -1;
49  		this.endIndexOnGenome = -1;
50  	}
51  
52  	public TrackWindow(int pixelWidth, int startIndexOnGenome, int endIndexOnGenome) {
53  		this.pixelWidth = pixelWidth;
54  		this.startIndexOnGenome = startIndexOnGenome;
55  		this.endIndexOnGenome = endIndexOnGenome;
56  	}
57  
58  	public TrackWindow(TrackWindow other) {
59  		this(other.pixelWidth, other.getStartOnGenome(), other.getEndOnGenome());
60  	}
61  
62  	/**
63  	 * calculate the X position (pixel address) in a track window of a given index on genome.
64  	 * 
65  	 * @param indexOnGenome
66  	 * @return relative X position in a window (0 origin).
67  	 */
68  	public int convertToPixelX(int indexOnGenome) {
69  		double v = (indexOnGenome - startIndexOnGenome) * (double) pixelWidth;
70  		double v2 = v / (endIndexOnGenome - startIndexOnGenome + 1);
71  		if (!isReverseStrand())
72  			return (int) (v2 + 0.5d);
73  		else
74  			return (int) (pixelWidth - v2 + 0.5d);
75  	}
76  
77  	public double convertToPixelXDouble(int indexOnGenome) {
78  		double v = (indexOnGenome - startIndexOnGenome) * (double) pixelWidth;
79  		double v2 = v / (endIndexOnGenome - startIndexOnGenome + 1);
80  		if (!isReverseStrand())
81  			return v2;
82  		else
83  			return (pixelWidth - v2);
84  	}
85  
86  	/**
87  	 * @param xOnWindow
88  	 *            calculate the genome index of a given x position in the current window
89  	 * @return genome position
90  	 */
91  	public int convertToGenomePosition(int xOnWindow) {
92  		if (!isReverseStrand()) {
93  			double genomeLengthPerBit = (double) (endIndexOnGenome - startIndexOnGenome) / (double) pixelWidth;
94  			return (int) (startIndexOnGenome + xOnWindow * genomeLengthPerBit);
95  		}
96  		else {
97  			// reverse strand
98  			double genomeLengthPerBit = (double) (startIndexOnGenome - endIndexOnGenome) / (double) pixelWidth;
99  			return (int) (endIndexOnGenome + (pixelWidth - xOnWindow) * genomeLengthPerBit);
100 		}
101 	}
102 
103 	public int convertToPixelLength(int rangeOnGenome) {
104 		return (int) ((pixelWidth * rangeOnGenome) / (double) (endIndexOnGenome - startIndexOnGenome));
105 	}
106 
107 	/**
108 	 * @return pixel length / (genome end - genome start);
109 	 */
110 	public double getPixelLengthPerBase() {
111 		return (double) pixelWidth / (double) (endIndexOnGenome - startIndexOnGenome);
112 	}
113 
114 	/**
115 	 * @return the window size
116 	 */
117 	public int getPixelWidth() {
118 		return pixelWidth;
119 	}
120 
121 	/**
122 	 * @return the sequence width
123 	 */
124 	public int getSequenceLength() {
125 		if (startIndexOnGenome <= endIndexOnGenome)
126 			return endIndexOnGenome - startIndexOnGenome;
127 		else
128 			return startIndexOnGenome - endIndexOnGenome;
129 	}
130 
131 	public int getViewStartOnGenome() {
132 		if (isReverseStrand())
133 			return endIndexOnGenome;
134 		else
135 			return startIndexOnGenome;
136 	}
137 
138 	public int getViewEndOnGenome() {
139 		if (isReverseStrand())
140 			return startIndexOnGenome;
141 		else
142 			return endIndexOnGenome;
143 	}
144 
145 	/**
146 	 * @return start position on the genome currently displayed in the window
147 	 */
148 	public int getStartOnGenome() {
149 		return startIndexOnGenome;
150 	}
151 
152 	/**
153 	 * @return end position on the genome currently displayed in the window
154 	 */
155 	public int getEndOnGenome() {
156 		return endIndexOnGenome;
157 	}
158 
159 	public boolean sameRangeWith(TrackWindow window) {
160 		return this.startIndexOnGenome == window.getStartOnGenome() && this.endIndexOnGenome == window.getEndOnGenome();
161 	}
162 
163 	public boolean isReverseStrand() {
164 		return getStartOnGenome() > getEndOnGenome();
165 	}
166 
167 	public boolean isPositiveStrand() {
168 		return !isReverseStrand();
169 	}
170 
171 	public TrackWindow newWindow(int newStartOnGenome, int newEndOnGenome) {
172 		return new TrackWindow(this.pixelWidth, newStartOnGenome, newEndOnGenome);
173 	}
174 
175 	public TrackWindow scroll(int startDiff) {
176 		return new TrackWindow(this.pixelWidth, this.startIndexOnGenome + startDiff, this.endIndexOnGenome + startDiff);
177 	}
178 
179 	public TrackWindow newPixelWidthWindow(int pixelSize) {
180 		return new TrackWindow(pixelSize, this.startIndexOnGenome, this.endIndexOnGenome);
181 	}
182 
183 	public boolean contains(TrackWindow other) {
184 		int s1 = getViewStartOnGenome();
185 		int e1 = getViewEndOnGenome();
186 		int s2 = other.getViewStartOnGenome();
187 		int e2 = other.getViewEndOnGenome();
188 		return s1 <= s2 && e2 <= e1;
189 	}
190 
191 	public boolean overlapWith(OnGenome g) {
192 		int s1 = getStartOnGenome();
193 		int e1 = getEndOnGenome();
194 		int s2 = g.getStart();
195 		int e2 = g.getEnd();
196 
197 		return s1 <= e2 && s2 <= e1;
198 	}
199 
200 	public boolean overlapWith(TrackWindow other) {
201 		int s1 = getStartOnGenome();
202 		int e1 = getEndOnGenome();
203 		int s2 = other.getStartOnGenome();
204 		int e2 = other.getEndOnGenome();
205 
206 		return s1 < e2 && s2 < e1;
207 	}
208 
209 	public boolean hasSameScaleWith(TrackWindow other) {
210 		if (other == null)
211 			return false;
212 		return this.getPixelWidth() == other.getPixelWidth() && this.getSequenceLength() == other.getSequenceLength();
213 	}
214 
215 	public TrackWindow mask(TrackWindow mask) {
216 		int s, e, pixelWidth;
217 		if (this.getStartOnGenome() < mask.getStartOnGenome()) {
218 			s = this.getStartOnGenome();
219 			e = mask.getStartOnGenome();
220 			pixelWidth = convertToPixelX(e);
221 		}
222 		else {
223 			s = mask.getEndOnGenome();
224 			e = this.getEndOnGenome();
225 			pixelWidth = this.getPixelWidth() - convertToPixelX(s);
226 		}
227 		return new TrackWindow(pixelWidth, s, e);
228 	}
229 
230 	public int compareTo(TrackWindow o) {
231 		return this.getViewStartOnGenome() - o.getViewStartOnGenome();
232 	}
233 
234 	// @see java.lang.Object#equals(java.lang.Object)
235 	@Override
236 	public boolean equals(Object o) {
237 		if (o instanceof TrackWindow) {
238 			TrackWindow window = (TrackWindow) o;
239 			return sameRangeWith(window) && (this.pixelWidth == window.getPixelWidth());
240 		}
241 		else
242 			return false;
243 	}
244 
245 	public int center() {
246 		return (int) ((startIndexOnGenome + endIndexOnGenome) / 2.0 + 0.5);
247 	}
248 
249 	@Override
250 	public int hashCode() {
251 		int hash = 3;
252 		hash += 137 * startIndexOnGenome;
253 		hash += 137 * endIndexOnGenome;
254 		hash += 137 * pixelWidth;
255 		return hash / 1987;
256 	}
257 
258 	@Override
259 	public String toString() {
260 		return "[" + getStartOnGenome() + ", " + getEndOnGenome() + ") pixel width: " + pixelWidth;
261 	}
262 }