/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*
* 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.
*/
package org.geotools.swing.tool;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
import org.geotools.geometry.DirectPosition2D;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.GridCoverageLayer;
import org.geotools.map.GridReaderLayer;
import org.geotools.map.MapContent;
import org.geotools.map.RasterLayer;
import org.opengis.geometry.DirectPosition;
import org.opengis.referencing.operation.MathTransform;
/**
* Helper class used by {@code InfoTool} to query {@code Layers}
* with raster feature data ({@code GridCoverage2D} or {@code AbstractGridCoverage2DReader}).
*
* @see InfoTool
* @see VectorLayerHelper
*
* @author Michael Bedward
* @since 2.6
*
*
* @source $URL$
* @version $URL$
*/
public class GridLayerHelper extends InfoToolHelper<List<Number>> {
private enum SourceType {
COVERAGE,
READER;
}
private final WeakReference<Object> sourceRef;
private final SourceType sourceType;
/**
* Create a new helper to work with the given raster data source.
*
* @param content the {@code MapContent} associated with this helper
* @param rasterSource an instance of either
* {@code GridCoverage2D} or {@code AbstractGridCoverage2DReader
*/
public GridLayerHelper(MapContent content, RasterLayer layer) {
super(content, null);
Object source = null;
try {
if (layer instanceof GridCoverageLayer) {
sourceType = SourceType.COVERAGE;
sourceRef = new WeakReference<Object>(((GridCoverageLayer)layer).getCoverage());
} else if (layer instanceof GridReaderLayer) {
sourceType = SourceType.READER;
sourceRef = new WeakReference<Object>(((GridReaderLayer)layer).getReader());
} else {
throw new IllegalArgumentException("Unrecognized raster layer type");
}
} catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
setCRS(layer.getBounds().getCoordinateReferenceSystem());
}
/**
* Get band values at the given position
*
* @param pos the location to query
*
* @param params not used at present
*
* @return a {@code List} of band values; will be empty if {@code pos} was
* outside the coverage bounds
*
* @throws Exception if the grid coverage could not be queried
*/
@Override
public List<Number> getInfo(DirectPosition2D pos, Object... params)
throws Exception {
List<Number> list = new ArrayList<Number>();
if (isValid()) {
switch (sourceType) {
case COVERAGE: {
GridCoverage2D source = (GridCoverage2D) sourceRef.get();
ReferencedEnvelope env = new ReferencedEnvelope(source.getEnvelope2D());
DirectPosition2D trPos = getTransformed(pos);
if (env.contains(trPos)) {
Object objArray = source.evaluate(trPos);
Number[] bandValues = asNumberArray(objArray);
if (bandValues != null) {
list.addAll(Arrays.asList(bandValues));
}
}
}
break;
case READER: {
AbstractGridCoverage2DReader reader = (AbstractGridCoverage2DReader) sourceRef.get();
GeneralEnvelope genEnv = reader.getOriginalEnvelope();
DirectPosition2D trPos = getTransformed(pos);
if (genEnv.contains(trPos)) {
Number[] bandValues = getGridReaderValues(trPos);
if (bandValues != null) {
list.addAll(Arrays.asList(bandValues));
}
}
}
break;
}
}
return list;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isValid() {
return (getMapContent() != null && sourceRef != null && sourceRef.get() != null);
}
/**
* TODO: WRITE METHOD !
*
* @param trPos
* @return
*/
private Number[] getGridReaderValues(DirectPosition2D trPos) {
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Convert the Object returned by {@linkplain GridCoverage2D#evaluate(DirectPosition)} into
* an array of {@code Numbers}.
*
* @param objArray an Object representing a primitive array
*
* @return a new array of Numbers
*/
private Number[] asNumberArray(Object objArray) {
Number[] numbers = null;
if (objArray instanceof byte[]) {
byte[] values = (byte[]) objArray;
numbers = new Number[values.length];
for (int i = 0; i < values.length; i++) {
numbers[i] = ((int)values[i]) & 0xff;
}
} else if (objArray instanceof int[]) {
int[] values = (int[]) objArray;
numbers = new Number[values.length];
for (int i = 0; i < values.length; i++) {
numbers[i] = values[i];
}
} else if (objArray instanceof float[]) {
float[] values = (float[]) objArray;
numbers = new Number[values.length];
for (int i = 0; i < values.length; i++) {
numbers[i] = values[i];
}
} else if (objArray instanceof double[]) {
double[] values = (double[]) objArray;
numbers = new Number[values.length];
for (int i = 0; i < values.length; i++) {
numbers[i] = values[i];
}
}
return numbers;
}
/**
* Transform the query position into the coordinate reference system of the
* data (if different to that of the {@code MapContent}).
*
* @param pos query position in {@code MapContent} coordinates
*
* @return query position in data ({@code Layer}) coordinates
*/
private DirectPosition2D getTransformed(DirectPosition2D pos) {
if (isTransformRequired()) {
MathTransform tr = getTransform();
if (tr == null) {
throw new IllegalStateException("MathTransform should not be null");
}
try {
return (DirectPosition2D) tr.transform(pos, null);
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
return pos;
}
}