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);
    }
  }
Пример #4
0
  /**
   * 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;
  }