/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wms.map;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.feature.FeatureTypes;
import org.geotools.styling.AnchorPoint;
import org.geotools.styling.ChannelSelection;
import org.geotools.styling.ColorMap;
import org.geotools.styling.ColorMapEntry;
import org.geotools.styling.ContrastEnhancement;
import org.geotools.styling.Displacement;
import org.geotools.styling.ExternalGraphic;
import org.geotools.styling.FeatureTypeConstraint;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Fill;
import org.geotools.styling.Graphic;
import org.geotools.styling.Halo;
import org.geotools.styling.ImageOutline;
import org.geotools.styling.LinePlacement;
import org.geotools.styling.LineSymbolizer;
import org.geotools.styling.Mark;
import org.geotools.styling.NamedLayer;
import org.geotools.styling.OverlapBehavior;
import org.geotools.styling.PointPlacement;
import org.geotools.styling.PointSymbolizer;
import org.geotools.styling.PolygonSymbolizer;
import org.geotools.styling.RasterSymbolizer;
import org.geotools.styling.Rule;
import org.geotools.styling.SelectedChannelType;
import org.geotools.styling.ShadedRelief;
import org.geotools.styling.Stroke;
import org.geotools.styling.Style;
import org.geotools.styling.StyleVisitor;
import org.geotools.styling.StyledLayer;
import org.geotools.styling.StyledLayerDescriptor;
import org.geotools.styling.Symbolizer;
import org.geotools.styling.TextSymbolizer;
import org.geotools.styling.UserLayer;
import org.opengis.feature.type.FeatureType;
import org.opengis.filter.capability.FunctionName;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Function;
import org.opengis.parameter.Parameter;
/**
* Extracts the active raster symbolizers, as long as there are some, and only raster symbolizers
* are available, without rendering transformations in place.
* In the case of mixed symbolizers it will return null
* TODO: extend this class so that it handles the case of other symbolizers applied after a raster
* symbolizer one (e.g., to draw a rectangle around a coverage)
*
* @author Andrea Aime
*
*/
public class RasterSymbolizerVisitor implements StyleVisitor {
double scaleDenominator;
FeatureType featureType;
List<RasterSymbolizer> symbolizers = new ArrayList<RasterSymbolizer>();
boolean otherSymbolizers = false;
Expression rasterTransformation = null;
boolean otherRenderingTransformations = false;
public RasterSymbolizerVisitor(double scaleDenominator, FeatureType featureType) {
this.scaleDenominator = scaleDenominator;
this.featureType = featureType;
}
public void reset() {
symbolizers.clear();
otherSymbolizers = false;
rasterTransformation = null;
otherRenderingTransformations = false;
}
public List<RasterSymbolizer> getRasterSymbolizers() {
if(otherSymbolizers || otherRenderingTransformations)
return Collections.emptyList();
else
return symbolizers;
}
public Expression getRasterRenderingTransformation() {
return rasterTransformation;
}
public void visit(StyledLayerDescriptor sld) {
for (StyledLayer sl : sld.getStyledLayers()) {
if (sl instanceof UserLayer) {
((UserLayer) sl).accept(this);
} else if (sl instanceof NamedLayer) {
((NamedLayer) sl).accept(this);
}
}
}
public void visit(NamedLayer layer) {
for (Style s : layer.getStyles())
s.accept(this);
}
public void visit(UserLayer layer) {
for (Style s : layer.getUserStyles())
s.accept(this);
}
public void visit(FeatureTypeConstraint ftc) {
// nothing to do
}
public void visit(Style style) {
for (FeatureTypeStyle fts : style.featureTypeStyles()) {
fts.accept(this);
}
}
public void visit(Rule rule) {
if (rule.getMinScaleDenominator() < scaleDenominator
&& rule.getMaxScaleDenominator() > scaleDenominator) {
for(Symbolizer s : rule.symbolizers())
s.accept(this);
}
}
public void visit(FeatureTypeStyle fts) {
// use the same logic as streaming renderer to decide if a fts is active
if(featureType == null || (featureType.getName().getLocalPart() != null)
&& (featureType.getName().getLocalPart().equalsIgnoreCase(fts.getFeatureTypeName()) ||
FeatureTypes.isDecendedFrom(featureType, null, fts.getFeatureTypeName()))) {
Expression tx = fts.getTransformation();
if(tx != null) {
boolean rasterTransformation = false;
if(tx instanceof Function) {
Function f = (Function) tx;
FunctionName name = f.getFunctionName();
if(name != null) {
Parameter<?> result = name.getReturn();
if(result != null) {
if(GridCoverage2D.class.isAssignableFrom(result.getType())) {
rasterTransformation = true;
this.rasterTransformation = tx;
}
}
}
}
otherRenderingTransformations |= !rasterTransformation;
}
for (Rule r : fts.rules()) {
r.accept(this);
}
}
}
public void visit(Fill fill) {
// nothing to do
}
public void visit(Stroke stroke) {
// nothing to do
}
public void visit(Symbolizer sym) {
if (sym instanceof RasterSymbolizer) {
visit((RasterSymbolizer) sym);
} else {
otherSymbolizers = true;
}
}
public void visit(PointSymbolizer ps) {
otherSymbolizers = true;
}
public void visit(LineSymbolizer line) {
otherSymbolizers = true;
}
public void visit(PolygonSymbolizer poly) {
otherSymbolizers = true;
}
public void visit(TextSymbolizer text) {
otherSymbolizers = true;
}
public void visit(RasterSymbolizer raster) {
this.symbolizers.add(raster);
}
public void visit(Graphic gr) {
// nothing to do
}
public void visit(Mark mark) {
// nothing to do
}
public void visit(ExternalGraphic exgr) {
// nothing to do
}
public void visit(PointPlacement pp) {
// nothing to do
}
public void visit(AnchorPoint ap) {
// nothing to do
}
public void visit(Displacement dis) {
// nothing to do
}
public void visit(LinePlacement lp) {
// nothing to do
}
public void visit(Halo halo) {
// nothing to do
}
public void visit(ColorMap colorMap) {
// nothing to do
}
public void visit(ColorMapEntry colorMapEntry) {
// nothing to do
}
public void visit(ContrastEnhancement contrastEnhancement) {
// nothing to do
}
public void visit(ImageOutline outline) {
// nothing to do
}
public void visit(ChannelSelection cs) {
// nothing to do
}
public void visit(OverlapBehavior ob) {
// nothing to do
}
public void visit(SelectedChannelType sct) {
// nothing to do
}
public void visit(ShadedRelief sr) {
// nothing to do
}
}