/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved
* (c) 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wms.capabilities;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.geoserver.catalog.LayerGroupInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.PublishedInfo;
import org.geoserver.catalog.StyleInfo;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Rule;
import org.geotools.styling.Style;
import org.geotools.util.NumberRange;
/**
* Provides utility methods required to build the capabilities document.
*
* @author Mauricio Pazos
*
*/
final class CapabilityUtil {
private CapabilityUtil(){
//utility class
}
/**
* Helper method: aggregates min/max scale denominators of a set of styles.
*
*/
private static NumberRange<Double> searchMinMaxScaleDenominator(Set<StyleInfo> styles) throws IOException {
// searches the maximum and minimum denominator in the style's rules that are contained in the style set.
double minScaleDenominator = Double.POSITIVE_INFINITY;
double maxScaleDenominator = Double.NEGATIVE_INFINITY;
for (StyleInfo styleInfo : styles) {
Style style = styleInfo.getStyle();
for (FeatureTypeStyle fts : style.featureTypeStyles()) {
for ( Rule rule : fts.rules() ) {
if ( rule.getMinScaleDenominator() < minScaleDenominator ) {
minScaleDenominator = rule.getMinScaleDenominator();
}
if ( rule.getMaxScaleDenominator() > maxScaleDenominator ) {
maxScaleDenominator = rule.getMaxScaleDenominator();
}
}
}
}
// If the initial values weren't changed by any rule in the previous step,
// then the default values, Min=0.0 and Max=infinity, are set.
if(minScaleDenominator == Double.POSITIVE_INFINITY) {
minScaleDenominator = 0.0;
}
if( maxScaleDenominator == Double.NEGATIVE_INFINITY) {
maxScaleDenominator = Double.POSITIVE_INFINITY;
}
assert minScaleDenominator <= maxScaleDenominator : "Min <= Max scale is expected";
return new NumberRange<Double>(Double.class, minScaleDenominator, maxScaleDenominator);
}
/**
* Searches the Max and Min scale denominators in the layer's styles.
*
* <pre>
* If the Min or Max values aren't present, the following default are assumed:
*
* Min Scale: 0.0
* Max Scale: infinity
* </pre>
* @param minScaleDenominator Min scale attribute (or element) name
* @param maxScaleDenominator Max scale attribute (or element) name
* @param layer
*
* @return Max and Min denominator
* @throws IOException
*/
public static NumberRange<Double> searchMinMaxScaleDenominator(final LayerInfo layer)
throws IOException {
Set<StyleInfo> stylesCopy;
StyleInfo defaultStyle;
synchronized (layer) {
stylesCopy = new HashSet<StyleInfo>(layer.getStyles());
defaultStyle = layer.getDefaultStyle();
}
if (!stylesCopy.contains(defaultStyle)) {
stylesCopy.add(defaultStyle);
}
return searchMinMaxScaleDenominator(stylesCopy);
}
/**
* Helper method: recursively collects all styles in a layergroup
*/
private static void findLayerGroupStyles(LayerGroupInfo layerGroup, Set<StyleInfo> stylesCopy) {
synchronized (layerGroup) {
for (int i = 0; i < layerGroup.getLayers().size(); i++) {
StyleInfo styleInfo = layerGroup.getStyles().get(i);
if (styleInfo == null) {
PublishedInfo publishedInfo = layerGroup.getLayers().get(i);
if (publishedInfo instanceof LayerInfo) {
styleInfo = ((LayerInfo) publishedInfo).getDefaultStyle();
stylesCopy.add(styleInfo);
} else if (publishedInfo instanceof LayerGroupInfo) {
findLayerGroupStyles((LayerGroupInfo) publishedInfo, stylesCopy);
}
} else {
stylesCopy.add(styleInfo);
}
}
}
}
/**
* Searches the Max and Min scale denominators in the layergroup's layers
*
* <pre>
* If the Min or Max values aren't present, the following default are assumed:
*
* Min Scale: 0.0
* Max Scale: infinity
* </pre>
* @param minScaleDenominator Min scale attribute (or element) name
* @param maxScaleDenominator Max scale attribute (or element) name
* @param layerGroup
*
* @return Max and Min denominator
* @throws IOException
*/
public static NumberRange<Double> searchMinMaxScaleDenominator(final LayerGroupInfo layerGroup)
throws IOException {
Set<StyleInfo> stylesCopy = new HashSet<StyleInfo>();
findLayerGroupStyles(layerGroup, stylesCopy);
return searchMinMaxScaleDenominator(stylesCopy);
}
/**
* Searches the Max and Min scale denominators for a Published (delegates to Layer orrLayerGroup methods)
*
* <pre>
* If the Min or Max values aren't present, the following default are assumed:
*
* Min Scale: 0.0
* Max Scale: infinity
* </pre>
* @param minScaleDenominator Min scale attribute (or element) name
* @param maxScaleDenominator Max scale attribute (or element) name
* @param published
*
* @return Max and Min denominator
* @throws IOException
*/
public static NumberRange<Double> searchMinMaxScaleDenominator(final PublishedInfo publishedInfo)
throws IOException {
if (publishedInfo instanceof LayerInfo) {
return searchMinMaxScaleDenominator ((LayerInfo) publishedInfo);
} else if (publishedInfo instanceof LayerGroupInfo) {
return searchMinMaxScaleDenominator ((LayerGroupInfo) publishedInfo);
}
throw new UnsupportedOperationException("PublishedInfo must be either Layer or Layergroup");
}
/**
* Computes the rendering scale taking into account the standard pixel size and the real world scale denominator.
*
* @param scaleDenominator
* @return the rendering scale.
*/
public static Double computeScaleHint(final Double scaleDenominator) {
// According to OGC SLD 1.0 specification: The "standardized rendering pixel size" is defined to be 0.28mm × 0.28mm (millimeters).
final Double sizeStandardRenderPixel = 0.00028;//(meters)
Double scaleHint = Math.sqrt(Math.pow((scaleDenominator * sizeStandardRenderPixel), 2) * 2);
return scaleHint;
}
}