001 /** 002 * Copyright (C) 2010 The Roslin Institute <contact andy.law@roslin.ed.ac.uk> 003 * 004 * This file is part of the Ensembl Java API demonstration project developed by the 005 * Bioinformatics Group at The Roslin Institute, The Royal (Dick) School of 006 * Veterinary Studies, University of Edinburgh. 007 * 008 * This is free software: you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (version 3) as published by 010 * the Free Software Foundation. 011 * 012 * This software is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * in this software distribution. If not, see <http://www.gnu.org/licenses/gpl-3.0.html/>. 019 */ 020 021 package uk.ac.roslin.ensembl.model; 022 023 import java.io.Serializable; 024 import java.util.TreeSet; 025 026 /** 027 * 028 * @author tpaterso 029 */ 030 public class CoordinateSet extends TreeSet<Coordinate> implements Serializable { 031 032 public CoordinateSet() { 033 } 034 035 036 public Integer getStart() { 037 Integer out = null; 038 039 if ( !this.isEmpty()) { 040 out = this.first().getStart(); 041 } 042 043 return out; 044 } 045 046 public Integer getEnd() { 047 Integer out = null; 048 049 if ( !this.isEmpty()) { 050 051 out = this.last().getEnd(); 052 053 for (Coordinate c : this) { 054 if (c.getEnd()>out) { 055 out = c.getEnd(); 056 } 057 } 058 } 059 return out; 060 } 061 062 public Coordinate getRange() { 063 Coordinate out = null; 064 if ( !this.isEmpty()) { 065 066 out = new Coordinate(this.getStart(),this.getEnd() ,1); 067 068 } 069 return out; 070 } 071 072 public CoordinateSet getGaps(){ 073 CoordinateSet gaps = new CoordinateSet(); 074 075 076 Integer rangeEnd = this.getEnd(); 077 Integer currentPosition = this.getStart(); 078 079 for (Coordinate c : this) { 080 081 Integer s = c.getStart(); 082 Integer e = c.getEnd(); 083 084 //if we're already past the extent of this region 085 if (currentPosition>=e) { 086 continue; 087 } 088 089 if (s>currentPosition) { 090 091 Coordinate newC = new Coordinate(currentPosition, s-1, 1); 092 gaps.add(newC); 093 } 094 095 if (e>=rangeEnd) { 096 break; 097 } 098 099 100 currentPosition = e+1; 101 102 } 103 104 return gaps; 105 } 106 107 public Boolean containsCoordinateWithoutGaps(Coordinate test) { 108 Boolean out = false; 109 110 Integer testBegin = test.getStart(); 111 Integer testEnd = test.getEnd(); 112 113 if (testBegin<this.getStart() || testEnd>this.getEnd()) { 114 out = false; 115 } else if (this.getGaps().isEmpty()) { 116 out = true; 117 } else { 118 119 out = true; 120 for(Coordinate c: this.getGaps()) { 121 if(test.overlaps(c)) { 122 out = false; 123 break; 124 } 125 } 126 127 } 128 return out; 129 } 130 131 public CoordinateSet getUncoveredRegions(Coordinate test) { 132 133 CoordinateSet gaps = new CoordinateSet(); 134 135 if (this.isEmpty()) { 136 gaps.add(test); 137 return gaps; 138 } 139 140 if (this.containsCoordinateWithoutGaps(test)) { 141 return gaps; 142 } 143 144 if (!this.getRange().overlaps(test)) { 145 gaps.add(test); 146 return gaps; 147 } 148 149 Integer testBegin = test.getStart(); 150 Integer testEnd = test.getEnd(); 151 Integer thisBegin = this.getStart(); 152 Integer thisEnd = this.getEnd(); 153 154 CoordinateSet thisGaps = this.getGaps(); 155 156 //overlap at start 157 if (testBegin<thisBegin) { 158 Coordinate newC = new Coordinate(testBegin, thisBegin-1, 1); 159 gaps.add(newC); 160 } 161 162 //overlap at end 163 if (testEnd>thisEnd) { 164 Coordinate newC2 = new Coordinate(thisEnd+1, testEnd, 1); 165 gaps.add(newC2); 166 } 167 168 for (Coordinate cd : thisGaps) { 169 170 //this gap completely contains the test Coordinate 171 if (test.liesWithinCoordinate(cd)) { 172 gaps.add(test); 173 break; 174 } 175 176 // this gap lies completely within the range 177 else if (cd.liesWithinCoordinate(test)) { 178 gaps.add(cd); 179 } 180 181 else if (cd.overlaps(test)) { 182 183 gaps.add(cd.getOverlap(test)); 184 } 185 186 } 187 188 return gaps; 189 } 190 191 }