/* * JGrass - Free Open Source Java GIS http://www.jgrass.org * (C) HydroloGIS - www.hydrologis.com * * This program 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, 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 Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.jgrasstools.gears.io.grasslegacy.io; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.RandomAccessFile; import java.util.Date; import org.jgrasstools.gears.io.grasslegacy.utils.FileUtilities; import org.jgrasstools.gears.io.grasslegacy.utils.GrassLegacyConstans; import org.jgrasstools.gears.io.grasslegacy.utils.Window; /** * <p> * This writes native JGrass Raster maps to disk in double format. * </p> * * @author Andrea Antonello - www.hydrologis.com * @since 1.1.0 */ public class GrassRasterWriter extends MapWriter { private String name = null; private String mapsetPath = null; private String locationPath = null; private String fcellFilePath = null; private long[] rowaddresses; /** the position in the file at which the next writing occurs */ private long pointerInFilePosition; private double range[] = new double[2]; private static final String ERROR_IN_WRITING_RASTER = "Error in writing raster: "; /** * this is 1 for float and 2 for double (jgrass only supports those two) */ private int outputToDiskType = 2; /** * */ public GrassRasterWriter() { super(MapWriter.RASTER_WRITER); } /* * (non-Javadoc) * * @see jgrass.io.MapWriter#open(java.lang.String) this method tests for the existence of the * needed folder structure and creates missing parts. The dataOutputType for the map to be * created is checked */ public boolean open( String fileName, String locationPath, String mapsetName ) { if (dataWindow != null) { name = fileName; this.locationPath = locationPath; this.mapsetPath = locationPath + File.separator + mapsetName; fcellFilePath = mapsetPath + File.separator + GrassLegacyConstans.FCELL + File.separator + name; if (!checkStructure()) return false; if (!createEmptyHeader(fcellFilePath, dataWindow.getRows())) return false; } else { return false; } return true; } /** * this method writes the new map using the geographic region and settings of the active region * (dataWindow). Parameter is the dataobject holding the data */ /* * (non-Javadoc) * * @see jgrass.io.MapWriter#write(java.lang.Object) */ public boolean write( Object dataObject ) throws Exception { /* * open the streams: the file for the map to create but also the needed null-file inside of * the cell_misc folder */ File ds1 = new File(fcellFilePath); RandomAccessFile theCreatedFile = new RandomAccessFile(ds1, "rw"); //$NON-NLS-1$ File ds2 = new File(mapsetPath + File.separator + GrassLegacyConstans.CELL_MISC + File.separator + name + File.separator + GrassLegacyConstans.CELLMISC_NULL); RandomAccessFile theCreatedNullFile = new RandomAccessFile(ds2, "rw"); //$NON-NLS-1$ /* * finally writing to disk */ CompressesRasterWriter crwriter = new CompressesRasterWriter(outputToDiskType, range, pointerInFilePosition, rowaddresses, dataWindow); crwriter.compressAndWriteObj(theCreatedFile, theCreatedNullFile, dataObject); // not sure I have to do this, have to check sooner or later outputToDiskType = crwriter.getOutputToDiskType(); range = crwriter.getRange(); pointerInFilePosition = crwriter.getPointerInFilePosition(); rowaddresses = crwriter.getRowaddresses(); dataWindow = crwriter.getDataWindow(); theCreatedFile.close(); theCreatedNullFile.close(); createUtilityFiles(); return true; } /** * check if the needed folders are there (they could be missing if the mapset has just been * created and this is the first file that gets into it * * @return */ private boolean checkStructure() { File ds; ds = new File(mapsetPath + File.separator + GrassLegacyConstans.CATS + File.separator); if (!ds.exists()) if (!ds.mkdir()) return false; ds = new File(mapsetPath + File.separator + GrassLegacyConstans.CELL + File.separator); if (!ds.exists()) if (!ds.mkdir()) return false; ds = new File(mapsetPath + File.separator + GrassLegacyConstans.CELL_MISC + File.separator); if (!ds.exists()) if (!ds.mkdir()) return false; ds = new File(mapsetPath + File.separator + GrassLegacyConstans.CELL_MISC + File.separator + name); if (!ds.exists()) if (!ds.mkdir()) return false; ds = new File(mapsetPath + File.separator + GrassLegacyConstans.FCELL + File.separator); if (!ds.exists()) if (!ds.mkdir()) return false; ds = new File(mapsetPath + File.separator + GrassLegacyConstans.CELLHD + File.separator); if (!ds.exists()) if (!ds.mkdir()) return false; ds = new File(mapsetPath + File.separator + GrassLegacyConstans.COLR + File.separator); if (!ds.exists()) if (!ds.mkdir()) return false; ds = new File(mapsetPath + File.separator + GrassLegacyConstans.HIST + File.separator); if (!ds.exists()) if (!ds.mkdir()) return false; return true; } /** * creates the space for the header of the rasterfile, filling the spaces with zeroes. After the * compression the values will be rewritten * * @param filePath * @param rows * @return */ private boolean createEmptyHeader( String filePath, int rows ) { try { RandomAccessFile theCreatedFile = new RandomAccessFile(filePath, "rw"); rowaddresses = new long[rows + 1]; // the size of a long theCreatedFile.write(4); // write the addresses of the row begins. Since we don't know how // much // they will be compressed, they will be filled after the // compression for( int i = 0; i < rows + 1; i++ ) { theCreatedFile.writeInt(0); } pointerInFilePosition = theCreatedFile.getFilePointer(); rowaddresses[0] = pointerInFilePosition; theCreatedFile.close(); } catch (Exception e) { e.printStackTrace(); return false; } return true; } // here the missing goes /** * this method creates all the support files needed in the grass filesystem for a raster map and * registers the rastermap to the parent-mapset */ private void createUtilityFiles() throws Exception { // create the right files in the right places // cats/<name> File ds = new File(mapsetPath + File.separator + GrassLegacyConstans.CATS + File.separator + name); OutputStreamWriter catsWriter = new OutputStreamWriter(new FileOutputStream(ds)); catsWriter.write("# xyz categories\n#\n#\n 0.00 0.00 0.00 0.00"); catsWriter.close(); // cell/<name> ds = new File(mapsetPath + File.separator + GrassLegacyConstans.CELL + File.separator + name); OutputStreamWriter cellWriter = new OutputStreamWriter(new FileOutputStream(ds)); cellWriter.write(""); cellWriter.close(); // cell_misc/<name>/<files> // the directory <name> in cell_misc has already been created in // writeMapInActiveRegion (or extended) of the Class Mapset (or // extended) // f_format ds = new File(mapsetPath + File.separator + GrassLegacyConstans.CELL_MISC + File.separator + name + File.separator + GrassLegacyConstans.CELLMISC_FORMAT); OutputStreamWriter cell_miscFormatWriter = new OutputStreamWriter(new FileOutputStream(ds)); if (outputToDiskType * 4 == 8) { cell_miscFormatWriter.write("type: double\nbyte_order: xdr\nlzw_compression_bits: -1"); } else { cell_miscFormatWriter.write("type: float\nbyte_order: xdr\nlzw_compression_bits: -1"); } cell_miscFormatWriter.close(); // f_quant ds = new File(mapsetPath + File.separator + GrassLegacyConstans.CELL_MISC + File.separator + name + File.separator + GrassLegacyConstans.CELLMISC_QUANT); OutputStreamWriter cell_miscQantWriter = new OutputStreamWriter(new FileOutputStream(ds)); cell_miscQantWriter.write("round"); cell_miscQantWriter.close(); // f_range ds = new File(mapsetPath + File.separator + GrassLegacyConstans.CELL_MISC + File.separator + name + File.separator + GrassLegacyConstans.CELLMISC_RANGE); OutputStream cell_miscRangeStream = new FileOutputStream(ds); // if (logger.isDebugEnabled()) // logger.debug("RRRRRRRRRRRRRANGES: " + range[0] + "/" + range[1]); cell_miscRangeStream.write(FileUtilities.double2bytearray(range[0])); cell_miscRangeStream.write(FileUtilities.double2bytearray(range[1])); cell_miscRangeStream.close(); // write the file cellhd /* * this won't work since the default window lost the proj information somewhere. When it is * set at the begin, it is there. This is a problem, since grass 6.0 complains about wrong * proj!!! It doesn't show rasters. createCellhd(GrassEnvironmentManager.getInstance() * .getCurrentSessionGrassEnvironment().getLocation().getDefaultWindow() .getProj(), * GrassEnvironmentManager.getInstance() * .getCurrentSessionGrassEnvironment().getLocation().getDefaultWindow() .getZone(), * dataWindow.getNorth(), dataWindow.getSouth(), dataWindow .getEast(), * dataWindow.getWest(), dataWindow.getCols(), dataWindow .getRows(), * dataWindow.getNSResolution(), dataWindow.getWEResolution(), -1, 1); */ /* * need to reread the wind file to get the proj and zone (GRASS will not work if the cellhd * is not equal to the WIND proj) */ Window tmp = new Window(locationPath + File.separator + GrassLegacyConstans.PERMANENT_MAPSET + File.separator + GrassLegacyConstans.WIND); createCellhd(tmp.getProj(), tmp.getZone(), dataWindow.getNorth(), dataWindow.getSouth(), dataWindow.getEast(), dataWindow.getWest(), dataWindow.getCols(), dataWindow.getRows(), dataWindow.getNSResolution(), dataWindow.getWEResolution(), -1, 1); // hist/<name> ds = new File(mapsetPath + File.separator + GrassLegacyConstans.HIST + File.separator + name); OutputStreamWriter windFile = new OutputStreamWriter(new FileOutputStream(ds)); Date date = new Date(); windFile.write(date + "\n"); windFile.write(name + "\n"); windFile.write(mapsetPath + "\n"); windFile.write("generic user\n"); windFile.write("DCELL\n"); windFile.write("\n\nCreated by JGrass\n"); windFile.write(historyComment + "\n"); windFile.close(); // now all the files have been created } /** * changes the cellhd file inserting the new values obtained from the environment */ private void createCellhd( int chproj, int chzone, double chn, double chs, double che, double chw, int chcols, int chrows, double chnsres, double chewres, int chformat, int chcompressed ) throws Exception { StringBuffer data = new StringBuffer(512); data.append("proj: " + chproj + "\n").append("zone: " + chzone + "\n").append("north: " + chn + "\n") .append("south: " + chs + "\n").append("east: " + che + "\n").append("west: " + chw + "\n") .append("cols: " + chcols + "\n").append("rows: " + chrows + "\n").append("n-s resol: " + chnsres + "\n") .append("e-w resol: " + chewres + "\n").append("format: " + chformat + "\n") .append("compressed: " + chcompressed); File ds = new File(mapsetPath + File.separator + GrassLegacyConstans.CELLHD + File.separator + name); OutputStreamWriter windFile = new OutputStreamWriter(new FileOutputStream(ds)); windFile.write(data.toString()); windFile.close(); } public void setOutputDataObject( Object _dataObject ) { dataObject = _dataObject; if (_dataObject instanceof Double) { outputToDiskType = 2; } else if (_dataObject instanceof Float) { outputToDiskType = 1; } else { // throw something } } /* * (non-Javadoc) * * @see jgrass.io.MapWriter#setParameter(java.lang.String, java.lang.Object) */ public void setParameter( String key, Object obj ) { } public void setDataWindow( Window window ) { dataWindow = window; } public boolean open( String mapPath ) { File mapFile = new File(mapPath); String fileName = mapFile.getName(); File mapsetFile = mapFile.getParentFile().getParentFile(); String mapsetName = mapsetFile.getName(); String locationPath = mapsetFile.getParent(); return open(fileName, locationPath, mapsetName); } }