/*
* 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.map.color;
import java.awt.Color;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import org.jgrasstools.gears.io.grasslegacy.map.JGrassRasterMapReader;
import org.jgrasstools.gears.io.grasslegacy.utils.GrassLegacyConstans;
import org.jgrasstools.gears.io.grasslegacy.utils.JlsTokenizer;
import org.jgrasstools.gears.io.grasslegacy.utils.Window;
/**
* <p>
* Representation of a GRASS colortable for raster maps
* </p>
*
* @author Andrea Antonello - www.hydrologis.com
* @since 1.1.0
*/
public class GrassColorTable extends ColorTable {
private File colrFile;
private int alpha = 255;
public GrassColorTable( String mapsetPath, String mapName, double[] dataRange ) throws IOException {
this(mapsetPath + File.separator + GrassLegacyConstans.COLR + File.separator + mapName, dataRange);
}
/** Creates a new instance of ColorTable */
public GrassColorTable( String colorFilePath, double[] dataRange ) throws IOException {
colrFile = new File(colorFilePath);
if (colrFile.exists()) {
BufferedReader rdr = new BufferedReader(new InputStreamReader(new FileInputStream(colrFile)));
String line = rdr.readLine();
if (line == null) {
colorTableEmpty = true;
rdr.close();
if (colrFile.delete()) {
System.out.println("removed empty color file"); //$NON-NLS-1$
}
return;
}
line = line.trim();
/*
* Read first line and if it starts with # then it is a 3.x color map. If it starts with %
* then it it a 4.x/5.x color map
*/
if (line == null)
return;
if (line.charAt(0) == '%') {
String[] stringValues = line.split("\\s+");
if (stringValues.length == 4) {
try {
alpha = Integer.parseInt(stringValues[3]);
} catch (NumberFormatException e) {
alpha = 255;
}
} else {
alpha = 255;
}
/* Read all the color rules */
while( (line = rdr.readLine()) != null ) {
if (line.charAt(0) != '%')
processGrass4ColorRule(line.trim());
}
} else if (line.charAt(0) == '#') {
int catNumber = Integer.parseInt(line.substring(1, 2));
/* Read second line which is the background colour */
processGrass3ColorRule(-1, rdr.readLine());
/* Now read the rest of the lines */
while( (line = rdr.readLine()) != null ) {
processGrass3ColorRule(catNumber++, line.trim());
}
} else {
int catNumber = 0;
/* Now read the rest of the lines */
while( (line = rdr.readLine()) != null ) {
processGrass3ColorRule(catNumber++, line.trim());
}
}
rdr.close();
colorTableEmpty = false;
// System.out.println("================================COLORTABLE================================");
// for (int i=0; i<rules.size(); i++)
// System.out.println("RULE="+rules.elementAt(i));
// System.out.println("================================");
} else {
colorTableEmpty = true;
}
}
/**
*
*/
@SuppressWarnings("nls")
private void processGrass3ColorRule( int lineNumber, String line ) {
String r, g, b;
if (line == null)
return;
try {
JlsTokenizer tk = new JlsTokenizer(line, " ");
if (lineNumber < 0) {
if (tk.hasMoreTokens()) {
r = g = b = tk.nextToken();
if (tk.hasMoreTokens())
g = tk.nextToken();
if (tk.hasMoreTokens())
b = tk.nextToken();
if (r.indexOf('.') == -1)
setBackgroundColor(new Color(Integer.parseInt(r), Integer.parseInt(g), Integer.parseInt(b)));
else
setBackgroundColor(new Color(Float.parseFloat(r), Float.parseFloat(g), Float.parseFloat(b)));
}
} else {
r = g = b = tk.nextToken();
if (tk.hasMoreTokens())
g = tk.nextToken();
if (tk.hasMoreTokens())
b = tk.nextToken();
if (r.indexOf('.') == -1)
addColorRule(lineNumber, Integer.parseInt(r), Integer.parseInt(g), Integer.parseInt(b));
else
addColorRule(lineNumber, (int) (Float.parseFloat(r) * 255f), (int) (Float.parseFloat(g) * 255f),
(int) (Float.parseFloat(b) * 255));
}
} catch (NumberFormatException ex) {
ex.printStackTrace();
}
}
/**
*
*/
@SuppressWarnings("nls")
private void processGrass4ColorRule( String line ) {
int r0 = -1, g0 = -1, b0 = -1;
int r1 = -1, g1 = -1, b1 = -1;
float cat0 = 0, cat1 = 0;
if (line == null)
return;
// System.out.println(">>"+line);
try {
JlsTokenizer tk = new JlsTokenizer(line, " ");
if (tk.hasMoreTokens()) {
/* Some lines may have two colors seperated by a space. */
JlsTokenizer tk1 = new JlsTokenizer(tk.nextToken(), ":");
cat0 = Float.parseFloat(tk1.nextToken());
/* The next value(s) describe the color as R:G:B */
r0 = g0 = b0 = Integer.parseInt(tk1.nextToken());
if (tk1.hasMoreTokens())
g0 = b0 = Integer.parseInt(tk1.nextToken());
if (tk1.hasMoreTokens())
b0 = Integer.parseInt(tk1.nextToken());
if (tk.hasMoreTokens()) {
/* Some lines may have two colors seperated by a space. */
tk1 = new JlsTokenizer(tk.nextToken(), ":");
cat1 = Float.parseFloat(tk1.nextToken());
/* The next value(s) describe the color as R:G:B */
r1 = g1 = b1 = Integer.parseInt(tk1.nextToken());
if (tk1.hasMoreTokens())
g1 = b1 = Integer.parseInt(tk1.nextToken());
if (tk1.hasMoreTokens())
b1 = Integer.parseInt(tk1.nextToken());
}
/* Add colour rule if specified for a range */
if (r1 == -1) {
addColorRule((int) cat0, r0, g0, b0);
} else {
addColorRule(cat0, r0, g0, b0, cat1, r1, g1, b1);
}
}
} catch (NumberFormatException ex) {
ex.printStackTrace();
}
}
/**
* create the default color table for a given dataRange for the case in which no hardcoded color
* table is found
*
* @param dataRange the datarange for which the colortable is created
*/
@SuppressWarnings("nls")
public void createDefaultColorTable( double[] dataRange ) {
int[][] rainbow = PredefinedColorRules.rainbow;
ArrayList<String> rules = new ArrayList<String>();
// calculate the color increment
float rinc = (float) (dataRange[1] - dataRange[0]) / 5;
for( int i = 0; i < 4; i++ ) {
addColorRule((float) (dataRange[0] + (i * rinc)), rainbow[i][0], rainbow[i][1], rainbow[i][2],
(float) (dataRange[0] + ((i + 1) * rinc)), rainbow[i + 1][0], rainbow[i + 1][1], rainbow[i + 1][2]);
StringBuffer rule = new StringBuffer();
rule.append((dataRange[0] + (i * rinc)) + ":");
rule.append(rainbow[i][0] + ":" + rainbow[i][1] + ":" + rainbow[i][2] + " ");
rule.append((dataRange[0] + ((i + 1) * rinc)) + ":");
rule.append(rainbow[i + 1][0] + ":" + rainbow[i + 1][1] + ":" + rainbow[i + 1][2] + " ");
rules.add(rule.toString());
}
addColorRule((float) (dataRange[1] - rinc), rainbow[4][0], rainbow[4][1], rainbow[4][2], (float) (dataRange[1]),
rainbow[5][0], rainbow[5][1], rainbow[5][2]);
StringBuffer rule = new StringBuffer();
rule.append((dataRange[1] - rinc) + ":");
rule.append(rainbow[4][0] + ":" + rainbow[4][1] + ":" + rainbow[4][2] + " ");
rule.append((dataRange[1]) + ":");
rule.append(rainbow[5][0] + ":" + rainbow[5][1] + ":" + rainbow[5][2] + " ");
rules.add(rule.toString());
if (!colrFile.exists()) {
BufferedWriter bw = null;
try {
// check also existence of colr folder, it could be missing
File colFolder = colrFile.getParentFile();
if (!colFolder.exists()) {
colFolder.mkdirs();
}
bw = new BufferedWriter(new FileWriter(colrFile));
String header = "% " + dataRange[0] + " " + dataRange[1] + " 255";
bw.write(header + "\n");
for( String string : rules ) {
bw.write(string + "\n");
}
bw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
public static String setColorTableFromRules( File colrFile, double[] dataRange, int[][] colorRules ) throws IOException {
if (dataRange == null) {
dataRange = new double[2];
// need to read the datarange
String name = colrFile.getName();
File mapsetFile = colrFile.getParentFile().getParentFile();
String mapsetPath = mapsetFile.getAbsolutePath();
String mapsetName = mapsetFile.getName();
String locationPath = mapsetFile.getParent();
String activeWindowPath = mapsetPath + File.separator + GrassLegacyConstans.WIND;
// first try to read the range file
String rangePath = mapsetPath + File.separator + GrassLegacyConstans.CELL_MISC + File.separator + name
+ File.separator + "f_range";
File ds = new File(rangePath);
boolean fileok = true;
int testread = 0;
if (ds.exists()) {
// the range file exists
InputStream is = null;
is = new FileInputStream(ds);
byte[] numbers = new byte[16];
try {
testread = is.read(numbers);
is.close();
} catch (IOException e) {
fileok = false;
e.printStackTrace();
}
if (testread == 16) {
// the range was read right (is this check enough? dont' know...)
ByteBuffer rangeBuffer = ByteBuffer.wrap(numbers);
dataRange[0] = rangeBuffer.getDouble();
dataRange[1] = rangeBuffer.getDouble();
} else {
// something went wrong while reading the range
fileok = false;
}
} else {
// range file does not exist
fileok = false;
}
if (!fileok) {
// something went wrong. read the map and get the range (timeconsuming)
JGrassRasterMapReader jGrassMapReader = new JGrassRasterMapReader.BuilderFromPathAndNames(new Window(
activeWindowPath), name, mapsetName, locationPath).build();
// read the map to get the range
if (!jGrassMapReader.open())
throw new IOException("An error occurred while reading the map."); // test file
while( jGrassMapReader.hasMoreData() ) {
jGrassMapReader.getNextData(); // read data
}
dataRange = jGrassMapReader.getRange();
jGrassMapReader.close();
}
}
// calculate the color increment
float rinc = (float) (dataRange[1] - dataRange[0]) / (float) (colorRules.length - 1);
StringBuffer rule = new StringBuffer();
rule.append("% " + dataRange[0] + " " + dataRange[1] + " 255\n");
for( int i = 0; i < colorRules.length - 2; i++ ) {
rule.append((dataRange[0] + (i * rinc)) + ":");
rule.append(colorRules[i][0] + ":" + colorRules[i][1] + ":" + colorRules[i][2] + " ");
rule.append((dataRange[0] + ((i + 1) * rinc)) + ":");
rule.append(colorRules[i + 1][0] + ":" + colorRules[i + 1][1] + ":" + colorRules[i + 1][2] + "\n");
}
rule.append((dataRange[1] - rinc) + ":");
rule.append(colorRules[colorRules.length - 2][0] + ":" + colorRules[colorRules.length - 2][1] + ":"
+ colorRules[colorRules.length - 2][2] + " ");
rule.append((dataRange[1]) + ":");
rule.append(colorRules[colorRules.length - 1][0] + ":" + colorRules[colorRules.length - 1][1] + ":"
+ colorRules[colorRules.length - 1][2] + "\n");
BufferedWriter bw = new BufferedWriter(new FileWriter(colrFile));
bw.write(rule.toString());
bw.close();
return rule.toString();
}
/**
* Create a default colorrules of the string format of the colorfile of the map.
*
* @param dataRange can be null
* @return the string format of the colorfile of the map
* @throws Exception
*/
@SuppressWarnings("nls")
public String createDefaultColorRulesString( double[] dataRange, boolean writeToDisk ) throws Exception {
int[][] rainbow = PredefinedColorRules.rainbow;
if (dataRange == null) {
dataRange = new double[2];
// need to read the datarange
String name = colrFile.getName();
File mapsetFile = colrFile.getParentFile().getParentFile();
String mapsetPath = mapsetFile.getAbsolutePath();
String mapsetName = mapsetFile.getName();
String locationPath = mapsetFile.getParent();
String activeWindowPath = mapsetPath + File.separator + GrassLegacyConstans.WIND;
// first try to read the range file
String rangePath = mapsetPath + File.separator + GrassLegacyConstans.CELL_MISC + File.separator + name
+ File.separator + "f_range";
File ds = new File(rangePath);
boolean fileok = true;
int testread = 0;
if (ds.exists()) {
// the range file exists
InputStream is = null;
try {
is = new FileInputStream(ds);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
byte[] numbers = new byte[16];
try {
testread = is.read(numbers);
is.close();
} catch (IOException e) {
fileok = false;
e.printStackTrace();
}
if (testread == 16) {
// the range was read right (is this check enough? dont' know...)
ByteBuffer rangeBuffer = ByteBuffer.wrap(numbers);
dataRange[0] = rangeBuffer.getDouble();
dataRange[1] = rangeBuffer.getDouble();
} else {
// something went wrong while reading the range
fileok = false;
}
} else {
// range file does not exist
fileok = false;
}
if (!fileok) {
// something went wrong. read the map and get the range (timeconsuming)
JGrassRasterMapReader jGrassMapReader = new JGrassRasterMapReader.BuilderFromPathAndNames(new Window(
activeWindowPath), name, mapsetName, locationPath).build();
// read the map to get the range
if (!jGrassMapReader.open())
return null; // test file
while( jGrassMapReader.hasMoreData() ) {
jGrassMapReader.getNextData(); // read data
}
dataRange = jGrassMapReader.getRange();
jGrassMapReader.close();
}
}
// calculate the color increment
float rinc = (float) (dataRange[1] - dataRange[0]) / 5;
StringBuffer rule = new StringBuffer();
rule.append("% " + dataRange[0] + " " + dataRange[1] + " 255\n");
for( int i = 0; i < 4; i++ ) {
rule.append((dataRange[0] + (i * rinc)) + ":");
rule.append(rainbow[i][0] + ":" + rainbow[i][1] + ":" + rainbow[i][2] + " ");
rule.append((dataRange[0] + ((i + 1) * rinc)) + ":");
rule.append(rainbow[i + 1][0] + ":" + rainbow[i + 1][1] + ":" + rainbow[i + 1][2] + "\n");
}
rule.append((dataRange[1] - rinc) + ":");
rule.append(rainbow[4][0] + ":" + rainbow[4][1] + ":" + rainbow[4][2] + " ");
rule.append((dataRange[1]) + ":");
rule.append(rainbow[5][0] + ":" + rainbow[5][1] + ":" + rainbow[5][2] + "\n");
if (writeToDisk) {
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(colrFile));
bw.write(rule.toString());
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return rule.toString();
}
public File getColrFile() {
return colrFile;
}
public int getAlpha() {
return alpha;
}
}