/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2006-2011, 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.gce.grassraster.core.color; import java.awt.Color; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import org.geotools.gce.grassraster.JGrassMapEnvironment; /** * Represents a GRASS rastermap color table. * * <p> * Colortables for GRASS 5 and greater are supported. * </p> * * <p>Format of the color file, which is located in * <b>location/mapset/colr/mapname</b>:</p> * <p>The first line is a % character and two numbers indicating the minimum * and maximum data values which have colors. <b>Note that in JGrass after the * range values we add a third value for alpha support.</b></p> * <p>After the first line, the list of color rules appears, that can be * of the following formats: * <ul> * <li><code>value1:r:g:b value2:r:g:b</code> interpolation of colors between * the two values with the two colors</li> * <li><code>value1:grey value2:grey</code interpolation of grayscale between * the two values with the two grey values></li> * <li><code>value1:r:g:b</code> assumption that it means that value1 == * value2</li> * <li><code>nv:r:g:b</code> novalues could also have color with such a rule.</li> * </ul> * </p> * * @author Andrea Antonello (www.hydrologis.com) * @since 3.0 * * @source $URL: http://svn.osgeo.org/geotools/trunk/modules/plugin/grassraster/src/main/java/org/geotools/gce/grassraster/core/color/JGrassColorTable.java $ */ public class JGrassColorTable { /** * The rainbow color table, used as default for non existing color table. */ private final static int[][] rainbow = new int[][]{{255, 255, 0}, /* yellow */ {0, 255, 0}, /* green */ {0, 255, 255}, /* cyan */ {0, 0, 255}, /* blue */ {255, 0, 255}, /* magenta */ {255, 0, 0} /* red */ }; // private final static int[][] aspect = new int[][]{{255, 255, 255}, /* white */ // {0, 0, 0}, /* black */ // {255, 255, 255} /* white */ // }; /** * The transparency value. */ private int alpha = 255; /** * The list of colorrules to be used. */ private List<String> rules = new ArrayList<String>(); /** * Creates a new instance of ColorTable * * @param readerGrassEnv the grass environment used to identify paths. * @param dataRange the datarange to be used if the native one is missing. */ public JGrassColorTable( JGrassMapEnvironment readerGrassEnv, double[] dataRange ) throws IOException { File colrFile = readerGrassEnv.getCOLR(); if (!colrFile.exists()) { if (dataRange != null) { rules = createDefaultColorTable(dataRange, alpha); } return; } else { BufferedReader rdr = new BufferedReader(new InputStreamReader(new FileInputStream(colrFile))); String line = rdr.readLine(); if (line == null) { rdr.close(); if (colrFile.delete()) { System.out.println("removed empty color file"); //$NON-NLS-1$ } rules = createDefaultColorTable(dataRange, alpha); return; } line = line.trim(); if (line.charAt(0) == '%') { String[] stringValues = line.split("\\s+"); //$NON-NLS-1$ 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 ) { rules.add(line + " " + alpha); //$NON-NLS-1$ } } else { while( (line = rdr.readLine()) != null ) { rules.add(line + " " + alpha); //$NON-NLS-1$ } } rdr.close(); } } /** * Creates a default rainbow color table given a data range. * * @param dataRange the data range for which the color table is created * @return the list of color rules as <code>value1:r:g:b value2:r:g:b alpha</code> */ @SuppressWarnings("nls") public static List<String> createDefaultColorTable( double[] dataRange, int alpha ) { List<String> rules = new ArrayList<String>(); // calculate the color increment float rinc = (float) (dataRange[1] - dataRange[0]) / 5; for( int i = 0; i < 5; i++ ) { 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] + " " + alpha); rules.add(rule.toString()); } return rules; } /** * Getter for the color rules. * * @return the list of color rules. */ public List<String> getColorRules() { return rules; } /** * Getter for the alpha value. * * @return the alpha value. */ public int getAlpha() { return alpha; } /** * parses a color rule. * * <p> * Arrays of doubles and colors have to be passed, that will * be filled with the values of the color rule. * </p> * * @param rule the color rule as taken from the list returned by * {@link JGrassColorTable#getColorRules()} * @param values the array of doubles to be filled with the values. * @param colors the array of {@link Color} to be filled with the colors (can be null). */ public static void parseColorRule( String rule, double[] values, Color[] colors ) { if (colors == null) { colors = new Color[2]; } String[] ruleSplit = rule.split("\\s+"); //$NON-NLS-1$ if (ruleSplit.length >= 2) { String part1 = ruleSplit[0]; String part2 = ruleSplit[1]; int alpha = 255; if (ruleSplit.length == 3) alpha = Integer.parseInt(ruleSplit[2]); String[] part1Split = part1.split(":"); //$NON-NLS-1$ String[] part2Split = part2.split(":"); //$NON-NLS-1$ if (part1Split.length == 2) { // gray scale values[0] = Double.parseDouble(part1Split[0]); colors[0] = new Color(Integer.parseInt(part1Split[1]), Integer.parseInt(part1Split[1]), Integer.parseInt(part1Split[1]), alpha); } else if (part1Split.length == 4) { // rgb values[0] = Double.parseDouble(part1Split[0]); colors[0] = new Color(Integer.parseInt(part1Split[1]), Integer.parseInt(part1Split[2]), Integer.parseInt(part1Split[3]), alpha); } else { values[0] = Double.NaN; colors[0] = new Color(0, 0, 0); } if (part2Split.length == 2) { // gray scale values[1] = Double.parseDouble(part2Split[0]); colors[1] = new Color(Integer.parseInt(part2Split[1]), Integer.parseInt(part2Split[1]), Integer.parseInt(part2Split[1]), alpha); } else if (part2Split.length == 4) { // rgb values[1] = Double.parseDouble(part2Split[0]); colors[1] = new Color(Integer.parseInt(part2Split[1]), Integer.parseInt(part2Split[2]), Integer.parseInt(part2Split[3]), alpha); } else { values[1] = Double.NaN; colors[1] = new Color(255, 255, 255); } } else if (ruleSplit.length >= 1) { String part = ruleSplit[0]; int alpha = 255; if (ruleSplit.length == 2) alpha = Integer.parseInt(ruleSplit[1]); String[] partSplit = part.split(":"); //$NON-NLS-1$ if (partSplit.length == 2) { // gray scale values[0] = Double.parseDouble(partSplit[0]); colors[0] = new Color(Integer.parseInt(partSplit[1]), Integer.parseInt(partSplit[1]), Integer.parseInt(partSplit[1]), alpha); } else if (partSplit.length == 4) { // rgb values[0] = Double.parseDouble(partSplit[0]); colors[0] = new Color(Integer.parseInt(partSplit[1]), Integer.parseInt(partSplit[2]), Integer.parseInt(partSplit[3]), alpha); } else { values[0] = Double.NaN; colors[0] = new Color(0, 0, 0); } values[1] = values[0]; colors[1] = colors[0]; } else { values[0] = -1000; colors[0] = new Color(0, 0, 0); values[1] = 1000; colors[1] = new Color(255, 255, 255); } } }