package org.geotools.coverage.io.domain;
import java.awt.Rectangle;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.geotools.resources.i18n.ErrorKeys;
import org.geotools.resources.i18n.Errors;
/**
* A class describing the desired layout of an <code>OpImage</code>.
*
* <p> The <code>RasterLayout</code> class encapsulates three types of information about
* an image:
*
* <ul>
* <li> The image bounds, comprising the min X and Y coordinates,
* image width, and image height;
* <li> The tile grid layout, comprising the tile grid X and Y offsets,
* the tile width, and the tile height; and
* <li> The <code>SampleModel</code> and <code>ColorModel</code> of the image.
* </ul>
*
* <p> Each of these parameters may be set individually, or left unset.
* An unset parameter will cause the corresponding value of a given
* <code>RenderedImage</code> to be used. For example, the code:
*
* <pre>
* RasterLayout layout;
* RenderedImage im;
*
* int width = layout.getTileWidth(im);
* </pre>
*
* will return the tile width of the <code>RasterLayout</code> if it is set,
* or the tile width of the image <code>im</code> if it is not.
*
* <p> <code>RasterLayout</code> objects are primarily intended to be passed as part
* of the <code>renderingHints</code> argument of the <code>create()</code> method of
* <code>RenderedImageFactory</code>. The <code>create()</code> method may remove parameter
* settings that it cannot deal with, prior to passing the
* <code>RasterLayout</code> to any <code>OpImage</code> constructors. New <code>OpImage</code> subclasses
* are not required to accept an <code>RasterLayout</code> parameter, but most will
* at least need to synthesize one to be passed up the constructor
* chain.
*
* <p> Methods that modify the state of an <code>RasterLayout</code> return a reference
* to 'this' following the change. This allows multiple modifications to
* be made in a single expression. This provides a way of modifying an
* <code>RasterLayout</code> within a superclass constructor call.
*
*
* @source $URL: http://svn.osgeo.org/geotools/branches/2.7.x/build/maven/javadoc/../../../modules/unsupported/coverage-experiment/coverage-api/src/main/java/org/geotools/coverage/io/domain/RasterLayout.java $
*/
public class RasterLayout extends Object implements Cloneable, Serializable {
/**
*
*/
private static final long serialVersionUID = 1606060744626516740L;
/** A bitmask to specify the validity of <code>minX</code>. */
public static final int MIN_X_MASK = 0x1;
/** A bitmask to specify the validity of <code>minY</code>. */
public static final int MIN_Y_MASK = 0x2;
/** A bitmask to specify the validity of <code>width</code>. */
public static final int WIDTH_MASK = 0x4;
/** A bitmask to specify the validity of <code>height</code>. */
public static final int HEIGHT_MASK = 0x8;
/** A bitmask to specify the validity of <code>tileGridXOffset</code>. */
public static final int TILE_GRID_X_OFFSET_MASK = 0x10;
/** A bitmask to specify the validity of <code>tileGridYOffset</code>. */
public static final int TILE_GRID_Y_OFFSET_MASK = 0x20;
/** A bitmask to specify the validity of <code>tileWidth</code>. */
public static final int TILE_WIDTH_MASK = 0x40;
/** A bitmask to specify the validity of <code>tileHeight</code>. */
public static final int TILE_HEIGHT_MASK = 0x80;
/** The image's minimum X coordinate. */
int minX = 0;
/** The image's minimum Y coordinate. */
int minY = 0;
/** The image's <code>width</code>. */
int width = 0;
/** The image's height. */
int height = 0;
/** The X coordinate of tile (0, 0). */
int tileGridXOffset = 0;
/** The Y coordinate of tile (0, 0). */
int tileGridYOffset = 0;
/** The width of a tile. */
int tileWidth = 0;
/** The height of a tile. */
int tileHeight = 0;
/** The 'or'-ed together valid bitmasks. */
protected int validMask = 0;
/** Constructs an <code>RasterLayout</code> with no parameters set. */
public RasterLayout() {}
/**
* Constructs an <code>RasterLayout</code> with all its parameters set.
* The <code>sampleModel</code> and <code>colorModel</code> parameters are ignored if null.
*
* @param minX the image's minimum X coordinate.
* @param minY the image's minimum Y coordinate.
* @param width the image's width.
* @param height the image's height.
* @param tileGridXOffset the X coordinate of tile (0, 0).
* @param tileGridYOffset the Y coordinate of tile (0, 0).
* @param tileWidth the width of a tile.
* @param tileHeight the height of a tile.
* @param sampleModel the image's <code>SampleModel</code>.
* @param colorModel the image's <code>ColorModel</code>.
*/
public RasterLayout(int minX,
int minY,
int width,
int height,
int tileGridXOffset,
int tileGridYOffset,
int tileWidth,
int tileHeight) {
setMinX(minX);
setMinY(minY);
setWidth(width);
setHeight(height);
setTileGridXOffset(tileGridXOffset);
setTileGridYOffset(tileGridYOffset);
setTileWidth(tileWidth);
setTileHeight(tileHeight);
}
/**
* Constructs an <code>RasterLayout</code> with only the image dimension
* parameters set.
*
* @param minX the image's minimum X coordinate.
* @param minY the image's minimum Y coordinate.
* @param width the image's width.
* @param height the image's height.
*/
public RasterLayout(int minX,
int minY,
int width,
int height) {
setMinX(minX);
setMinY(minY);
setWidth(width);
setHeight(height);
}
/**
* Constructs an <code>RasterLayout</code> with all its parameters set
* to equal those of a given <code>RenderedImage</code>.
*
* @param im a <code>RenderedImage</code> whose layout will be copied.
*/
public RasterLayout(RenderedImage im) {
this(im.getMinX(),
im.getMinY(),
im.getWidth(),
im.getHeight(),
im.getTileGridXOffset(),
im.getTileGridYOffset(),
im.getTileWidth(),
im.getTileHeight());
}
public RasterLayout(Rectangle bounds) {
if(bounds==null)
throw new NullPointerException(Errors.format(ErrorKeys.NULL_ARGUMENT_$1, "bounds"));
this.height=bounds.height;
this.width=bounds.width;
this.minX=bounds.x;
this.minY=bounds.y;
}
/**
* Returns the 'or'-ed together bitmask indicating parameter validity.
* To determine the validity of a particular parameter, say tile width,
* test <code>getValidMask() & RasterLayout.TILE_WIDTH_MASK</code>
* against <code>0</code>.
*
* <p> To test a single mask value or set of mask values, the
* convenience method isValid() may be used.
*
* @return an int that is the logical 'or' of the valid mask values,
* with a '1' bit representing the setting of a value.
*/
public int getValidMask() {
return validMask;
}
/**
* Returns <code>true</code> if all the parameters specified by the argument are set.
*
* @param mask a bitmask.
* @return a boolean truth value.
*/
public final boolean isValid(int mask) {
return (validMask & mask) == mask;
}
/**
* Sets selected bits of the valid bitmask. The valid bitmask is
* set to the logical 'or' of its prior value and a new value.
*
* @param mask the new mask value to be 'or'-ed with the prior value.
* @return a reference to this <code>RasterLayout</code> following the change.
*/
public RasterLayout setValid(int mask) {
validMask |= mask;
return this;
}
/**
* Clears selected bits of the valid bitmask. The valid bitmask
* is set to the logical 'and' of its prior value and the negation
* of the new mask value. This effectively subtracts from the set of
* valid parameters.
*
* @param mask the new mask value to be negated and 'and'-ed with
* the prior value.
* @return a reference to this <code>RasterLayout</code> following the change.
*/
public RasterLayout unsetValid(int mask) {
validMask &= ~mask;
return this;
}
/**
* Marks the parameters dealing with the image bounds
* (minX, minY, width, and height) as being invalid.
*
* @return a reference to this <code>RasterLayout</code> following the change.
*/
public RasterLayout unsetImageBounds() {
unsetValid(MIN_X_MASK |
MIN_Y_MASK |
WIDTH_MASK |
HEIGHT_MASK);
return this;
}
/**
* Marks the parameters dealing with the tile layout (tileGridXOffset,
* tileGridYOffset, tileWidth, and tileHeight) as being invalid.
*
* @return a reference to this <code>RasterLayout</code> following the change.
*/
public RasterLayout unsetTileLayout() {
unsetValid(TILE_GRID_X_OFFSET_MASK |
TILE_GRID_Y_OFFSET_MASK |
TILE_WIDTH_MASK |
TILE_HEIGHT_MASK);
return this;
}
/**
* Returns the value of <code>minX</code> if it is valid, and
* otherwise returns the value from the supplied <code>RenderedImage</code>.
* If <code>minX</code> is not valid and fallback is null, 0 is returned.
*
* @param fallback the <code>RenderedImage</code> fallback.
* @return the appropriate value of minX.
*/
public int getMinX(RenderedImage fallback) {
if (isValid(MIN_X_MASK)) {
return minX;
} else {
if (fallback == null) {
return 0;
} else {
return fallback.getMinX();
}
}
}
/**
* Sets <code>minX</code> to the supplied value and marks it as valid.
*
* @param minX the minimum X coordinate of the image, as an int.
* @return a reference to this <code>RasterLayout</code> following the change.
*/
public RasterLayout setMinX(int minX) {
this.minX = minX;
setValid(MIN_X_MASK);
return this;
}
/**
* Returns the value of <code>minY</code> if it is valid, and
* otherwise returns the value from the supplied <code>RenderedImage</code>.
* If <code>minY</code> is not valid and fallback is null, 0 is returned.
*
* @param fallback the <code>RenderedImage</code> fallback.
* @return the appropriate value of minY.
*/
public int getMinY(RenderedImage fallback) {
if (isValid(MIN_Y_MASK)) {
return minY;
} else {
if (fallback == null) {
return 0;
} else {
return fallback.getMinY();
}
}
}
/**
* Sets <code>minY</code> to the supplied value and marks it as valid.
*
* @param minY the minimum Y coordinate of the image, as an int.
* @return a reference to this <code>RasterLayout</code> following the change.
*/
public RasterLayout setMinY(int minY) {
this.minY = minY;
setValid(MIN_Y_MASK);
return this;
}
/**
* Returns the value of <code>width</code> if it is valid, and
* otherwise returns the value from the supplied <code>RenderedImage</code>.
* If <code>width</code> is not valid and fallback is null, 0 is returned.
*
* @param fallback the <code>RenderedImage</code> fallback.
* @return the appropriate value of width.
*/
public int getWidth(RenderedImage fallback) {
if (isValid(WIDTH_MASK)) {
return width;
} else {
if (fallback == null) {
return 0;
} else {
return fallback.getWidth();
}
}
}
/**
* Sets <code>width</code> to the supplied value and marks it as valid.
*
* @param width the width of the image, as an int.
* @return a reference to this <code>RasterLayout</code> following the change.
* @throws IllegalArgumentException if <code>width</code> is non-positive.
*/
public RasterLayout setWidth(int width) {
if(width <= 0) {
throw new IllegalArgumentException("ImageLayout0");
}
this.width = width;
setValid(WIDTH_MASK);
return this;
}
/**
* Returns the value of height if it is valid, and
* otherwise returns the value from the supplied <code>RenderedImage</code>.
* If height is not valid and fallback is null, 0 is returned.
*
* @param fallback the <code>RenderedImage</code> fallback.
* @return the appropriate value of height.
*/
public int getHeight(RenderedImage fallback) {
if (isValid(HEIGHT_MASK)) {
return height;
} else {
if (fallback == null) {
return 0;
} else {
return fallback.getHeight();
}
}
}
/**
* Sets height to the supplied value and marks it as valid.
*
* @param height the height of the image, as an int.
* @return a reference to this <code>RasterLayout</code> following the change.
* @throws IllegalArgumentException if <code>height</code> is non-positive.
*/
public RasterLayout setHeight(int height) {
if(height <= 0) {
throw new IllegalArgumentException("ImageLayout0");
}
this.height = height;
setValid(HEIGHT_MASK);
return this;
}
/**
* Returns the value of <code>tileGridXOffset</code> if it is valid, and
* otherwise returns the value from the supplied <code>RenderedImage</code>.
* If <code>tileGridXOffset</code> is not valid and fallback is null, 0 is returned.
*
* @param fallback the <code>RenderedImage</code> fallback.
* @return the appropriate value of tileGridXOffset.
*/
public int getTileGridXOffset(RenderedImage fallback) {
if (isValid(TILE_GRID_X_OFFSET_MASK)) {
return tileGridXOffset;
} else {
if (fallback == null) {
return 0;
} else {
return fallback.getTileGridXOffset();
}
}
}
/**
* Sets <code>tileGridXOffset</code> to the supplied value and marks it as valid.
*
* @param tileGridXOffset the X coordinate of tile (0, 0), as an int.
* @return a reference to this <code>RasterLayout</code> following the change.
*/
public RasterLayout setTileGridXOffset(int tileGridXOffset) {
this.tileGridXOffset = tileGridXOffset;
setValid(TILE_GRID_X_OFFSET_MASK);
return this;
}
/**
* Returns the value of <code>tileGridYOffset</code> if it is valid, and
* otherwise returns the value from the supplied <code>RenderedImage</code>.
* If <code>tileGridYOffset</code> is not valid and fallback is null, 0 is returned.
*
* @param fallback the <code>RenderedImage</code> fallback.
* @return the appropriate value of tileGridYOffset.
*/
public int getTileGridYOffset(RenderedImage fallback) {
if (isValid(TILE_GRID_Y_OFFSET_MASK)) {
return tileGridYOffset;
} else {
if (fallback == null) {
return 0;
} else {
return fallback.getTileGridYOffset();
}
}
}
/**
* Sets <code>tileGridYOffset</code> to the supplied value and marks it as valid.
*
* @param tileGridYOffset the Y coordinate of tile (0, 0), as an int.
* @return a reference to this <code>RasterLayout</code> following the change.
*/
public RasterLayout setTileGridYOffset(int tileGridYOffset) {
this.tileGridYOffset = tileGridYOffset;
setValid(TILE_GRID_Y_OFFSET_MASK);
return this;
}
/**
* Returns the value of <code>tileWidth</code> if it is valid, and
* otherwise returns the value from the supplied <code>RenderedImage</code>.
* If <code>tileWidth</code> is not valid and fallback is null, 0 is returned.
*
* @param fallback the <code>RenderedImage</code> fallback.
* @return the appropriate value of tileWidth.
*/
public int getTileWidth(RenderedImage fallback) {
if (isValid(TILE_WIDTH_MASK)) {
return tileWidth;
} else {
if (fallback == null) {
return 0;
} else {
return fallback.getTileWidth();
}
}
}
/**
* Sets <code>tileWidth</code> to the supplied value and marks it as valid.
*
* @param tileWidth the width of a tile, as an int.
* @return a reference to this <code>RasterLayout</code> following the change.
* @throws IllegalArgumentException if <code>tileWidth</code> is
* non-positive.
*/
public RasterLayout setTileWidth(int tileWidth) {
if(tileWidth <= 0) {
throw new IllegalArgumentException("ImageLayout0");
}
this.tileWidth = tileWidth;
setValid(TILE_WIDTH_MASK);
return this;
}
/**
* Returns the value of tileHeight if it is valid, and
* otherwise returns the value from the supplied <code>RenderedImage</code>.
* If tileHeight is not valid and fallback is null, 0 is returned.
*
* @param fallback the <code>RenderedImage</code> fallback.
* @return the appropriate value of tileHeight.
*/
public int getTileHeight(RenderedImage fallback) {
if (isValid(TILE_HEIGHT_MASK)) {
return tileHeight;
} else {
if (fallback == null) {
return 0;
} else {
return fallback.getTileHeight();
}
}
}
/**
* Sets tileHeight to the supplied value and marks it as valid.
*
* @param tileHeight the height of a tile, as an int.
* @return a reference to this <code>RasterLayout</code> following the change.
* @throws IllegalArgumentException if <code>tileHeight</code> is
* non-positive.
*/
public RasterLayout setTileHeight(int tileHeight) {
if(tileHeight <= 0) {
throw new IllegalArgumentException("ImageLayout0");
}
this.tileHeight = tileHeight;
setValid(TILE_HEIGHT_MASK);
return this;
}
/** Returns a String containing the values of all valid fields. */
public String toString() {
String s = "RasterLayout[";
boolean first = true;
if (isValid(MIN_X_MASK)) {
s += "MIN_X=" + minX;
first = false;
}
if (isValid(MIN_Y_MASK)) {
if (!first) {
s += ", ";
}
s += "MIN_Y=" + minY;
first = false;
}
if (isValid(WIDTH_MASK)) {
if (!first) {
s += ", ";
}
s += "WIDTH=" + width;
first = false;
}
if (isValid(HEIGHT_MASK)) {
if (!first) {
s += ", ";
}
s += "HEIGHT=" + height;
first = false;
}
if (isValid(TILE_GRID_X_OFFSET_MASK)) {
if (!first) {
s += ", ";
}
s += "TILE_GRID_X_OFFSET=" + tileGridXOffset;
first = false;
}
if (isValid(TILE_GRID_Y_OFFSET_MASK)) {
if (!first) {
s += ", ";
}
s += "TILE_GRID_Y_OFFSET=" + tileGridYOffset;
first = false;
}
if (isValid(TILE_WIDTH_MASK)) {
if (!first) {
s += ", ";
}
s += "TILE_WIDTH=" + tileWidth;
first = false;
}
if (isValid(TILE_HEIGHT_MASK)) {
if (!first) {
s += ", ";
}
s += "TILE_HEIGHT=" + tileHeight;
first = false;
}
s += "]";
return s;
}
/**
* Returns a clone of the <code>RasterLayout</code> as an Object.
*/
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
/**
* Serialize the <code>RasterLayout</code>.
* @throws IOException
*/
private void writeObject(ObjectOutputStream out) throws IOException {
// Write the non-static and non-transient fields.
out.defaultWriteObject();
}
/**
* Deserialize the <code>RasterLayout</code>.
* @throws IOException
*/
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
// Read the non-static and non-transient fields.
in.defaultReadObject();
}
/**
* Tests if the specified <code>Object</code> equals this
* <code>RasterLayout</code>.
*
* @param obj the <code>Object</code> to test for equality
*
* @return <code>true</code> if the specified <code>Object</code>
* is an instance of <code>RasterLayout</code> and equals this
* <code>RasterLayout</code>; <code>false</code> otherwise.
*
* @since JAI 1.1
*/
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof RasterLayout))
return false;
RasterLayout il = (RasterLayout)obj;
return (validMask == il.validMask ) &&
(width == il.width ) &&
(height == il.height ) &&
(minX == il.minX ) &&
(minY == il.minY ) &&
(tileHeight == il.tileHeight ) &&
(tileWidth == il.tileWidth ) &&
(tileGridXOffset == il.tileGridXOffset) &&
(tileGridYOffset == il.tileGridYOffset) ;
}
/**
* Returns the hash code for this <code>RasterLayout</code>.
*
* @return a hash code for this <code>RasterLayout</code>.
*
* @since JAI 1.1
*/
public int hashCode() {
int code = 0, i = 1;
// This implementation is quite arbitrary.
// hashCode's NEED not be uniqe for two "different" objects
code += (width * i++);
code += (height * i++);
code += (minX * i++);
code += (minY * i++);
code += (tileHeight * i++);
code += (tileWidth * i++);
code += (tileGridXOffset * i++);
code += (tileGridYOffset * i++);
code ^= validMask;
return code;
}
}