/* * This file is part of JGrasstools (http://www.jgrasstools.org) * (C) HydroloGIS - www.hydrologis.com * * JGrasstools is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.jgrasstools.gears.io.rasterreader; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_AUTHORCONTACTS; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_AUTHORNAMES; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_DO_LEGACY_GRASS_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_FILE_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_FILE_NOVALUE_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_GEO_DATA_NOVALUE_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_KEYWORDS; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_LABEL; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_LICENSE; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_NAME; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_OUT_RASTER_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_P_COLS_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_P_EAST_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_P_NORTH_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_P_ROWS_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_P_SOUTH_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_P_WEST_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_P_X_RES_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_P_Y_RES_DESCRIPTION; import static org.jgrasstools.gears.i18n.GearsMessages.OMSRASTERREADER_STATUS; import static org.jgrasstools.gears.libs.modules.JGTConstants.AIG; import static org.jgrasstools.gears.libs.modules.JGTConstants.ESRIGRID; import static org.jgrasstools.gears.libs.modules.JGTConstants.GEOTIF; import static org.jgrasstools.gears.libs.modules.JGTConstants.GEOTIFF; import static org.jgrasstools.gears.libs.modules.JGTConstants.GRASS; import static org.jgrasstools.gears.libs.modules.JGTConstants.JPEG; import static org.jgrasstools.gears.libs.modules.JGTConstants.JPG; import static org.jgrasstools.gears.libs.modules.JGTConstants.PNG; import static org.jgrasstools.gears.libs.modules.JGTConstants.doubleNovalue; import static org.jgrasstools.gears.libs.modules.JGTConstants.isNovalue; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.COLS; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.EAST; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.NORTH; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.ROWS; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.SOUTH; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.WEST; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.XRES; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.YRES; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.buildCoverage; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.createDoubleWritableRaster; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.createGridGeometryGeneralParameter; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.getRegionParamsFromGridCoverage; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.gridGeometryFromRegionParams; import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.makeRegionParamsMap; import java.awt.RenderingHints; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.HashMap; import javax.media.jai.ImageLayout; import javax.media.jai.JAI; import javax.media.jai.iterator.RandomIter; import javax.media.jai.iterator.RandomIterFactory; import javax.media.jai.iterator.WritableRandomIter; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.coverage.grid.GridGeometry2D; import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader; import org.geotools.coverage.processing.Operations; import org.geotools.coverageio.gdal.BaseGDALGridCoverage2DReader; import org.geotools.coverageio.gdal.aig.AIGReader; import org.geotools.factory.Hints; import org.geotools.gce.arcgrid.ArcGridReader; import org.geotools.gce.geotiff.GeoTiffReader; import org.geotools.gce.grassraster.GrassCoverageReader; import org.geotools.gce.grassraster.JGrassMapEnvironment; import org.geotools.gce.grassraster.JGrassRegion; import org.geotools.gce.grassraster.format.GrassCoverageFormat; import org.geotools.gce.grassraster.format.GrassCoverageFormatFactory; import org.geotools.gce.image.WorldImageReader; import org.geotools.geometry.GeneralEnvelope; import org.geotools.geometry.jts.ReferencedEnvelope; import org.jgrasstools.gears.io.grasslegacy.OmsGrassLegacyReader; import org.jgrasstools.gears.io.grasslegacy.utils.GrassLegacyUtilities; import org.jgrasstools.gears.libs.exceptions.ModelsIllegalargumentException; import org.jgrasstools.gears.libs.modules.JGTConstants; import org.jgrasstools.gears.libs.modules.JGTModel; import org.jgrasstools.gears.libs.monitor.IJGTProgressMonitor; import org.jgrasstools.gears.utils.coverage.CoverageUtilities; import org.jgrasstools.gears.utils.files.FileUtilities; import org.jgrasstools.gears.utils.math.NumericsUtilities; import org.opengis.parameter.GeneralParameterValue; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Envelope; import oms3.annotations.Author; import oms3.annotations.Description; import oms3.annotations.Execute; import oms3.annotations.In; import oms3.annotations.Keywords; import oms3.annotations.Label; import oms3.annotations.License; import oms3.annotations.Name; import oms3.annotations.Out; import oms3.annotations.Status; import oms3.annotations.UI; @Description(OMSRASTERREADER_DESCRIPTION) @Author(name = OMSRASTERREADER_AUTHORNAMES, contact = OMSRASTERREADER_AUTHORCONTACTS) @Keywords(OMSRASTERREADER_KEYWORDS) @Label(OMSRASTERREADER_LABEL) @Name(OMSRASTERREADER_NAME) @Status(OMSRASTERREADER_STATUS) @License(OMSRASTERREADER_LICENSE) public class OmsRasterReader extends JGTModel { @Description(OMSRASTERREADER_FILE_DESCRIPTION) @UI(JGTConstants.FILEIN_UI_HINT) @In public String file = null; @Description(OMSRASTERREADER_FILE_NOVALUE_DESCRIPTION) @In public Double fileNovalue = -9999.0; @Description(OMSRASTERREADER_GEO_DATA_NOVALUE_DESCRIPTION) @In public Double geodataNovalue = doubleNovalue; @Description(OMSRASTERREADER_P_NORTH_DESCRIPTION) @UI(JGTConstants.PROCESS_NORTH_UI_HINT) @In public Double pNorth = null; @Description(OMSRASTERREADER_P_SOUTH_DESCRIPTION) @UI(JGTConstants.PROCESS_SOUTH_UI_HINT) @In public Double pSouth = null; @Description(OMSRASTERREADER_P_WEST_DESCRIPTION) @UI(JGTConstants.PROCESS_WEST_UI_HINT) @In public Double pWest = null; @Description(OMSRASTERREADER_P_EAST_DESCRIPTION) @UI(JGTConstants.PROCESS_EAST_UI_HINT) @In public Double pEast = null; @Description(OMSRASTERREADER_P_X_RES_DESCRIPTION) @UI(JGTConstants.PROCESS_XRES_UI_HINT) @In public Double pXres = null; @Description(OMSRASTERREADER_P_Y_RES_DESCRIPTION) @UI(JGTConstants.PROCESS_YRES_UI_HINT) @In public Double pYres = null; @Description(OMSRASTERREADER_P_ROWS_DESCRIPTION) @UI(JGTConstants.PROCESS_ROWS_UI_HINT) @In public Integer pRows = null; @Description(OMSRASTERREADER_P_COLS_DESCRIPTION) @UI(JGTConstants.PROCESS_COLS_UI_HINT) @In public Integer pCols = null; @Description(OMSRASTERREADER_DO_LEGACY_GRASS_DESCRIPTION) @In public Boolean doLegacyGrass = false; @Description(OMSRASTERREADER_OUT_RASTER_DESCRIPTION) @Out public GridCoverage2D outRaster = null; /** * Flag to read only envelope (if true, the output geodata is null). */ public boolean doEnvelope = false; /** * The original envelope of the coverage. */ public GeneralEnvelope originalEnvelope; private GeneralParameterValue[] generalParameter = null; private double[] pBounds; private double[] pRes; private int[] pRowcol; private double internalFileNovalue = -9999.0; private double internalGeodataNovalue = doubleNovalue; private boolean doLegacyGrassAutoBoxed = false; @Execute public void process() throws Exception { if (!concatOr(outRaster == null, doReset)) { return; } if (doLegacyGrass != null && doLegacyGrass) { doLegacyGrassAutoBoxed = true; } if (fileNovalue != null) { internalFileNovalue = fileNovalue; } if (geodataNovalue != null) { internalGeodataNovalue = geodataNovalue; } if (hasBoundsRequest() && (!hasResolutionRequest() && !hasRowColsRequest())) { throw new RuntimeException("If bounds are requested, also a resolution or number of rows/cols has to be supplied."); } if (hasBoundsRequest()) { pBounds = new double[]{pNorth, pSouth, pWest, pEast}; } if (hasResolutionRequest()) { pRes = new double[]{pXres, pYres}; } if (hasRowColsRequest()) { pRowcol = new int[]{pRows, pCols}; } String pType = null; // try to guess from the extension if (file.toLowerCase().endsWith(ESRIGRID)) { pType = ESRIGRID; } else if (file.toLowerCase().endsWith(AIG)) { pType = AIG; } else if (file.toLowerCase().endsWith(GEOTIFF) || file.toLowerCase().endsWith(GEOTIF)) { pType = GEOTIFF; } else if (file.toLowerCase().endsWith(JPEG) || file.toLowerCase().endsWith(JPG)) { pType = JPG; } else if (file.toLowerCase().endsWith(PNG)) { pType = PNG; } else if (CoverageUtilities.isGrass(file)) { pType = GRASS; } else throw new ModelsIllegalargumentException( "Can't recognize the data format. Supported are: asc, tiff, jpg, png, grass.", this.getClass() .getSimpleName(), pm); File mapFile = new File(file); try { pm.beginTask("Reading coverage: " + mapFile.getName(), IJGTProgressMonitor.UNKNOWN); if (pType.equals(ESRIGRID)) { readArcGrid(mapFile); } else if (pType.equals(GEOTIFF)) { readGeotiff(mapFile); } else if (pType.equals(JPG)) { readWorldImage(mapFile); } else if (pType.equals(PNG)) { readWorldImage(mapFile); } else if (pType.equals(AIG) || pType.endsWith("w001001x.adf")) { readAig(mapFile); } else if (pType.equals(GRASS)) { readGrass(mapFile); } else { throw new ModelsIllegalargumentException("Data type not supported: " + pType, this.getClass().getSimpleName(), pm); } } finally { pm.done(); } } private void readGrass( File mapFile ) throws Exception { JGrassMapEnvironment mapEnvironment = new JGrassMapEnvironment(new File(file)); CoordinateReferenceSystem crs = mapEnvironment.getCoordinateReferenceSystem(); JGrassRegion readRegion = mapEnvironment.getFileRegion(); double n = readRegion.getNorth(); double s = readRegion.getSouth(); double w = readRegion.getWest(); double e = readRegion.getEast(); Envelope env = readRegion.getEnvelope(); originalEnvelope = new GeneralEnvelope(new ReferencedEnvelope(env.getMinX(), env.getMaxX(), env.getMinY(), env.getMaxY(), crs)); // if bounds supplied, use them as region if (pBounds != null) { // n, s, w, e n = pBounds[0]; s = pBounds[1]; w = pBounds[2]; e = pBounds[3]; } if (pRes != null) { readRegion = new JGrassRegion(w, e, s, n, pRes[0], pRes[1]); } if (pRowcol != null) { readRegion = new JGrassRegion(w, e, s, n, pRowcol[0], pRowcol[1]); } if (!doEnvelope) { int r = readRegion.getRows(); int c = readRegion.getCols(); if (!JGTConstants.doesOverFlow(r, c) && !doLegacyGrassAutoBoxed) { if (generalParameter == null) { generalParameter = createGridGeometryGeneralParameter(readRegion.getCols(), readRegion.getRows(), readRegion.getNorth(), readRegion.getSouth(), readRegion.getEast(), readRegion.getWest(), crs); } GrassCoverageFormat format = new GrassCoverageFormatFactory().createFormat(); GrassCoverageReader reader = format.getReader(mapEnvironment.getCELL()); outRaster = (GridCoverage2D) reader.read(generalParameter); } else { OmsGrassLegacyReader reader = new OmsGrassLegacyReader(); reader.file = file; reader.pm = pm; reader.inWindow = GrassLegacyUtilities.jgrassRegion2legacyWindow(readRegion); reader.readCoverage(); outRaster = reader.outGC; } checkNovalues(); } } private void readAig( File mapFile ) throws IllegalArgumentException, IOException { final ImageLayout l = new ImageLayout(); l.setTileGridXOffset(0).setTileGridYOffset(0).setTileHeight(512).setTileWidth(512); Hints hints = new Hints(); hints.add(new RenderingHints(JAI.KEY_IMAGE_LAYOUT, l)); final URL url = mapFile.toURI().toURL(); final Object source = url; final BaseGDALGridCoverage2DReader reader = new AIGReader(source, hints); originalEnvelope = reader.getOriginalEnvelope(); if (!doEnvelope) { outRaster = (GridCoverage2D) reader.read(generalParameter); resample(); checkNovalues(); } } private void readGeotiff( File mapFile ) throws IOException { String nameWithoutExtention = FileUtilities.getNameWithoutExtention(mapFile); File twfFile = new File(mapFile.getParentFile(), nameWithoutExtention + ".tfw"); AbstractGridCoverage2DReader geoTiffReader; if (twfFile.exists()) { geoTiffReader = new WorldImageReader(mapFile); } else { geoTiffReader = new GeoTiffReader(mapFile); } originalEnvelope = geoTiffReader.getOriginalEnvelope(); if (!doEnvelope) { outRaster = geoTiffReader.read(generalParameter); resample(); checkNovalues(); } } private void readArcGrid( File mapFile ) throws IllegalArgumentException, IOException { ArcGridReader arcGridReader = new ArcGridReader(mapFile); originalEnvelope = arcGridReader.getOriginalEnvelope(); if (!doEnvelope) { outRaster = arcGridReader.read(generalParameter); resample(); checkNovalues(); } } private void readWorldImage( File mapFile ) throws IllegalArgumentException, IOException { WorldImageReader worldImageReader = new WorldImageReader(mapFile); originalEnvelope = worldImageReader.getOriginalEnvelope(); if (!doEnvelope) { outRaster = worldImageReader.read(generalParameter); resample(); // checkNovalues(); } } private void resample() { if (!hasBoundsRequest() && !hasResolutionRequest() && !hasRowColsRequest()) { // no resample required return; } HashMap<String, Double> envelopeParams = getRegionParamsFromGridCoverage(outRaster); double west = envelopeParams.get(WEST); double south = envelopeParams.get(SOUTH); double east = envelopeParams.get(EAST); double north = envelopeParams.get(NORTH); double xres = envelopeParams.get(XRES); double yres = envelopeParams.get(YRES); if (pBounds == null) { pBounds = new double[]{north, south, west, east}; } if (pRes == null) { pRes = new double[]{xres, yres}; } double n = pBounds[0]; double s = pBounds[1]; double w = pBounds[2]; double e = pBounds[3]; if (pRes != null || pRowcol != null) { int newRows = 0; int newCols = 0; if (pRowcol != null) { newRows = (int) pRowcol[0]; newCols = (int) pRowcol[1]; if (pRes == null) { pRes = new double[2]; } pRes[0] = (e - w) / (double) newCols; pRes[1] = (n - s) / (double) newRows; } else if (pRes != null) { pRowcol = new int[2]; newRows = (int) Math.round((n - s) / pRes[1]); newCols = (int) Math.round((e - w) / pRes[0]); } pRowcol[0] = newRows; pRowcol[1] = newCols; } HashMap<String, Double> newParams = makeRegionParamsMap(n, s, w, e, pRes[0], pRes[1], (int) pRowcol[1], (int) pRowcol[0]); CoordinateReferenceSystem crs = outRaster.getCoordinateReferenceSystem(); GridGeometry2D gg = gridGeometryFromRegionParams(newParams, crs); outRaster = (GridCoverage2D) Operations.DEFAULT.resample(outRaster, crs, gg, null); } private void checkNovalues() { // TODO make this nice, this can't be the way if (fileNovalue == null || geodataNovalue == null) { return; } if (isNovalue(internalFileNovalue) && isNovalue(internalGeodataNovalue)) { return; } if (!NumericsUtilities.dEq(internalFileNovalue, internalGeodataNovalue)) { HashMap<String, Double> params = getRegionParamsFromGridCoverage(outRaster); int height = params.get(ROWS).intValue(); int width = params.get(COLS).intValue(); WritableRaster tmpWR = createDoubleWritableRaster(width, height, null, null, null); WritableRandomIter tmpIter = RandomIterFactory.createWritable(tmpWR, null); RenderedImage readRI = outRaster.getRenderedImage(); RandomIter readIter = RandomIterFactory.create(readRI, null); int minX = readRI.getMinX(); int minY = readRI.getMinY(); for( int r = 0; r < height; r++ ) { for( int c = 0; c < width; c++ ) { double value = readIter.getSampleDouble(c + minX, r + minY, 0); if (isNovalue(value) || value == internalFileNovalue || value == -Float.MAX_VALUE || value == Float.MAX_VALUE) { tmpIter.setSample(c, r, 0, internalGeodataNovalue); } else { tmpIter.setSample(c, r, 0, value); } } } readIter.done(); tmpIter.done(); outRaster = buildCoverage(new File(file).getName(), tmpWR, params, outRaster.getCoordinateReferenceSystem()); } } private boolean hasBoundsRequest() { return pNorth != null && pSouth != null && pWest != null && pEast != null; } private boolean hasRowColsRequest() { return pRows != null && pCols != null; } private boolean hasResolutionRequest() { return pXres != null && pYres != null; } /** * Utility method to quickly read a grid in default mode. * * @param path the path to the file. * @return the read coverage. * @throws Exception */ public static GridCoverage2D readRaster( String path ) throws Exception { OmsRasterReader reader = new OmsRasterReader(); reader.file = path; reader.process(); GridCoverage2D geodata = reader.outRaster; return geodata; } }