// $Id: RangeMap.java,v 1.1 2006/05/20 17:02:03 Sasha Buzko Exp $ // // Copyright (c) 2000-2002 San Diego Supercomputer Center (SDSC), // a facility operated jointly by the University of California, // San Diego (UCSD) and General Atomics, San Diego, California, USA. // // Users and possessors of this source code are hereby granted a // nonexclusive, royalty-free copyright and design patent license to // use this code in individual software. License is not granted for // commercial resale, in whole or in part, without prior written // permission from SDSC. This source is provided "AS IS" without express // or implied warranty of any kind. // // For further information, please see: http://mbt.sdsc.edu // // History: // $Log: RangeMap.java,v $ // Revision 1.1 2006/05/20 17:02:03 Sasha Buzko // Updated version // // Revision 1.1 2006/04/30 20:13:59 Sasha Buzko // New version of the app // // Revision 1.1 2006/04/15 19:42:26 Sasha Buzko // Initial commit // // Revision 1.1 2005/11/13 04:35:07 Administrator // *** empty log message *** // // Revision 1.10 2003/10/06 23:41:17 moreland // Corrected typo in exception string. // // Revision 1.9 2003/10/03 23:58:40 moreland // Added collapseOn flag and get/set methods. // // Revision 1.8 2003/04/28 21:58:34 moreland // Added setRangeValue method. // // Revision 1.7 2003/04/25 17:27:07 moreland // Moved exhaustive collapse code into a "collapse" method. // The "append" method now keeps the last range automatically/cheaply collapsed. // // Revision 1.6 2003/04/24 21:01:55 moreland // Added getRange method that returns a COPY of an (int[]) range. // // Revision 1.5 2003/04/24 17:16:25 moreland // Added safe range walking methods. // Added append and remove methods. // // Revision 1.4 2003/04/24 00:19:59 moreland // Removed outdated StructureComponentID references. // // Revision 1.3 2003/04/23 22:56:57 moreland // Fixed off-by-one error at the end of the range. // Added "text diagrams" to better document the setRange method. // Added code to collapse/join ranges after a setRange is performed. // // Revision 1.2 2003/03/19 22:25:23 moreland // Moved binary search code out of getValue into new private findRange method. // Added public getContiguousValue method to do efficient range value searches. // // Revision 1.1 2003/02/27 21:03:59 moreland // First version. // // Revision 1.0 2003/02/12 18:33:20 moreland // First implementation/check-in. // package edu.sdsc.mbt.util; import java.util.Hashtable; import java.util.Vector; /** * The RangeMap class provides a means to map an integer value * (such as an index) that falls in a fixed range (min and max) * to application-supplied Objects. This can be used to efficiently * associate properties (colors, radii, etc) to a numbered set of objects. *
* @author John L. Moreland
*/
public class RangeMap
{
/**
* The minimum value for the spaned range.
*/
private int rangeMin = 0;
/**
* The maximum value for the spaned range.
*/
private int rangeMax = 0;
/**
* The sorted range tuple objects (ie: int[2]).
*/
private Vector ranges = new Vector( );
/**
* The value objects keyed by range tuple objects (ie: int[2]).
*/
private Hashtable values = new Hashtable( );
/**
* The transparency changed.
*/
private Object defaultValue = null;
/**
* Flag to enable/disable collapse feature.
*/
private boolean collapseOn = true;
//
// Constructor.
//
/**
* Construct a RangeMap object with the specified min, max, and
* default value.
*/
public RangeMap( int min, int max, Object defaultObject )
{
reset( min, max, defaultObject );
}
//
// Public RangeMap methods.
//
/**
* Get the minimum range index.
*/
public int getMin( )
{
return rangeMin;
}
/**
* Get the maximum range index.
*/
public int getMax( )
{
return rangeMax;
}
/**
* Set flag to enable/disable collapse feature.
*/
public void setCollapseOn( boolean state )
{
collapseOn = state;
}
/**
* Get flag to enable/disable collapse feature.
*/
public boolean getCollapseOn( )
{
return collapseOn;
}
/**
* Assign an object value to the specified range.
*/
public void setRange( int start, int stop, Object value )
{
// Make sure that the parameters are valid.
if ( start > stop )
throw new IllegalArgumentException( "stop must be >= start" );
if ( start < rangeMin )
throw new IllegalArgumentException( "start must be >= min" );
if ( stop > rangeMax )
throw new IllegalArgumentException( "stop must be <= max" );
if ( value == null )
throw new IllegalArgumentException( "value was null" );
int newRange[] = { start, stop };
boolean haveAddedNewRange = false;
/*
System.err.println( "DEBUG: before setRange of " + newRange[0] + " - " + newRange[1] );
System.err.print( " " );
for ( int i=0; i
* This method is useful for efficiently determining if an entire index range maps
* contiguously (unbroken) to the same value object.
*
* Example, in order to test that a given chain is selected, simply pass the
* chain's start atom index and end atom index to this method. If the chain is
* selected, the return value should be a boolean "True" object. If all atoms
* in the given chain are not all selected, then this method would return null.
*/
public Object getContiguousValue( int start_index, int end_index )
{
int rangeIndex = findRange( start_index );
int[] range = (int[]) ranges.elementAt( rangeIndex );
if ( range == null ) return null;
if ( (end_index >= range[0]) && (end_index <= range[1]) )
return values.get( range );
return null;
}
/**
* Get the number of ranges currently assigned to this map.
*/
public int getRangeCount( )
{
return ranges.size( );
}
/**
* Get the value currently associated with the given rangeIndex.
*/
public Object getRangeValue( int rangeIndex )
{
int[] range = (int[]) ranges.elementAt( rangeIndex );
return values.get( range );
}
/**
* Set the value currently associated with the given rangeIndex.
*/
public void setRangeValue( int rangeIndex, Object value )
{
if ( value == null )
throw new IllegalArgumentException( "null value" );
int[] range = (int[]) ranges.elementAt( rangeIndex );
values.put( range, value );
}
/**
* Get the range currently associated with the given rangeIndex.
*/
public int[] getRange( int rangeIndex )
{
int[] range = (int[]) ranges.elementAt( rangeIndex );
// Copy it so the user can't change our copy out from under us!
int[] result = { range[0], range[1] };
return result;
}
/**
* Get the startIndex for the given rangeIndex.
*/
public int getRangeStart( int rangeIndex )
{
int[] range = (int[]) ranges.elementAt( rangeIndex );
return range[0];
}
/**
* Get the endIndex for the given rangeIndex.
*/
public int getRangeEnd( int rangeIndex )
{
int[] range = (int[]) ranges.elementAt( rangeIndex );
return range[1];
}
/**
* Append a new value (increasing the range maximum by 1).
*/
public void append( Object value )
{
if ( value == null )
throw new IllegalArgumentException( "null value" );
rangeMax++;
// If last range value matches the new value, just extend last range.
// This keeps the last/appended range automatically "collapsed".
int[] lastRange = (int[]) ranges.elementAt( ranges.size()-1 );
Object lastValue = values.get( lastRange );
if ( lastValue == value )
{
lastRange[1] += 1;
}
else
{
int range[] = { rangeMax, rangeMax };
ranges.add( range );
values.put( range, value );
}
}
/**
* Remove an index (decreasing the range maximum by 1 and causing
* all subsequent index values to be decreased by 1).
*/
public void remove( int index )
{
if ( (index < rangeMin) || (index > rangeMax) )
throw new IllegalArgumentException( "index out of bounds" );
int rangeIndex = findRange( index );
int[] range = (int[]) ranges.elementAt( rangeIndex );
if ( range[0] == range[1] )
{
values.remove( range );
ranges.remove( rangeIndex );
}
else
{
range[1] -= 1;
rangeIndex++;
}
// Simply subtract 1 from the remaining range start/end tuples.
int rangeCount = ranges.size( );
for ( int r=rangeIndex; r