/*
* Copyright (c) 2014 Oculus Info Inc. http://www.oculusinfo.com/
*
* Released under the MIT License.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.oculusinfo.binning.impl;
import java.util.*;
import com.oculusinfo.binning.TileData;
import com.oculusinfo.binning.TileDataMetadataImpl;
import com.oculusinfo.binning.TileIndex;
/**
* This class represents a tile's worth of data as a dense array.
*
* It also contains the tile index describing the position of the tile.
*
* This object is not necessarily immutable.
*
* @author nkronenfeld
*
* @param <T> The type of data stored in the bins of this tile.
*/
public class DenseTileData<T> extends TileDataMetadataImpl<T> implements TileData<T> {
private static final long serialVersionUID = 1L;
private TileIndex _definition;
private List<T> _data;
private T _default;
// No-argument constructor, really just for use by Kryo, but we call it from
// the main constructor just to get rid of the warning.
private DenseTileData() {
super();
}
/**
* Construct a dense tile data object for a particular tile. All entries are initialized to null.
*
* @param definition The index of the tile whose data is to be collected by this object.
*/
public DenseTileData(TileIndex definition) {
this(definition, (T) null);
}
/**
* Construct a dense tile for a particular tile index. All entries are initialized to the given default value.
*
* @param definition The index of the tile whose data is to be collected by this object.
* @param defaultValue The default value of each bin
*/
public DenseTileData(TileIndex definition, T defaultValue) {
this();
_definition = definition;
_data = new ArrayList<T>(_definition.getXBins()
* _definition.getYBins());
_default = defaultValue;
for (int x = 0; x < _definition.getXBins(); ++x) {
for (int y = 0; y < _definition.getYBins(); ++y) {
_data.add(_default);
}
}
}
/**
* Construct a tile for a particular tile index, with preset data. Note the passed-in preset data is used as is,
* not copied.
*
* @param definition
* The index of the tile whose data is to be represented by this
* object.
* @param tileData
* The data for this tile
*/
public DenseTileData(TileIndex definition, List<T> tileData) {
this(definition, null, tileData);
}
/**
* Construct a tile for a particular tile index, with preset data. Note the passed-in preset data is used as is,
* not copied.
*
* @param definition
* The index of the tile whose data is to be represented by this
* object.
* @param defaultValue
* The default value to use for undefined bins; not used, since all bins are defined, but needed
* for some edge cases anyway (such as slicing, when a resultant slice ends up being sparse)
* @param tileData
* The data for this tile
*/
public DenseTileData(TileIndex definition, T defaultValue, List<T> tileData) {
_definition = definition;
int requiredLength = _definition.getXBins() * _definition.getYBins();
if (tileData.size() != requiredLength) {
throw new IllegalArgumentException(
"Data was of the wrong length. Should have been "
+ requiredLength
+ ", was "
+ tileData.size());
}
_data = tileData;
_default = defaultValue;
}
/** {@inheritDoc} */
@Override
public TileIndex getDefinition() {
return _definition;
}
/** {@inheritDoc} */
@Override
public T getDefaultValue () {return _default;}
public void setDefaultValue (T defaultValue) {
_default = defaultValue;
}
/** {@inheritDoc} */
@Override
public void setBin(int x, int y, T value) {
if (x < 0 || x >= _definition.getXBins()) {
throw new IllegalArgumentException("Bin x index is outside of tile's valid bin range");
}
if (y < 0 || y >= _definition.getYBins()) {
throw new IllegalArgumentException("Bin y index is outside of tile's valid bin range");
}
_data.set(x + y * _definition.getXBins(), value);
}
/** {@inheritDoc} */
@Override
public T getBin(int x, int y) {
if (x < 0 || x >= _definition.getXBins()) {
throw new IllegalArgumentException("Bin x index is outside of tile's valid bin range");
}
if (y < 0 || y >= _definition.getYBins()) {
throw new IllegalArgumentException("Bin y index is outside of tile's valid bin range");
}
return _data.get(x + y * _definition.getXBins());
}
/**
* Get all the data for this tile. While this data is row-by-row, use of
* this method is intended for users using the data as a block (such as for
* I/O) without any need to know what the data itself is - the only thing
* most users should know is that the format output here is the same one
* expected by {@link #DenseTileData(TileIndex, List)}.
*/
public List<T> getData () {
return Collections.unmodifiableList(_data);
}
/**
* Get all the data for a given tile, in a form that can be used to initialize a dense tile.
*/
static public <T> List<T> getData (TileData<T> tile) {
if (tile instanceof DenseTileData) {
return ((DenseTileData<T>) tile).getData();
} else {
List<T> result = new ArrayList<>();
TileIndex idx = tile.getDefinition();
for (int y = 0; y < idx.getYBins(); ++y) {
for (int x = 0; x < idx.getXBins(); ++x) {
result.add(tile.getBin(x, y));
}
}
return result;
}
}
@Override
public String toString () {
return "<dense-tile index=\""+getDefinition()+"\", default=\""+_default+"\"/>";
}
}