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.genome.parsers.gff; 022 023import org.biojava.nbio.genome.App; 024import org.slf4j.Logger; 025import org.slf4j.LoggerFactory; 026 027 028/** 029 * A location on a sequence. 030 * A location is a contiguous range of indices, with a single start and end point. 031 * <br><br> 032 * Internally, location indices are stored in Java "half-open" format: the start is the (origin 0) index of 033 * the first symbol in the range; the end is the origin 0 index of the first symbol PAST the 034 * end of the range, so that end - start == length. 035 * <br><br> 036 * Location objects, once constructed, cannot be changed. Instead, all methods return a new 037 * location. This allows the use of "method chaining" to implement a particular calculation. 038 * For example, consider the chained statement "loc.prefix( 100 ).suffix( 10 )", 039 * which first applies the prefix method to 040 * the variable named loc, and then the suffix method to the result. 041 * Together, the chained operations create a new location object of length 10 042 * whose start is the index of the 90th symbol. 043 * Here's another example. This one returns a location object holding the coordinates of the intron between 044 * the first exon (location exon1) and 045 * the second exon (location exon2) on a sequence (seq): "seq.prefix( exon2 ).suffix( exon1 )" 046 * <br><br> 047 * About the negative (reverse) strand: The location object stores reverse strand locations as 048 * negative indices. For example, the positive strand location from index 12 to index 97 is 049 * on the opposite side as index -97 (start) to index -12 (end). Note that the larger index is 050 * always downstream from the smaller index, (i.e. start <= end, regardless of strand). 051 * Obviously this representation makes it trivial 052 * to convert a location from one strand to the other. 053 * <br><br> 054 * Additional points regarding the use of locations on opposite strands: 055 *<br> 056 * (1) Opposite strand locations cannot be compared, eg isBefore() will 057 * throw an exception.<br> 058 * (2) Containment queries ( eg overlaps(), contains() ) also throw exceptions. 059 *<br> 060 * (3) The plus() method will map a location to its positive strand equivalent; use it on both args 061 * before calling, for example the intersection() method, 062 * if your code needs to be indifferent to strand. 063 *<br><br> 064 * Exceptions and how they are (typically) used: 065 *<br> 066 * IllegalArgumentException - the location given as a parameter is not on the same strand as the location. 067 *<br> 068 * IndexOutOfBoundsException - often means the operation caused the location to span the origin, ie 069 * be partially on positive and partially on negative strand. 070 *<br> 071 * @author Hanno Hinsch 072 */ 073public class Location implements Iterable<Location> 074{ 075 private static final Logger logger = LoggerFactory.getLogger(App.class); 076 077 private int mStart; 078 private int mEnd; 079 080// /** 081// */ 082// private Location() 083// { 084// } 085 086 /** 087 * Construct new location from coordinates. 088 * See package description of coordinate format. 089 * @param start Origin 0 index of first symbol. 090 * @param end Origin 0 index of last symbol + 1. 091 * @throws IllegalArgumentException End is not after start, or location spans the origin 092 */ 093 public Location( int start, int end ) 094 { 095 mStart= start; 096 mEnd= end; 097 098 if( !isHealthy() ) 099 { 100 throw new IllegalArgumentException( "Improper location parameters: (" + start + "," + end + ")" ); 101 } 102 103 } 104 105 /** 106 * Clone other location. 107 * @param other The location to clone. 108 */ 109 public Location( Location other ) 110 { 111 mStart= other.mStart; 112 mEnd= other.mEnd; 113 114 assert isHealthy(): toString(); 115 } 116 117 public int getBegin(){ 118 if(isNegative()) 119 return mEnd; 120 else 121 return mStart; 122 } 123 124 public int getEnd(){ 125 if(isNegative()) 126 return mStart; 127 else 128 return mEnd; 129 } 130 131 132 /** 133 * Create location from "biocoordinates", as in GFF file. In biocoordinates, 134 * the start index of a range is represented in origin 1 (ie the very first index is 1, not 0), 135 * and end= start + length - 1. 136 * 137 * @param start Origin 1 index of first symbol. 138 * @param end Origin 1 index of last symbol. 139 * @param strand '+' or '-' or '.' ('.' is interpreted as '+'). 140 * @return Created location. 141 * @throws IllegalArgumentException strand must be '+', '-' or '.' 142 */ 143 public static Location fromBio( int start, int end, char strand ) 144 { 145 int s= start - 1; 146 int e= end; 147 148 if( !( strand == '-' || strand == '+' || strand == '.' )) 149 { 150 throw new IllegalArgumentException( "Strand must be '+', '-', or '.'" ); 151 } 152 153 if( strand == '-' ) 154 { 155 //negate 156 s= - end; 157 e= - ( start - 1); 158 } 159 160 return new Location( s, e ); 161 } 162 163 /** 164 * Create a location from MAF file coordinates, which represent negative 165 * strand locations as the distance from the end of the sequence. 166 * 167 * @param start Origin 1 index of first symbol. 168 * @param length Number of symbols in range. 169 * @param strand '+' or '-' or '.' ('.' is interpreted as '+'). 170 * @param totalLength Total number of symbols in sequence. 171 * @throws IllegalArgumentException Strand must be '+', '-', '.' 172 * 173 */ 174 public static Location fromBioExt( int start, int length, char strand, int totalLength ) 175 { 176 int s= start; 177 int e= s + length; 178 179 if( !( strand == '-' || strand == '+' || strand == '.' )) 180 { 181 throw new IllegalArgumentException( "Strand must be '+', '-', or '.'" ); 182 } 183 184 if( strand == '-' ) 185 { 186 s= s - totalLength; 187 e= e - totalLength; 188 } 189 190 return new Location( s, e ); 191 } 192 193 /** 194 * Get character representation of strand. 195 * 196 * @return '+' or '-' 197 */ 198 public char bioStrand() 199 { 200 return ( isNegative() )?'-':'+'; 201 } 202 203 /** 204 * Get start index, in biocoordinates. 205 * 206 * @return The origin 1 index of the first symbol in location. 207 */ 208 public int bioStart() 209 { 210 return plus().start() + 1; 211 } 212 213 /** 214 * Get end index, in biocoordinates. 215 * 216 * @return The origin 1 index of the final symbol in location. 217 */ 218 public int bioEnd() 219 { 220 return plus().end(); 221 } 222 223 224 225 /** 226 * Return location that is in same position on plus strand. If location is already 227 * on plus strand, just return the location unchanged. 228 * 229 * @return Location on plus strand. 230 */ 231 public Location plus() 232 { 233 if( isNegative() ) 234 { 235 return opposite(); 236 } 237 else 238 { 239 return this; 240 } 241 } 242 243 /** 244 * Return location that is in same position on negative strand. If location is already 245 * on negative strand, just return the location unchanged. 246 * 247 * @return Location on negative strand. 248 */ 249 public Location minus() 250 { 251 if( isNegative() ) 252 { 253 return this; 254 } 255 else 256 { 257 return opposite(); 258 } 259 } 260 261 262 /** 263 * Return the union. 264 * <br> 265 * 266 * @param other The location to join. 267 * @return The union is a range that starts at the lesser of the two starting indices and ends at the 268 * greater of the two ends. 269 * @throws IllegalArgumentException Locations are on opposite strands. 270 */ 271 public Location union( Location other ) 272 { 273 274 if( !isSameStrand( other )) 275 { 276 throw new IllegalArgumentException( "Locations are on opposite strands." ); 277 } 278 else 279 { 280 int start= (other.mStart < mStart)? other.mStart: mStart; 281 int end= (other.mEnd > mEnd)? other.mEnd: mEnd; 282 283 return new Location( start, end ); 284 } 285 286 } 287 288 /** 289 * Return the intersection, or null if no overlap. 290 * 291 * @param other 292 * The location to intersect. 293 * @return The maximal location that is contained by both. Returns null if 294 * no overlap! 295 * @throws IllegalArgumentException 296 * Locations are on opposite strands. 297 */ 298 public Location intersection(Location other) { 299 if (isSameStrand(other)) { 300 return intersect(mStart, mEnd, other.mStart, other.mEnd); 301 } else { 302 throw new IllegalArgumentException("Locations are on opposite strands."); 303 } 304 } 305 306 private Location intersect(int a1, int a2, int b1, int b2) { 307 if (a1 > b1) { 308 return intersect(b1, b2, a1, a2); 309 } 310 // Safe to assume a1 <= b1 311 if (b1 >= a2) { 312 // b starts after a ends 313 return null; 314 } else if (b1 < a2 && b2 <= a2) { 315 // b starts after a starts and ends before or at where a ends 316 return new Location(b1, b2); 317 } else if (b1 >= a1 && a2 <= b2) { 318 // b starts after a but extends after the end of a 319 return new Location(b1, a2); 320 } 321 return null; 322 } 323 324 325 /** 326 * Get starting index (origin 0). 327 * 328 * @return The start index. 329 */ 330 public int start() 331 { 332 return mStart; 333 } 334 335 /** 336 * Get the ending index. 337 * 338 * @return The index of last symbol + 1 (remember Java half-open coordinates). 339 */ 340 public int end() 341 { 342 return mEnd; 343 } 344 345 /** 346 * Get length of range. 347 * 348 * @return The length of the range (end - start). 349 */ 350 public int length() 351 { 352 return mEnd - mStart; 353 } 354 355 356 /** 357 * Enable a "sliding window" iteration over a location 358 * to use with Java's "for" loop construct. 359 * The returned helper object implements the Iterable interface; the windowSize and increment semantics are implemented 360 * by an underlying LocIterator. 361 * <br><br> 362 * For example, given a location variable "loc": 363 *<br> 364<pre> 365 //use window size of 3 and increment of +3 366 for( Location temp: loc.window( 3, 3 )) 367 { 368 //at each iteration, temp will be the location of the next 3 symbols 369 } 370</pre> 371 * 372 * @param windowSize The number of symbols to get on each iteration. 373 * @param increment The direction and number of symbols to advance at each iteration. 374 * @return An anonymous iterable object to use with Java's for( ... ) loop construct. 375 */ 376 public Iterable<Location> window( final int windowSize, final int increment ) 377 { 378 final Location loc= this; 379 380 //return iterable anonymous inner class 381 return new Iterable<Location> () 382 { 383 @Override 384 public LocIterator iterator() 385 { 386 return new LocIterator( loc, windowSize, increment ); 387 } 388 389 }; 390 } 391 392 /** 393 * Create a location iterator over this location with a window size of 1 and 394 * an increment of +1 (successive symbols from start to end). 395 * 396 * @return An iterator over a Location (a LocIterator object). 397 */ 398 @Override 399 public LocIterator iterator() 400 { 401 return new LocIterator( this, 1, 1 ); 402 } 403 404 /** 405 * Create a location iterator over this location, 406 * using specified window size and increment. 407 * 408 * @param windowSize The number of symbols to get on each iteration. 409 * @param increment The direction and number of symbols to advance at each iteration. 410 * @return An iterator over a Location (a LocIterator object). 411 */ 412 public LocIterator iterator( int windowSize, int increment ) 413 { 414 return new LocIterator( this, windowSize, increment ); 415 } 416 417 418 /** 419 * The part of this location before the specified position. If position is negative, 420 * count backwards from the end. 421 * <br><br> 422 * For position >= 0, return Location( start, start + position ). 423 * <br> 424 * For position < 0, return Location( start, end + position ). 425 * <br> 426 * @return New location from start of this location to directly before position. 427 * @param position Where the prefix ends. 428 * @throws IndexOutOfBoundsException Specified prefix is longer than location. 429 */ 430 public Location prefix( int position ) 431 { 432 int end; 433 if( position >= 0 ) 434 { 435 if( (mStart + position <= mEnd) ) 436 { 437 end= mStart + position; 438 } 439 else 440 { 441 throw new IndexOutOfBoundsException( "Specified prefix longer than location." ); 442 } 443 } 444 else 445 { 446 if( (mEnd + position > mStart)) 447 { 448 end= mEnd + position; 449 } 450 else 451 { 452 throw new IndexOutOfBoundsException( "Specified prefix longer than location." ); 453 } 454 } 455 456 return new Location( mStart, end ); 457 } 458 459 460 /** 461 * The part of this location after the specified position. If position is negative, count backwards 462 * from the end. 463 * <br><br> 464 * For position >= 0, return Location( start + position, end ). 465 * <br> 466 * For position < 0, return Location( end - position, end ). 467 * <br> 468 * @return New location from position to end of this location. 469 * @param position Where the suffix starts. 470 * @throws IndexOutOfBoundsException Specified suffix is longer than location. 471 */ 472 public Location suffix( int position ) 473 { 474 int start; 475 if( position >= 0 ) 476 { 477 if( mStart + position <= mEnd ) // Scooter willis when 60 + 60 = 120 no remainder 478 { 479 start= mStart + position; 480 } 481 else 482 { 483 throw new IndexOutOfBoundsException( "Specified suffix longer than location." ); 484 } 485 } 486 else 487 { 488 if( mEnd + position >= mStart ) 489 { 490 start= mEnd + position; 491 } 492 else 493 { 494 throw new IndexOutOfBoundsException( "Specified suffix longer than location." ); 495 } 496 } 497 498 return new Location( start, mEnd ); 499 } 500 501 /** 502 * The part of this location before the other location (not inclusive). 503 * 504 * @param other The other location. 505 * @return The part of this location before the other location. 506 * @throws IllegalArgumentException Locations are on opposite strands. 507 * @throws IndexOutOfBoundsException This location does not contain other location. 508 */ 509 public Location prefix( Location other ) 510 { 511 512 if( isSameStrand( other ) ) 513 { 514 if( other.mStart >= mStart ) 515 { 516 return new Location( mStart, (other.mStart < mEnd)? other.mStart: mEnd ); 517 } 518 else 519 { 520 //other is out of bounds -- no prefix 521 throw new IndexOutOfBoundsException( "Specified location not within this location." ); 522 } 523 } 524 else 525 { 526 throw new IllegalArgumentException( "Locations are on opposite strands." ); 527 } 528 } 529 530 /** 531 * The part of this location after the other location (not inclusive). 532 * 533 * @param other The other location. 534 * @return The part of this location after the other location. 535 * @throws IllegalArgumentException Locations are on opposite strands. 536 * @throws IndexOutOfBoundsException This location does not contain other location. 537 */ 538 public Location suffix( Location other ) 539 { 540 if( isSameStrand( other )) 541 { 542 if( other.mEnd <= mEnd ) 543 { 544 return new Location( (other.mEnd > mStart)? other.mEnd: mStart, mEnd ); 545 } 546 else 547 { 548 //other is out of bounds -- no suffix 549 throw new IndexOutOfBoundsException( "Specified location not within this location." ); 550 } 551 } 552 else 553 { 554 throw new IllegalArgumentException( "Locations are on opposite strands." ); 555 } 556 557 } 558 559 /** 560 * Return the adjacent location of specified length directly upstream of this location. 561 * 562 * @return Upstream location. 563 * @param length The length of the upstream location. 564 * @throws IndexOutOfBoundsException Specified length causes crossing of origin. 565 */ 566 public Location upstream( int length ) 567 { 568 if( length < 0 ) 569 { 570 throw new IllegalArgumentException( "Parameter must be >= 0; is=" + length ); 571 } 572 573 if( Math.signum( mStart - length) == Math.signum( mStart ) || 0 == Math.signum( mStart - length ) ) 574 { 575 return new Location(mStart - length, mStart ); 576 } 577 else 578 { 579 throw new IndexOutOfBoundsException( "Specified length causes crossing of origin: " + length + "; " + toString() ); 580 } 581 } 582 583 /** 584 * Return the adjacent location of specified length directly downstream of this location. 585 * 586 * @return The downstream location. 587 * @param length The length of the downstream location. 588 * @throws IndexOutOfBoundsException Specified length causes crossing of origin. 589 */ 590 public Location downstream( int length ) 591 { 592 if( length < 0 ) 593 { 594 throw new IllegalArgumentException( "Parameter must be >= 0; is=" + length ); 595 } 596 597 if( Math.signum( mEnd + length) == Math.signum( mEnd ) || 0 == Math.signum( mEnd + length ) ) 598 { 599 return new Location( mEnd, mEnd + length ); 600 } 601 else 602 { 603 throw new IndexOutOfBoundsException( "Specified length causes crossing of origin: " + length + "; " + toString() ); 604 } 605 606 } 607 608 609 610 /** 611 * Return distance between this location and the other location. 612 * 613 * Distance is defined only if both locations are on same strand. 614 * 615 * @param other The location to compare. 616 * @return The integer distance. Returns -1 if they overlap; 0 if directly adjacent. 617 * @throws IllegalArgumentException Locations are on opposite strands. 618 */ 619 public int distance( Location other ) 620 { 621 if( isSameStrand( other )) 622 { 623 if( overlaps( other )) 624 { 625 return -1; 626 } 627 else 628 { 629 return ( mEnd <= other.mStart )? (other.mStart - mEnd) : (mStart - other.mEnd); 630 } 631 } 632 else 633 { 634 throw new IllegalArgumentException( "Locations are on opposite strands." ); 635 } 636 } 637 638 /** 639 * Return percent overlap of two locations. 640 * 641 * @param other The location to compare. 642 * @return 100.0 * intersection(other).length() / this.length() 643 * @throws IllegalArgumentException Locations are on opposite strands. 644 */ 645 public double percentOverlap( Location other ) 646 { 647 if( length() > 0 && overlaps( other )) 648 { 649 return 100.0 * (((double) intersection( other ).length()) / (double) length()); 650 } 651 else 652 { 653 return 0; 654 } 655 } 656 657 /** 658 * Check if this location and other location overlap. 659 * 660 * @param other The location to compare. 661 * @return True if they overlap. 662 * @throws IllegalArgumentException Locations are on opposite strands. 663 */ 664 public boolean overlaps( Location other ) 665 { 666 if( isSameStrand( other )) 667 { 668 return !( mStart >= other.mEnd || mEnd <= other.mStart ); 669 } 670 else 671 { 672 throw new IllegalArgumentException( "Locations are on opposite strands." ); 673 } 674 } 675 676 /** 677 * Check if this location contains the other. 678 * 679 * @param other The location to compare. 680 * @return True if other is entirely contained by this location. 681 * @throws IllegalArgumentException Locations are on opposite strands. 682 */ 683 public boolean contains( Location other ) 684 { 685 if( isSameStrand( other )) 686 { 687 return ( mStart <= other.mStart && mEnd >= other.mEnd ); 688 } 689 else 690 { 691 throw new IllegalArgumentException( "Locations are on opposite strands." ); 692 } 693 } 694 695 696 /** 697 * Check if this location starts after the other location starts. 698 * The locations may overlap. 699 * 700 * @param other The location to compare. 701 * @return True if this starts after other. 702 * @throws IllegalArgumentException Locations are on opposite strands. 703 */ 704 public boolean startsAfter( Location other ) 705 { 706 if( isSameStrand( other )) 707 { 708 return mStart > other.mStart; 709 } 710 else 711 { 712 throw new IllegalArgumentException( "Locations are on opposite strands." ); 713 } 714 } 715 716 /** 717 * Check if this location starts before other location starts. 718 * The locations may overlap. 719 * 720 * @param other The location to compare. 721 * @return True if this starts before other. 722 * @throws IllegalArgumentException Locations are on opposite strands. 723 */ 724 public boolean startsBefore( Location other ) 725 { 726 if( isSameStrand( other )) 727 { 728 return mStart < other.mStart; 729 } 730 else 731 { 732 throw new IllegalArgumentException( "Locations are on opposite strands." ); 733 } 734 } 735 736 /** 737 * Check if this location ends after other location ends. 738 * The locations may overlap. 739 * 740 * @param other The location to compare. 741 * @return True if location ends after other. 742 * @throws IllegalArgumentException Locations are on opposite strands. 743 */ 744 public boolean endsAfter( Location other ) 745 { 746 if( isSameStrand( other ) ) 747 { 748 return mEnd > other.mEnd; 749 } 750 else 751 { 752 throw new IllegalArgumentException( "Locations are on opposite strands." ); 753 } 754 } 755 756 /** 757 * Check if this location ends before other location ends. 758 * The locations may overlap. 759 * 760 * @param other The location to compare. 761 * @return True if this ends before other. 762 * @throws IllegalArgumentException Locations are on opposite strands. 763 */ 764 public boolean endsBefore( Location other ) 765 { 766 if( isSameStrand( other ) ) 767 { 768 return mEnd < other.mEnd; 769 } 770 else 771 { 772 throw new IllegalArgumentException( "Locations are on opposite strands." ); 773 } 774 } 775 776 /** 777 * Check if this location is entirely after the other location (no overlap). 778 * 779 * @param other The location to compare. 780 * @return True if this is after other. 781 * @throws IllegalArgumentException Locations are on opposite strands. 782 */ 783 public boolean isAfter( Location other ) 784 { 785 if( isSameStrand( other ) ) 786 { 787 return mStart >= other.mEnd; 788 } 789 else 790 { 791 throw new IllegalArgumentException( "Locations are on opposite strands." ); 792 } 793 } 794 795 /** 796 * Check if this location is entirely before other location (no overlap). 797 * 798 * @param other The location to compare. 799 * @return True if this is before other. 800 * @throws IllegalArgumentException Locations are on opposite strands. 801 */ 802 public boolean isBefore( Location other ) 803 { 804 if( isSameStrand( other ) ) 805 { 806 return mEnd <= other.mStart; 807 } 808 else 809 { 810 throw new IllegalArgumentException( "Locations are on opposite strands." ); 811 } 812 } 813 814 /** 815 * Check if location is on negative strand. 816 * Note that Location( 0, 0 ) is by construction defined to be on the 817 * positive strand. 818 * 819 * @return True if on negative (reverse) strand. 820 */ 821 public boolean isNegative() 822 { 823 return ( mStart <= 0 && mEnd <= 0 ); 824 } 825 826 /** 827 * Return location that is in same position on opposite strand. 828 * 829 * @return Location on opposite strand. 830 */ 831 public Location opposite() 832 { 833 return new Location( - mEnd, - mStart ); 834 } 835 836 /** 837 * Check if this location is on same strand as other location. 838 * 839 * @param other The location to compare. 840 * @return True if on same strand. 841 */ 842 public boolean isSameStrand( Location other ) 843 { 844 return ( isNegative() && other.isNegative() ) || ( !isNegative() && !other.isNegative() ); 845 } 846 847 848 /** 849 * Return a string representation of location. 850 * 851 * @return Text string. 852 */ 853 @Override 854 public String toString() 855 { 856 return new String( "[L=" + (mEnd - mStart) + "; S=" + mStart + "; E=" + mEnd +"]" ); 857 } 858 859 /* (non-Javadoc) 860 * @see java.lang.Object#hashCode() 861 */ 862 @Override 863 public int hashCode() { 864 final int prime = 31; 865 int result = 1; 866 result = prime * result + mEnd; 867 result = prime * result + mStart; 868 return result; 869 } 870 871 /* (non-Javadoc) 872 * @see java.lang.Object#equals(java.lang.Object) 873 */ 874 @Override 875 public boolean equals(Object obj) { 876 if (this == obj) 877 return true; 878 if (obj == null) 879 return false; 880 if (getClass() != obj.getClass()) 881 return false; 882 Location other = (Location) obj; 883 if (mEnd != other.mEnd) 884 return false; 885 if (mStart != other.mStart) 886 return false; 887 return true; 888 } 889 890 /** 891 * 892 */ 893 private boolean isHealthy() 894 { 895 return ( mStart <= mEnd ) && (( mStart <= 0 && mEnd <= 0 ) || (mStart >= 0 && mEnd >= 0)); 896 } 897 898 //shorthand for testing 899 static private Location L( int s, int e ) 900 { 901 return new Location( s, e ); 902 } 903 904 @SuppressWarnings("unused") 905 static private Location R( int s, int e ) 906 { 907 return new Location( -e, -s ); 908 } 909 910 911 /** 912 * @deprecated 913 */ 914 @Deprecated 915 @SuppressWarnings("unused") 916 public static void main(String[] args ) 917 throws Exception 918 { 919 Location p3_7= new Location( 3, 7 ); 920 Location p16_19= new Location( 16, 19 ); 921 Location p15_19= new Location( 15, 19 ); 922 Location p15_16= new Location( 15, 16 ); 923 Location p10_17= new Location( 10, 17 ); 924 Location p10_12= new Location( 10, 12 ); 925 Location p14_17= new Location( 14, 17 ); 926 Location p14_14= new Location( 14, 14 ); 927 928 Location r13_17= new Location( 13, 17 ); 929 Location r21_25= new Location( 21, 25 ); 930 931 Location r4_7= new Location( 4, 7 ); 932 Location r2_5= new Location( 2, 5 ); 933 Location r0_3= new Location( 0, 3 ); 934 Location r5_8= new Location( 5, 8 ); 935 936 //distance 937 assert L(14,14).distance( L(3,7) ) == 7; 938 assert L(3,7).distance( L(14,14) ) == 7; 939 assert L(1,4).distance( L(7, 10) ) == 3; 940 941 //union 942 assert p10_12.union( p14_17 ).equals( p10_17 ); 943 assert p14_17.union( p10_12 ).equals( p10_17 ); 944 assert p15_19.union( p15_16).equals( p15_19 ); 945 946 //intersection 947 assert r13_17.union( r21_25 ).intersection( r21_25 ).equals( new Location( 21, 25 )); 948 949 950 //isBefore 951 assert r2_5.isBefore( r5_8 ); 952 assert !r2_5.isBefore( r4_7 ); 953 954 //isAfter 955 assert r5_8.isAfter( r2_5 ); 956 assert !r5_8.isAfter( r4_7 ); 957 958 //contains 959 assert p15_19.contains( p16_19 ); 960 961 //overlaps 962 assert r2_5.overlaps( r4_7 ); 963 assert r2_5.overlaps( r0_3 ); 964 assert !r5_8.overlaps( r2_5 ); 965 assert !r2_5.overlaps( r5_8 ); 966 967 968 //prefix 969 assert L(2,20).prefix(1).equals( L(2,3)); 970 assert L(2,20).prefix(-1).equals( L(2,19)); 971 assert L(2,20).prefix( L(10,12)).equals( L(2,10)); 972 973 //suffix 974 assert L(2,20).suffix(1).equals( L(3,20)); 975 assert L(2,20).suffix(-1).equals( L(19,20)); 976 assert L(2,20).suffix( L(10,12)).equals( L(12,20)); 977 978 979 //upstream 980 //downstream 981 982 //startsBefore 983 //startsAfter 984 //endsBefore 985 //endsAfter 986 987 //equals 988 989 //percentoverlap 990 991 992 //plus 993 //minus 994 //isNegative 995 //oppposite 996 997 //fromBio, etc. 998 999 logger.info("JavaGene.Location Passed."); 1000 } 1001 1002}