001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, Geotools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.renderer.lite.gridcoverage2d;
017:
018: // J2SE dependencies
019: import java.awt.Color;
020: import java.util.HashMap;
021: import java.util.List;
022: import java.util.Map;
023:
024: import javax.media.jai.util.Range;
025:
026: import org.geotools.coverage.Category;
027: import org.geotools.coverage.FactoryFinder;
028: import org.geotools.coverage.GridSampleDimension;
029: import org.geotools.coverage.grid.GridCoverage2D;
030: import org.geotools.coverage.grid.GridGeometry2D;
031: import org.geotools.styling.ColorMapEntry;
032: import org.geotools.styling.RasterSymbolizer;
033: import org.opengis.coverage.SampleDimension;
034: import org.opengis.coverage.grid.GridCoverage;
035: import org.opengis.filter.expression.Expression;
036:
037: /**
038: * A helper class for {@link GridCoverage} objects rendering SLD stylers
039: * support.
040: *
041: * @author Alessio Fabiani
042: * @author Simone Giannecchini
043: *
044: * @task Optimize and complete
045: * @source $URL:
046: * http://svn.geotools.org/geotools/branches/coverages_branch/trunk/gt/module/render/src/org/geotools/renderer/lite/RasterSymbolizerSupport.java $
047: */
048: public final class RasterSymbolizerSupport {
049: /** The Styled Layer Descriptor * */
050: private final RasterSymbolizer symbolizer;
051:
052: /**
053: * Constructor
054: *
055: * @param symbolizer
056: *
057: */
058: public RasterSymbolizerSupport(final RasterSymbolizer symbolizer) {
059: this .symbolizer = symbolizer;
060: }
061:
062: public GridCoverage recolorCoverage(GridCoverage grid)
063: throws IllegalArgumentException {
064: if (!(grid instanceof GridCoverage2D)) {
065: throw new IllegalArgumentException(
066: "Cannot Recolor GridCoverage: GridCoverage2D is needed.");
067: }
068:
069: // final ColorMap map = symbolizer.getColorMap();
070: // if (map == null)
071: // throw new IllegalArgumentException(
072: // "Cannot Recolor GridCoverage: ColorMap is needed.");
073: // final ColorMapEntry[] entries = map.getColorMapEntries();
074: // if (entries == null || entries.length <= 0)
075: // throw new IllegalArgumentException(
076: // "Cannot Recolor GridCoverage: ColorMapEntries are needed.");
077: // final int length = entries.length;
078: // final Map colorMap = new HashMap();
079: // for (int i = 0; i < length; i++)
080: // colorMap.put(entries[i].getQuantity().getValue(null), entries[i]
081: // .getQuantity().getValue(null));
082: // return Operations.DEFAULT.recolor(grid, new Map[] { Collections
083: // .singletonMap(null, colorMap) });
084:
085: final GridCoverage2D gridCoverage = (GridCoverage2D) grid;
086: final int numBands = gridCoverage.getNumSampleDimensions();
087: final GridSampleDimension[] targetBands = new GridSampleDimension[numBands];
088: final Map[] colorMaps = new Map[numBands];
089: for (int band = 0; band < numBands; band++) { // TODO get separated
090: // R,G,B colorMaps from
091: // symbolizer
092: final Map categories = getCategories(band);
093: colorMaps[band] = categories;
094:
095: /**
096: * Temporary solution, until the Recolor Operation is ported ...
097: */
098: targetBands[band] = (GridSampleDimension) transformColormap(
099: band, gridCoverage.getSampleDimension(band),
100: colorMaps);
101: }
102:
103: return FactoryFinder.getGridCoverageFactory(null).create(
104: gridCoverage.getName(),
105: gridCoverage.getRenderedImage(),
106: (GridGeometry2D) gridCoverage.getGridGeometry(),
107: targetBands, new GridCoverage[] { gridCoverage }, null);
108: }
109:
110: /**
111: * HELPER FUNCTIONS
112: */
113: public float getOpacity() {
114: float alpha = 1.0f;
115: Expression exp = this .symbolizer.getOpacity();
116: if (exp == null) {
117: return alpha;
118: }
119: Number number = (Number) exp.evaluate(null, Float.class);
120: if (number == null) {
121: return alpha;
122: }
123: return number.floatValue();
124: }
125:
126: public Map getCategories(final int band) {
127: final String[] labels = getLabels(band);
128: final Color[] colors = getColors(band);
129:
130: final Map categories = new HashMap();
131:
132: /**
133: * Checking Categories
134: */
135: final int labelsLength = labels.length;
136: Color[] oldCmap;
137: int length;
138: Color[] newCmap;
139: for (int i = 0; i < labelsLength; i++) {
140: if (!categories.containsKey(labels[i])) {
141: categories.put(labels[i], new Color[] { colors[i] });
142: } else {
143: oldCmap = (Color[]) categories.get(labels[i]);
144: length = oldCmap.length;
145: newCmap = new Color[length + 1];
146: System.arraycopy(oldCmap, 0, newCmap, 0, length);
147: newCmap[length] = colors[i];
148: categories.put(labels[i], newCmap);
149: }
150: }
151:
152: return categories;
153: }
154:
155: public String[] getLabels(final int band) {
156: String[] labels = null;
157: if (this .symbolizer.getColorMap() != null) {
158: final ColorMapEntry[] colors = this .symbolizer
159: .getColorMap().getColorMapEntries();
160: final int numColors = colors.length;
161: labels = new String[numColors];
162: for (int ci = 0; ci < numColors; ci++) {
163: labels[ci] = colors[ci].getLabel();
164: }
165: }
166:
167: return labels;
168: }
169:
170: public Color[] getColors(final int band) {
171: Color[] colorTable = null;
172: if (this .symbolizer.getColorMap() != null) {
173: final ColorMapEntry[] colors = this .symbolizer
174: .getColorMap().getColorMapEntries();
175: final int numColors = colors.length;
176: colorTable = new Color[numColors];
177: double opacity;
178: for (int ci = 0; ci < numColors; ci++) {
179: opacity = toOpacity(colors[ci].getOpacity());
180: colorTable[ci] = toColor(colors[ci].getColor(), opacity);
181: if (colorTable[ci] == null) {
182: return null;
183: }
184: }
185: }
186:
187: return colorTable;
188: }
189:
190: public static Color toColor(Expression exp, double opacity) {
191: if (exp == null) {
192: return null;
193: }
194: Color color = (Color) exp.evaluate(null, Color.class);
195: int alpha = new Double(Math.ceil(255.0 * opacity)).intValue();
196: if (color != null) {
197: return new Color(color.getRed(), color.getGreen(), color
198: .getBlue(), alpha);
199: } else {
200: // the value morphing code failed us .. let's try by hand
201: Object obj = exp.evaluate(null);
202: if (obj == null) {
203: return null;
204: }
205: Integer intval = Integer.decode((String) obj);
206: int i = intval.intValue();
207: return new Color((i >> 16) & 0xFF, (i >> 8) & 0xFF,
208: i & 0xFF, alpha);
209: }
210: }
211:
212: public static double toOpacity(Expression opacity) {
213: if (opacity == null) {
214: return 1.0;
215: }
216:
217: Double value = (Double) opacity.evaluate(null, Double.class);
218: if (value == null) {
219: return 1.0;
220: }
221: return value.doubleValue();
222: //
223: // opacity = (colors[ci].getOpacity() != null
224: // ? (colors[ci].getOpacity().getValue(null) instanceof String
225: // ? Double.valueOf((String) colors[ci].getOpacity().getValue(null))
226: // : (Double) colors[ci].getOpacity().getValue(null))
227: // : new Double(1.0));
228: }
229:
230: /**
231: * Transform the supplied RGB colors.
232: */
233: public SampleDimension transformColormap(final int band,
234: SampleDimension dimension, final Map[] colorMaps) {
235: if (colorMaps == null || colorMaps.length == 0) {
236: return dimension;
237: }
238: boolean changed = false;
239: final Map colorMap = colorMaps[Math.min(band,
240: colorMaps.length - 1)];
241: final List categoryList = ((GridSampleDimension) dimension)
242: .getCategories();
243: if (categoryList == null) {
244: return dimension;
245: }
246: final Category categories[] = (Category[]) categoryList
247: .toArray();
248: Category category;
249: Color[] colors;
250: final int length = categories.length;
251: Range range;
252: int lower;
253: int upper;
254: for (int j = length; --j >= 0;) {
255: category = categories[j];
256: colors = (Color[]) colorMap.get(category.getName()
257: .toString());
258: if (colors == null) {
259: if (!category.isQuantitative()) {
260: continue;
261: }
262: colors = (Color[]) colorMap.get(null);
263: if (colors == null) {
264: continue;
265: }
266: }
267: range = category.getRange();
268: lower = ((Number) range.getMinValue()).intValue();
269: upper = ((Number) range.getMaxValue()).intValue();
270: if (!range.isMinIncluded())
271: lower++;
272: if (range.isMaxIncluded())
273: upper++;
274: category = category.recolor(colors);
275: if (!categories[j].equals(category)) {
276: categories[j] = category;
277: changed = true;
278: }
279: }
280: return changed ? new GridSampleDimension(dimension
281: .getDescription(), categories, dimension.getUnits())
282: : dimension;
283: }
284: }
|