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.bio.symbol; 022 023import java.util.ArrayList; 024import java.util.Collections; 025import java.util.Iterator; 026import java.util.List; 027import java.util.ListIterator; 028 029import org.biojava.bio.BioException; 030 031/** 032 * Produced by LocationTools as a result of union operations. 033 * It's a <code>RangeLocation</code> and can be used 034 * as such but it also retains knowledge of which individual components made 035 * it up. None of the methods of RangeLocation are overridden only new methods 036 * have been added to get the subcomponents.</p> 037 * 038 * <p>For example a union operation between the following locations 039 * [1,20],[27,45],[30-70] will produce a <code>CompoundLocation</code> 040 * like this: {[1,20],[27,70]}, the last two locations have been merged into a 041 * <code>MergeLocation</code> which contains the two subcomponents.</p> 042 * 043 * <p>Copyright: Copyright (c) 2002</p> 044 * <p>Company: AgResearch</p> 045 * @author Mark Schreiber 046 * @author Francois Pepin 047 * @version 1.0 048 */ 049 050public class MergeLocation extends RangeLocation { 051 List componentLocations; 052 053 /** 054 * Private constructor, use static method mergeLocations to make an 055 * instance of this class 056 * @param min the minimum point spanned by the location 057 * @param max the maximum point spanned by the location 058 * @param componentLocations the locations that make up this. 059 */ 060 private MergeLocation(int min, int max, List componentLocations){ 061 super(min, max); 062 this.componentLocations = componentLocations; 063 } 064 065 /** 066 * Gets the component locations that make up this one 067 * 068 * @param recurse if true the method lists the component locations of all 069 * nested <code>MergedLocation</code>s. 070 * 071 * @return a <code>List</code> of <code>Location</code>s. 072 */ 073 public List getComponentList(boolean recurse){ 074 if(! recurse) 075 return componentLocations; 076 077 else{ 078 List l = new ArrayList(); 079 for(Iterator i = componentLocations.iterator(); i.hasNext();){ 080 Object o = i.next(); 081 082 //what if its decorated? 083 if(o instanceof AbstractLocationDecorator){ 084 o = ((AbstractLocationDecorator)o).getWrapped(); 085 } 086 087 if (o instanceof MergeLocation) { 088 List ll = ((MergeLocation)o).getComponentList(true); 089 l.addAll(ll); 090 } 091 else { 092 l.add(o); 093 } 094 095 } 096 097 return l; 098 } 099 } 100 101 /** 102 * @return A <code>ListIterator</code> over the component locations. The iterator 103 * does not recurse nested MergeLocations. 104 */ 105 public ListIterator componentLocationIterator(){ 106 return componentLocations.listIterator(); 107 } 108 109 /** 110 * Static Factory method for getting an instance of a <code>MergeLocation</code> 111 * @param componentLocations the <code>Locations to Merge</code> 112 * @return the merged location 113 * @throws BioException if the list contains objects that are not <code>Locations</code> 114 * or if the locations don't represent a contiguous block. Use <code> 115 * LocationTools.union()</code> if you want to merge discontinuous blocks. 116 */ 117 public static MergeLocation mergeLocations(List componentLocations) 118 throws BioException{ 119 120 Collections.sort(componentLocations, Location.naturalOrder); 121 122 int lastMax = -1; 123 int lastMin = -1; 124 125 int min = Integer.MAX_VALUE; 126 int max = 0; 127 128 for (Iterator i = componentLocations.iterator(); i.hasNext(); ) { 129 Object item = i.next(); 130 131 if(!( item instanceof Location)){ 132 throw new BioException( 133 "All members of the component locations list must be Location objects"); 134 } 135 136 Location loc = (Location)item; 137 138 //make sure blocks are contiguous 139 if(lastMin != -1 && lastMax != -1){ 140 if(!(loc.getMin()+1 <= lastMax)){ 141 //blocks aren't contiguous 142 throw new BioException( 143 "All members of the component locations list must be contiguous"); 144 } 145 } 146 147 //determine what the min and max should be for the MergeLocation 148 if (loc.getMin() < min) { 149 min = loc.getMin(); 150 } 151 if (loc.getMax() > max) { 152 max = loc.getMax(); 153 } 154 155 lastMin = loc.getMin(); lastMax = loc.getMax(); 156 } 157 158 return new MergeLocation(min, max, componentLocations); 159 } 160 161 public static MergeLocation mergeLocations(Location locA, 162 Location locB) throws BioException{ 163 164 int min = Math.min(locA.getMin(), locB.getMin()); 165 int max = Math.max(locA.getMax(), locB.getMax()); 166 167 List l = new ArrayList(2); 168 l.add(locA); 169 l.add(locB); 170 171 return new MergeLocation(min, max, l); 172 } 173}