1 /* MarkerRange.java 2 * 3 * created: Tue Dec 29 1998 4 * 5 * This file is part of Artemis 6 * 7 * Copyright (C) 1998,1999,2000 Genome Research Limited 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; either version 2 12 * of the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 * 23 * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/sequence/MarkerRange.java,v 1.1 2004-06-09 09:52:20 tjc Exp $ 24 */ 25 26 package uk.ac.sanger.artemis.sequence; 27 28 import uk.ac.sanger.artemis.util.*; 29 30 import uk.ac.sanger.artemis.io.Range; 31 32 /** 33 * This class implements a range that has end points specified by a pair of 34 * positions in a Strand object. 35 * 36 * @author Kim Rutherford 37 * @version $Id: MarkerRange.java,v 1.1 2004-06-09 09:52:20 tjc Exp $ 38 **/ 39 40 public class MarkerRange { 41 /** 42 * Create a new MarkerRange object. If the start position is greater than 43 * the end position the two positions will be silently swapped. 44 * @param strand The Strand that contains this range. 45 * @param start The start position. 46 * @param end The end position. 47 **/ MarkerRange(final Strand strand, final int start, final int end)48 public MarkerRange (final Strand strand, final int start, final int end) 49 throws OutOfRangeException { 50 if (start <= end) { 51 this.start = strand.makeMarker (start); 52 this.end = strand.makeMarker (end); 53 } else { 54 this.start = strand.makeMarker (end); 55 this.end = strand.makeMarker (start); 56 } 57 } 58 59 /** 60 * Create a new MarkerRange object that covers one base (given by a Marker 61 * object). 62 * @param marker The position of the new MarkerRange. 63 **/ MarkerRange(final Marker marker)64 public MarkerRange (final Marker marker) { 65 this.start = marker; 66 this.end = marker; 67 } 68 69 /** 70 * Return the Strand object that was passed to the constructor. 71 **/ getStrand()72 public Strand getStrand () { 73 return getStart ().getStrand (); 74 } 75 76 /** 77 * Return true if and only if this MarkerRange is a MarkerRange on the 78 * forward strand. 79 **/ isForwardMarker()80 public boolean isForwardMarker () { 81 return getStrand ().isForwardStrand (); 82 } 83 84 /** 85 * Return the start Marker of this range. 86 **/ getStart()87 public Marker getStart () { 88 return start; 89 } 90 91 /** 92 * Return the end Marker of this range. 93 **/ getEnd()94 public Marker getEnd () { 95 return end; 96 } 97 98 /** 99 * Return the number of bases in the range, inclusive of the end points. 100 **/ getCount()101 public int getCount () { 102 return 103 getRawEnd ().getRawPosition () - getRawStart ().getRawPosition () + 1; 104 } 105 106 /** 107 * Return the end marker if it marks a lower position on the underlying 108 * Bases of the Strand than the start Marker, otherwise return the start 109 * Marker. 110 **/ getRawStart()111 public Marker getRawStart () { 112 if (getStart ().getRawPosition () <= getEnd ().getRawPosition ()) { 113 return getStart (); 114 } else { 115 return getEnd (); 116 } 117 } 118 119 /** 120 * Return the start marker if it marks a lower position on the underlying 121 * Bases of the Strand than the end Marker, otherwise return the end 122 * Marker. 123 **/ getRawEnd()124 public Marker getRawEnd () { 125 if (getEnd ().getRawPosition () <= getStart ().getRawPosition ()) { 126 return getStart (); 127 } else { 128 return getEnd (); 129 } 130 } 131 132 /** 133 * Return an embl.Range object that corresponds a range of bases on the 134 * underlying Bases object of this MarkerRange. 135 **/ getRawRange()136 public Range getRawRange () { 137 try { 138 if (getStrand ().isForwardStrand ()) { 139 return new Range (getStart ().getRawPosition (), 140 getEnd ().getRawPosition ()); 141 } else { 142 return new Range (getEnd ().getRawPosition (), 143 getStart ().getRawPosition ()); 144 } 145 } catch (OutOfRangeException e) { 146 throw new Error ("internal error - unexpected exception: " + e); 147 } 148 } 149 150 /** 151 * Return an embl.Range object for this MarkerRange. The start and end 152 * positions of the Range will be the same as the start and end that was 153 * passed to the constructor. 154 **/ getRange()155 public Range getRange () { 156 try { 157 return new Range (getStart ().getPosition (), getEnd ().getPosition ()); 158 } catch (OutOfRangeException e) { 159 throw new Error ("internal error - unexpected exception: " + e); 160 } 161 } 162 163 /** 164 * Return true if and only if this MarkerRange and the given MarkerRange 165 * overlap. 166 **/ overlaps(final MarkerRange arg_range)167 public boolean overlaps (final MarkerRange arg_range) { 168 if (getStart ().getPosition () < arg_range.getStart ().getPosition () && 169 getEnd ().getPosition () < arg_range.getStart ().getPosition ()) { 170 return false; 171 } 172 if (getStart ().getPosition () > arg_range.getEnd ().getPosition () && 173 getEnd ().getPosition () > arg_range.getEnd ().getPosition ()) { 174 return false; 175 } 176 return true; 177 } 178 179 /** 180 * Return a new MarkerRange object that is the same as this object but has 181 * been extended to contain the given range. 182 * @param arg_range The returned MarkerRange will cover this range too. 183 **/ extendRange(final MarkerRange arg_range)184 public MarkerRange extendRange (final MarkerRange arg_range) { 185 return combineRanges (arg_range, true); 186 } 187 188 /** 189 * Return a new MarkerRange object that is the same as this object but is 190 * guaranteed to contain the given range. 191 * @param arg_range The returned MarkerRange will cover this range too. 192 * @param truncate_if_contained If the arg_range is completely contained in 193 * this range then the returned range will be truncated if and only if 194 * this is true. If true then one extreme of the returned range will be 195 * moved so that it coincides with the closest extreme of the arg_range. 196 * The returned range will be only as small as necessary to achieve this. 197 * eg. if this is 1..100, the arg is 20..30 and truncate_if_contained is 198 * true then the returned range will be 20..100 199 **/ combineRanges(final MarkerRange arg_range, final boolean truncate_if_contained)200 public MarkerRange combineRanges (final MarkerRange arg_range, 201 final boolean truncate_if_contained) { 202 if (getStrand () != arg_range.getStrand ()) { 203 throw new Error ("internal error - strands do not match"); 204 } 205 206 final MarkerRange return_range; 207 208 try { 209 return_range = 210 new MarkerRange (getStrand (), 211 getStart ().getPosition (), 212 getEnd ().getPosition ()); 213 } catch (OutOfRangeException e) { 214 throw new Error ("internal error - unexpected exception: " + e); 215 } 216 217 if (return_range.contains (arg_range)) { 218 if (truncate_if_contained) { 219 // truncate the return_range 220 if ((arg_range.getStart ().getPosition () - 221 return_range.getStart ().getPosition ()) > 222 (return_range.getEnd ().getPosition () - 223 arg_range.getEnd ().getPosition ())) { 224 return_range.end = arg_range.getEnd (); 225 } else { 226 return_range.start = arg_range.getStart (); 227 } 228 } else { 229 // do nothing 230 } 231 } else { 232 if (return_range.getStart ().getPosition () > 233 arg_range.getStart ().getPosition ()) { 234 return_range.start = arg_range.getStart (); 235 } 236 237 if (return_range.getEnd ().getPosition () < 238 arg_range.getEnd ().getPosition ()) { 239 return_range.end = arg_range.getEnd (); 240 } 241 } 242 243 return return_range; 244 } 245 246 /** 247 * Return true if and only if the given MarkerRange is contained within 248 * this range. 249 **/ contains(final MarkerRange arg_range)250 public boolean contains (final MarkerRange arg_range) { 251 if (getStart ().getPosition () <= arg_range.getStart ().getPosition () && 252 getEnd ().getPosition () >= arg_range.getEnd ().getPosition ()) { 253 return true; 254 } else { 255 return false; 256 } 257 } 258 259 /** 260 * Create and return a Location object from the embl package that describes 261 * this MarkerRange object. For example if the sequence is 1000 bases long 262 * and the MarkerRange object covers the reverse strand bases 100..200 then 263 * the Location object will be "complement(800..900)". 264 **/ createLocation()265 public uk.ac.sanger.artemis.io.Location createLocation () { 266 try { 267 final uk.ac.sanger.artemis.io.Location new_location = 268 new uk.ac.sanger.artemis.io.Location (getRawRange ()); 269 270 if (getStrand ().isForwardStrand ()) { 271 return new_location; 272 } else { 273 return new_location.getComplement (); 274 } 275 } catch (OutOfRangeException e) { 276 throw new Error ("internal error - unexpected exception: " + e); 277 } 278 } 279 280 /** 281 * The start Marker created from the Strand object and the start position 282 * passed to the constructor. 283 **/ 284 private Marker start = null; 285 286 /** 287 * The end Marker created from the Strand object and the end position 288 * passed to the constructor. 289 **/ 290 private Marker end = null; 291 } 292 293 294