private static void forceSRS(GetMapRequest getMap, String srs) { getMap.setSRS(srs); try { getMap.setCrs(CRS.decode(srs)); } catch (NoSuchAuthorityCodeException e) { e.printStackTrace(); } catch (FactoryException e) { e.printStackTrace(); } }
public static GetMapRequest autoSetMissingProperties(GetMapRequest getMap) { // set the defaults if (getMap.getFormat() == null) { getMap.setFormat(FORMAT); } if ((getMap.getStyles() == null) || getMap.getStyles().isEmpty()) { // set styles to be the defaults for the specified layers // TODO: should this be part of core WMS logic? is so lets throw // this // into the GetMapKvpRequestReader if ((getMap.getLayers() != null) && (getMap.getLayers().size() > 0)) { ArrayList<Style> styles = new ArrayList<Style>(getMap.getLayers().size()); for (int i = 0; i < getMap.getLayers().size(); i++) { styles.add(getMap.getLayers().get(i).getDefaultStyle()); } getMap.setStyles(styles); } else { getMap.setStyles(STYLES); } } // auto-magic missing info configuration autoSetBoundsAndSize(getMap); return getMap; }
/** * This method tries to automatically determine SRS, bounding box and output size based on the * layers provided by the user and any other parameters. * * <p>If bounds are not specified by the user, they are automatically se to the union of the * bounds of all layers. * * <p>The size of the output image defaults to 512 pixels, the height is automatically determined * based on the width to height ratio of the requested layers. This is also true if either height * or width are specified by the user. If both height and width are specified by the user, the * automatically determined bounding box will be adjusted to fit inside these bounds. * * <p>General idea 1) Figure out whether SRS has been specified, fall back to EPSG:4326 2) * Determine whether all requested layers use the same SRS, - if so, try to do bounding box * calculations in native coordinates 3) Aggregate the bounding boxes (in EPSG:4326 or native) 4a) * If bounding box has been specified, adjust height of image to match 4b) If bounding box has not * been specified, but height has, adjust bounding box */ public static void autoSetBoundsAndSize(GetMapRequest getMap) { // Get the layers List<MapLayerInfo> layers = getMap.getLayers(); /** 1) Check what SRS has been requested */ String reqSRS = getMap.getSRS(); // if none, try to determine which SRS to use // and keep track of whether we can use native all the way boolean useNativeBounds = true; if (reqSRS == null) { reqSRS = guessCommonSRS(layers); forceSRS(getMap, reqSRS); } /** 2) Compare requested SRS */ for (int i = 0; useNativeBounds && i < layers.size(); i++) { if (layers.get(i) != null) { String layerSRS = layers.get(i).getSRS(); useNativeBounds = reqSRS.equalsIgnoreCase(layerSRS) && layers.get(i).getResource().getNativeBoundingBox() != null; } else { useNativeBounds = false; } } CoordinateReferenceSystem reqCRS; try { reqCRS = CRS.decode(reqSRS); } catch (Exception e) { throw new ServiceException(e); } // Ready to determine the bounds based on the layers, if not specified Envelope aggregateBbox = getMap.getBbox(); boolean specifiedBbox = true; // If bbox is not specified by request if (aggregateBbox == null) { specifiedBbox = false; // Get the bounding box from the layers for (int i = 0; i < layers.size(); i++) { MapLayerInfo layerInfo = layers.get(i); ReferencedEnvelope curbbox; try { curbbox = layerInfo.getLatLongBoundingBox(); if (useNativeBounds) { ReferencedEnvelope nativeBbox = layerInfo.getBoundingBox(); if (nativeBbox == null) { try { CoordinateReferenceSystem nativeCrs = layerInfo.getCoordinateReferenceSystem(); nativeBbox = curbbox.transform(nativeCrs, true); } catch (Exception e) { throw new ServiceException("Best effort native bbox computation failed", e); } } curbbox = nativeBbox; } } catch (Exception e) { throw new RuntimeException(e); } if (aggregateBbox != null) { aggregateBbox.expandToInclude(curbbox); } else { aggregateBbox = curbbox; } } ReferencedEnvelope ref = null; // Reproject back to requested SRS if we have to if (!useNativeBounds && !reqSRS.equalsIgnoreCase(SRS)) { try { ref = new ReferencedEnvelope(aggregateBbox, CRS.decode("EPSG:4326")); aggregateBbox = ref.transform(reqCRS, true); } catch (ProjectionException pe) { ref.expandBy(-1 * ref.getWidth() / 50, -1 * ref.getHeight() / 50); try { aggregateBbox = ref.transform(reqCRS, true); } catch (FactoryException e) { e.printStackTrace(); } catch (TransformException e) { e.printStackTrace(); } // And again... } catch (NoSuchAuthorityCodeException e) { e.printStackTrace(); } catch (TransformException e) { e.printStackTrace(); } catch (FactoryException e) { e.printStackTrace(); } } } // Just in case if (aggregateBbox == null) { forceSRS(getMap, DefaultWebMapService.SRS); aggregateBbox = DefaultWebMapService.BBOX; } // Start the processing of adjust either the bounding box // or the pixel height / width double bbheight = aggregateBbox.getHeight(); double bbwidth = aggregateBbox.getWidth(); double bbratio = bbwidth / bbheight; double mheight = getMap.getHeight(); double mwidth = getMap.getWidth(); if (mheight > 0.5 && mwidth > 0.5 && specifiedBbox) { // This person really doesnt want our help, // we'll warp it any way they like it... } else { if (mheight > 0.5 && mwidth > 0.5) { // Fully specified, need to adjust bbox double mratio = mwidth / mheight; // Adjust bounds to be less than ideal to meet spec if (bbratio > mratio) { // Too wide, need to increase height of bb double diff = ((bbwidth / mratio) - bbheight) / 2; aggregateBbox.expandBy(0, diff); } else { // Too tall, need to increase width of bb double diff = ((bbheight * mratio) - bbwidth) / 2; aggregateBbox.expandBy(diff, 0); } adjustBounds(reqSRS, aggregateBbox); } else if (mheight > 0.5) { mwidth = bbratio * mheight; } else { if (mwidth > 0.5) { mheight = (mwidth / bbratio >= 1) ? mwidth / bbratio : 1; } else { if (bbratio > 1) { mwidth = MAX_SIDE; mheight = (mwidth / bbratio >= 1) ? mwidth / bbratio : 1; } else { mheight = MAX_SIDE; mwidth = (mheight * bbratio >= 1) ? mheight * bbratio : 1; } // make sure OL output height is sufficient to show the OL scale bar fully if (mheight < MIN_OL_HEIGHT && ("application/openlayers".equalsIgnoreCase(getMap.getFormat()) || "openlayers".equalsIgnoreCase(getMap.getFormat()))) { mheight = MIN_OL_HEIGHT; mwidth = (mheight * bbratio >= 1) ? mheight * bbratio : 1; } } } // Actually set the bounding box and size of image getMap.setBbox(aggregateBbox); getMap.setWidth((int) mwidth); getMap.setHeight((int) mheight); } }
/** * Returns the read parameters for the specified layer, merging some well known request parameters * into the read parameters if possible * * @param request * @param mapLayerInfo * @param layerFilter * @param reader * @return */ public GeneralParameterValue[] getWMSReadParameters( final GetMapRequest request, final MapLayerInfo mapLayerInfo, final Filter layerFilter, final List<Object> times, final List<Object> elevations, final GridCoverage2DReader reader, boolean readGeom) throws IOException { // setup the scene final ParameterValueGroup readParametersDescriptor = reader.getFormat().getReadParameters(); CoverageInfo coverage = mapLayerInfo.getCoverage(); MetadataMap metadata = coverage.getMetadata(); GeneralParameterValue[] readParameters = CoverageUtils.getParameters(readParametersDescriptor, coverage.getParameters(), readGeom); ReaderDimensionsAccessor dimensions = new ReaderDimensionsAccessor(reader); // pass down time final DimensionInfo timeInfo = metadata.get(ResourceInfo.TIME, DimensionInfo.class); // add the descriptors for custom dimensions final List<GeneralParameterDescriptor> parameterDescriptors = new ArrayList<GeneralParameterDescriptor>( readParametersDescriptor.getDescriptor().descriptors()); Set<ParameterDescriptor<List>> dynamicParameters = reader.getDynamicParameters(); parameterDescriptors.addAll(dynamicParameters); if (timeInfo != null && timeInfo.isEnabled()) { // handle "default" List<Object> fixedTimes = new ArrayList<Object>(times); for (int i = 0; i < fixedTimes.size(); i++) { if (fixedTimes.get(i) == null) { fixedTimes.set(i, getDefaultTime(coverage)); } } // pass down the parameters readParameters = CoverageUtils.mergeParameter( parameterDescriptors, readParameters, fixedTimes, "TIME", "Time"); } // pass down elevation final DimensionInfo elevationInfo = metadata.get(ResourceInfo.ELEVATION, DimensionInfo.class); if (elevationInfo != null && elevationInfo.isEnabled()) { // handle "default" List<Object> fixedElevations = new ArrayList<Object>(elevations); for (int i = 0; i < fixedElevations.size(); i++) { if (fixedElevations.get(i) == null) { fixedElevations.set(i, getDefaultElevation(coverage)); } } readParameters = CoverageUtils.mergeParameter( parameterDescriptors, readParameters, fixedElevations, "ELEVATION", "Elevation"); } if (layerFilter != null && readParameters != null) { // test for default [empty is replaced with INCLUDE filter] ]filter for (int i = 0; i < readParameters.length; i++) { GeneralParameterValue param = readParameters[i]; GeneralParameterDescriptor pd = param.getDescriptor(); if (pd.getName().getCode().equalsIgnoreCase("FILTER")) { final ParameterValue pv = (ParameterValue) pd.createValue(); // if something different from the default INCLUDE filter is specified if (layerFilter != Filter.INCLUDE) { // override the default filter pv.setValue(layerFilter); readParameters[i] = pv; } break; } } } // custom dimensions List<String> customDomains = new ArrayList(dimensions.getCustomDomains()); for (String domain : new ArrayList<String>(customDomains)) { List<String> values = request.getCustomDimension(domain); if (values != null) { readParameters = CoverageUtils.mergeParameter(parameterDescriptors, readParameters, values, domain); customDomains.remove(domain); } } // see if we have any custom domain for which we have to set the default value if (!customDomains.isEmpty()) { for (String name : customDomains) { final DimensionInfo customInfo = metadata.get(ResourceInfo.CUSTOM_DIMENSION_PREFIX + name, DimensionInfo.class); if (customInfo != null && customInfo.isEnabled()) { final ArrayList<String> val = new ArrayList<String>(1); val.add(getDefaultCustomDimensionValue(name, coverage, String.class)); readParameters = CoverageUtils.mergeParameter(parameterDescriptors, readParameters, val, name); } } } return readParameters; }