/*
* GISToolkit - Geographical Information System Toolkit
* (C) 2003, Ithaqua Enterprises Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package proprietary.datasources.ermapper;
import java.awt.image.BufferedImage;
import gistoolkit.common.*;
import gistoolkit.features.*;
import gistoolkit.projection.*;
import gistoolkit.datasources.*;
import com.ermapper.ecw.JNCSFile;
/**
* Class to allow reading images using the ERMapper wavelet protocol.
*/
public class ERMapperDatasource extends SimpleDataSource implements RasterDatasource {
/** The height of the image to retrieve. */
private int myImageHeight = -1;
/** Set the height (in pixels) of the image to retrieve.*/
public void setImageHeight(int inHeight) {myImageHeight = inHeight;}
/** Get the height (in pixels) of the image to retrieve.*/
public int getImageHeight(){return myImageHeight;}
/** The width of the image to retrieve. */
private int myImageWidth = -1;
/** Set the width (in pixels) of the image to retrieve.*/
public void setImageWidth(int inWidth) {myImageWidth = inWidth;}
/** Get the width (in pixels) of the image to retrieve.*/
public int getImageWidth(){return myImageWidth;}
/** The file or URL where the data source is to draw it's data. */
private String myFileLocation = null;
/** Set the file or URL where the data source is to draw it's data. */
public void setFileLocation(String inLocation){myFileLocation = inLocation; setName(inLocation);}
/** Get the file or URL where the data source is to draw it's data. */
public String getFileLocation(){return myFileLocation;}
/** Creates a new instance of ERMapperDatasource */
public ERMapperDatasource() {
super();
}
/** Creates a new instance of ERMapperDatasource with the given location.*/
public ERMapperDatasource(String inLocation) {
super();
setFileLocation(inLocation);
}
/** Save the envelope of the data source so that it does not need to be reread every time. */
private Envelope myWorldEnvelope = null;
/** Returns the bounding rectangle of all the shapes in the Data Source. */
public Envelope readEnvelope() throws Exception {
if (myWorldEnvelope == null){
JNCSFile tempECWFile = new JNCSFile(getFileLocation(), false);
// find the coordinates of the file.
Envelope tempECWFileEnvelope = new Envelope(
tempECWFile.originX,
tempECWFile.originY,
tempECWFile.originX+tempECWFile.cellIncrementX*(tempECWFile.width-1),
tempECWFile.originY+tempECWFile.cellIncrementY*(tempECWFile.height-1));
myWorldEnvelope = tempECWFileEnvelope;
// close the file, free the image cache.
tempECWFile.close(true);
}
return myWorldEnvelope;
}
/**
* Reads only the objects from the data source that intersect these envelope.
*/
public synchronized GISDataset readDataset(Envelope inEnvelope) throws Exception {
if (inEnvelope == null) return readDataset();
boolean blewCache = false;
if (getCached()){
blewCache = !isCachedProjected();
if ((getCacheEnvelope() == null) || (!getCacheEnvelope().isEqual(inEnvelope))){
clearCache();
}
}
// all the things that can blow a cache.
if ((getFromProjection() == null) || (getToProjection() == null)||(blewCache)||(getFromProjection() instanceof NoProjection)||(getToProjection() instanceof NoProjection)){
return super.readDataset(inEnvelope);
}
else{
// this is a very specific case to try to increase the resolution of reprojected images.
// If there is a from and a to projection, chances are they are from and two similar projections
// It is much more efficient to project these once than to do it many times.
Envelope tempEnvelope = inEnvelope;
if (getCacheEnvelope() != null){
if (getCacheEnvelope().contains(tempEnvelope)){
return queryFromCache(tempEnvelope);
}
}
tempEnvelope = ShapeProjector.projectBackward(getToProjection(), inEnvelope);
// I have some concerns about this because the shape is not really a square at this point.
// would be more efficient to convert to a polygon and then query from that.
GISDataset tempDataset = readShapes(ShapeProjector.projectForward(getFromProjection(), tempEnvelope));
if (tempDataset != null){
tempDataset = filterDataset(tempDataset);
tempDataset = (GISDataset) tempDataset.clone();
for (int i=0; i<tempDataset.size(); i++){
gistoolkit.features.Shape tempShape = tempDataset.getShape(i);
if ((tempShape != null) && (tempShape instanceof RasterShape)){
ImageProjector.reProject(getFromProjection(), getToProjection(), (RasterShape) tempShape);
}
}
setCache(tempDataset, (Envelope) inEnvelope.clone());
}
return tempDataset;
}
}
/**
* Reads all the objects from the data source.
*/
public GISDataset readDataset() throws Exception {
if ((getFromProjection() == null) || (getToProjection() == null)||(!isCachedProjected())||(getFromProjection() instanceof NoProjection)||(getToProjection() instanceof NoProjection)){
return super.readDataset(null);
}
else{
// this is a very specific case to try to increase the resolution of reprojected images.
// If there is a from and a to projection, chances are they are from and two similar projections
// It is much more efficient to project these once than to do it many times.
GISDataset tempDataset = readShapes(null);
if (tempDataset != null){
tempDataset = filterDataset(tempDataset);
for (int i=0; i<tempDataset.size(); i++){
gistoolkit.features.Shape tempShape = tempDataset.getShape(i);
if ((tempShape != null) && (tempShape instanceof RasterShape)){
ImageProjector.reProject(getFromProjection(), getToProjection(), (RasterShape) tempShape);
}
}
setCache(tempDataset, (Envelope) tempDataset.getEnvelope().clone());
}
return tempDataset;
}
}
/** This method should return the shapes from the data source */
protected GISDataset readShapes(Envelope inEnvelope) throws Exception {
// ensure there is an overlap
if (!inEnvelope.overlaps(readEnvelope())) return new GISDataset();
// create the new file, in nonprogressive mode.
JNCSFile tempECWFile = new JNCSFile(getFileLocation(), false);
// trim the envelope to the one in view.
Envelope tempEnvelope = inEnvelope.getOverlap(readEnvelope());
// figure out how big this image needs to be (the JNCSFile does not do subsampling);
int width = getImageWidth();
int height = getImageHeight();
// find the required width and height.
if (tempECWFile.cellIncrementX > (tempEnvelope.getWidth()/width)){
width = (int) (tempEnvelope.getWidth()/tempECWFile.cellIncrementX);
}
if (Math.abs(tempECWFile.cellIncrementY) > (tempEnvelope.getHeight()/height)){
height = (int) (tempEnvelope.getHeight()/Math.abs(tempECWFile.cellIncrementY));
}
// go about generating the data
double dWorldTLX, dWorldTLY, dWorldBRX, dWorldBRY;
int bandlist[];
int line, pRGBArray[] = null;
// Create an image of the ecw file.
BufferedImage ecwImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
pRGBArray = new int[width];
// Setup the view parameters for the ecw file.
bandlist = new int[tempECWFile.numBands];
for (int i=0; i< tempECWFile.numBands; i++) {
bandlist[i] = i;
}
dWorldTLX = tempEnvelope.getMinX();
dWorldTLY = tempEnvelope.getMaxY();
dWorldBRX = tempEnvelope.getMaxX();
dWorldBRY = tempEnvelope.getMinY();
// Set the view
tempECWFile.setView(tempECWFile.numBands, bandlist, dWorldTLX, dWorldTLY, dWorldBRX, dWorldBRY, width, height);
// Read the scan lines
for (line=0; line < height; line++) {
tempECWFile.readLineRGBA(pRGBArray);
ecwImage.setRGB(0, line, width, 1, pRGBArray, 0, width);
}
// close the file
tempECWFile.close(true);
// return the graphics object
RasterShape tempShape = new RasterShape(tempEnvelope, ecwImage);
Record tempRecord = new Record();
String[] tempAttributeNames = {"ERMapper"};
tempRecord.setAttributeNames(tempAttributeNames);
Object[][] tempAttributeValues = new Object[1][1];
tempAttributeValues[0][0] = getFileLocation();
tempRecord.setAttributes(tempAttributeValues);
tempRecord.setShape(tempShape);
GISDataset tempDataset = new GISDataset();
tempDataset.add(tempRecord);
return tempDataset;
}
/** Constants for the configuration information*/
private static final String FILE_LOCATION_TAG = "ERMFileLocation";
/** Get the configuration information for this layer. */
public Node getNode() {
Node tempRoot = super.getNode();
tempRoot.setName("ERMapperDataSource");
tempRoot.addAttribute(FILE_LOCATION_TAG, myFileLocation);
return tempRoot;
}
/** Set the configuration information for this layer. */
public void setNode(Node inNode) throws Exception{
super.setNode(inNode);
if (inNode != null){
// construct the file
String tempString = inNode.getAttribute(FILE_LOCATION_TAG);
if (tempString != null){
setFileLocation(tempString);
readEnvelope();
}
}
}
}