/**
   * Creates a {@link SimpleFeatureType} that exposes a coverage as a collections of feature points,
   * mapping the centre of each pixel as a point plus all the bands as attributes.
   *
   * <p>The FID is the long that combines x+y*width.
   *
   * @param gc2d the {@link GridCoverage2D} to wrap.
   * @param geometryClass the class for the geometry.
   * @return a {@link SimpleFeatureType} or <code>null</code> in case we are unable to wrap the
   *     coverage
   */
  public static SimpleFeatureType createFeatureType(
      final GridCoverage2D gc2d, final Class<? extends Geometry> geometryClass) {

    // checks
    Utilities.ensureNonNull("gc2d", gc2d);

    // building a feature type for this coverage
    final SimpleFeatureTypeBuilder ftBuilder = new SimpleFeatureTypeBuilder();
    ftBuilder.setName(gc2d.getName().toString());
    ftBuilder.setNamespaceURI("http://www.geotools.org/");

    // CRS
    ftBuilder.setCRS(gc2d.getCoordinateReferenceSystem2D());
    //		ftBuilder.setCRS(DefaultEngineeringCRS.GENERIC_2D);

    // TYPE is as follows the_geom | band
    ftBuilder.setDefaultGeometry("the_geom");
    ftBuilder.add("the_geom", geometryClass);
    if (!geometryClass.equals(Point.class)) {
      ftBuilder.add("value", Double.class);
    } else {

      // get sample type on bands
      final GridSampleDimension[] sampleDimensions = gc2d.getSampleDimensions();
      for (GridSampleDimension sd : sampleDimensions) {
        final SampleDimensionType sdType = sd.getSampleDimensionType();
        final int dataBuffType = TypeMap.getDataBufferType(sdType);

        // TODO I think this should be a public utility inside the FeatureUtilities class
        @SuppressWarnings("rawtypes")
        final Class bandClass;
        switch (dataBuffType) {
          case DataBuffer.TYPE_BYTE:
            bandClass = Byte.class;
            break;
          case DataBuffer.TYPE_DOUBLE:
            bandClass = Double.class;
            break;
          case DataBuffer.TYPE_FLOAT:
            bandClass = Float.class;
            break;
          case DataBuffer.TYPE_INT:
            bandClass = Integer.class;
            break;
          case DataBuffer.TYPE_SHORT:
          case DataBuffer.TYPE_USHORT:
            bandClass = Short.class;
            break;
          case DataBuffer.TYPE_UNDEFINED:
          default:
            return null;
        }
        ftBuilder.add(sd.getDescription().toString(), bandClass);
      }
    }
    return ftBuilder.buildFeatureType();
  }
Example #2
0
  /**
   * Wraps a grid coverage into a Feature. Code lifted from ArcGridDataSource (temporary).
   *
   * @param coverage the grid coverage.
   * @return a feature with the grid coverage envelope as the geometry and the grid coverage itself
   *     in the "grid" attribute.
   */
  @SuppressWarnings("unchecked")
  public static SimpleFeatureCollection wrapGridCoverage(final GridCoverage2D coverage)
      throws TransformException, SchemaException {
    final Polygon bounds = getPolygon(coverage.getEnvelope2D());
    final CoordinateReferenceSystem sourceCRS = coverage.getCoordinateReferenceSystem2D();

    SimpleFeatureTypeBuilder ftb = new SimpleFeatureTypeBuilder(getTypeFactory());
    ftb.setName("GridCoverage");
    ftb.add("geom", Polygon.class, sourceCRS);
    ftb.add("grid", GridCoverage.class);
    SimpleFeatureType schema = ftb.buildFeatureType();

    // create the feature
    SimpleFeatureBuilder fb = new SimpleFeatureBuilder(schema, getFeatureFactory());
    fb.add(bounds);
    fb.add(coverage);
    SimpleFeature feature = fb.buildFeature(null);

    final DefaultFeatureCollection collection = new DefaultFeatureCollection();
    collection.add(feature);
    return collection;
  }
Example #3
0
  /**
   * Applies a crop operation to a coverage.
   *
   * @see
   *     org.geotools.coverage.processing.AbstractOperation#doOperation(org.opengis.parameter.ParameterValueGroup,
   *     org.geotools.factory.Hints)
   */
  @SuppressWarnings("unchecked")
  public Coverage doOperation(ParameterValueGroup parameters, Hints hints) {

    final Geometry cropRoi; // extracted from parameters
    GeneralEnvelope cropEnvelope = null; // extracted from parameters
    final GridCoverage2D source; // extracted from parameters
    final double roiTolerance = parameters.parameter(Crop.PARAMNAME_ROITOLERANCE).doubleValue();
    final boolean forceMosaic = parameters.parameter(Crop.PARAMNAME_FORCEMOSAIC).booleanValue();

    // /////////////////////////////////////////////////////////////////////
    //
    // Assigning and checking input parameters
    //
    // ///////////////////////////////////////////////////////////////////

    // source coverage
    final ParameterValue sourceParameter = parameters.parameter("Source");
    if (sourceParameter == null || !(sourceParameter.getValue() instanceof GridCoverage2D)) {
      throw new CannotCropException(
          Errors.format(ErrorKeys.NULL_PARAMETER_$2, "Source", GridCoverage2D.class.toString()));
    }
    source = (GridCoverage2D) sourceParameter.getValue();

    // Check Envelope and ROI existence - we need at least one of them
    final ParameterValue envelopeParameter = parameters.parameter(PARAMNAME_ENVELOPE);
    final ParameterValue roiParameter = parameters.parameter(PARAMNAME_ROI);

    if ((envelopeParameter == null || envelopeParameter.getValue() == null)
        && (roiParameter == null || roiParameter.getValue() == null))
      throw new CannotCropException(
          Errors.format(
              ErrorKeys.NULL_PARAMETER_$2, PARAMNAME_ENVELOPE, GeneralEnvelope.class.toString()));

    Object envelope = envelopeParameter.getValue();
    if (envelope != null) {
      if (envelope instanceof GeneralEnvelope) {
        cropEnvelope = (GeneralEnvelope) envelope;
      } else if (envelope instanceof Envelope) {
        cropEnvelope = new GeneralEnvelope((Envelope) envelope);
      }
    }
    // may be null

    // Check crop ROI
    try {
      cropRoi =
          IntersectUtils.unrollGeometries(
              (Geometry) roiParameter.getValue()); // may throw if format not correct
    } catch (IllegalArgumentException ex) {
      throw new CannotCropException(
          Errors.format(ErrorKeys.ILLEGAL_ARGUMENT_$2, PARAMNAME_ROI, ex.getMessage()), ex);
    }

    // Setting a GeneralEnvelope from ROI if needed
    if (cropRoi != null && cropEnvelope == null) {
      Envelope e2d =
          JTS.getEnvelope2D(cropRoi.getEnvelopeInternal(), source.getCoordinateReferenceSystem());
      cropEnvelope = new GeneralEnvelope(e2d);
    }

    // /////////////////////////////////////////////////////////////////////
    //
    // Initialization
    //
    // We take the crop envelope and the source envelope then we check their
    // crs and we also check if they ever overlap.
    //
    // /////////////////////////////////////////////////////////////////////
    // envelope of the source coverage
    final Envelope2D sourceEnvelope = source.getEnvelope2D();
    // crop envelope
    Envelope2D destinationEnvelope = new Envelope2D(cropEnvelope);
    CoordinateReferenceSystem sourceCRS = sourceEnvelope.getCoordinateReferenceSystem();
    CoordinateReferenceSystem destinationCRS = destinationEnvelope.getCoordinateReferenceSystem();
    if (destinationCRS == null) {
      // Do not change the user provided object - clone it first.
      final Envelope2D ge = new Envelope2D(destinationEnvelope);
      destinationCRS = source.getCoordinateReferenceSystem2D();
      ge.setCoordinateReferenceSystem(destinationCRS);
      destinationEnvelope = ge;
    }

    // //
    //
    // Source and destination crs must be equals
    //
    // //
    if (!CRS.equalsIgnoreMetadata(sourceCRS, destinationCRS)) {
      throw new CannotCropException(
          Errors.format(
              ErrorKeys.MISMATCHED_ENVELOPE_CRS_$2,
              sourceCRS.getName().getCode(),
              destinationCRS.getName().getCode()));
    }

    if (cropRoi != null) {
      // TODO: check ROI SRID
    }

    // //
    //
    // Check the intersection and, if needed, do the crop operation.
    //
    // //
    final GeneralEnvelope intersectionEnvelope =
        new GeneralEnvelope((Envelope) destinationEnvelope);
    intersectionEnvelope.setCoordinateReferenceSystem(source.getCoordinateReferenceSystem());
    // intersect the envelopes
    intersectionEnvelope.intersect(sourceEnvelope);
    if (intersectionEnvelope.isEmpty())
      throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP));

    // intersect the ROI with the intersection envelope and throw an error if they do not intersect
    if (cropRoi != null) {
      final Geometry jis =
          JTS.toGeometry(
              (com.vividsolutions.jts.geom.Envelope) new ReferencedEnvelope(intersectionEnvelope));
      if (!IntersectUtils.intersects(cropRoi, jis))
        throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP));
    }

    // //
    //
    // Get the grid-to-world transform by keeping into account translation
    // of grid geometry constructor for respecting OGC PIXEL-IS-CENTER
    // ImageDatum assumption.
    //
    // //
    final AffineTransform sourceCornerGridToWorld =
        (AffineTransform)
            ((GridGeometry2D) source.getGridGeometry()).getGridToCRS(PixelInCell.CELL_CORNER);

    // //
    //
    // I set the tolerance as half the scale factor of the grid-to-world
    // transform. This should more or less means in most cases "don't bother
    // to crop if the new envelope is as close to the old one that we go
    // deep under pixel size."
    //
    // //
    final double tolerance = XAffineTransform.getScale(sourceCornerGridToWorld);
    if (cropRoi != null || !intersectionEnvelope.equals(sourceEnvelope, tolerance / 2.0, false)) {
      cropEnvelope = intersectionEnvelope.clone();
      return buildResult(
          cropEnvelope,
          cropRoi,
          roiTolerance,
          forceMosaic,
          (hints instanceof Hints) ? (Hints) hints : new Hints(hints),
          source,
          sourceCornerGridToWorld);
    } else {
      // //
      //
      // Note that in case we don't crop at all, WE DO NOT UPDATE the
      // envelope. If we did we might end up doing multiple successive
      // crop without actually cropping the image but, still, we would
      // shrink the envelope each time. Just think about having a loop
      // that crops recursively the same coverage specifying each time an
      // envelope whose URC is only a a scale quarter close to the LLC of
      // the old one. We would never crop the raster but we would modify
      // the grid-to-world transform each time.
      //
      // //
      return source;
    }
  }
    @Override
    public void encode(Object o) throws IllegalArgumentException {
      // register namespaces provided by extended capabilities
      NamespaceSupport namespaces = getNamespaceSupport();
      namespaces.declarePrefix("wcscrs", "http://www.opengis.net/wcs/service-extension/crs/1.0");
      namespaces.declarePrefix(
          "int", "http://www.opengis.net/WCS_service-extension_interpolation/1.0");
      namespaces.declarePrefix("gml", "http://www.opengis.net/gml/3.2");
      namespaces.declarePrefix("gmlcov", "http://www.opengis.net/gmlcov/1.0");
      namespaces.declarePrefix("swe", "http://www.opengis.net/swe/2.0");
      namespaces.declarePrefix("xlink", "http://www.w3.org/1999/xlink");
      namespaces.declarePrefix("xsi", "http://www.w3.org/2001/XMLSchema-instance");

      for (WCS20CoverageMetadataProvider cp : extensions) {
        cp.registerNamespaces(namespaces);
      }

      // is this a GridCoverage?
      if (!(o instanceof GridCoverage2D)) {
        throw new IllegalArgumentException(
            "Provided object is not a GridCoverage2D:"
                + (o != null ? o.getClass().toString() : "null"));
      }
      final GridCoverage2D gc2d = (GridCoverage2D) o;
      // we are going to use this name as an ID
      final String gcName = gc2d.getName().toString(Locale.getDefault());

      // get the crs and look for an EPSG code
      final CoordinateReferenceSystem crs = gc2d.getCoordinateReferenceSystem2D();
      List<String> axesNames =
          GMLTransformer.this.envelopeDimensionsMapper.getAxesNames(gc2d.getEnvelope2D(), true);

      // lookup EPSG code
      Integer EPSGCode = null;
      try {
        EPSGCode = CRS.lookupEpsgCode(crs, false);
      } catch (FactoryException e) {
        throw new IllegalStateException("Unable to lookup epsg code for this CRS:" + crs, e);
      }
      if (EPSGCode == null) {
        throw new IllegalStateException("Unable to lookup epsg code for this CRS:" + crs);
      }
      final String srsName = GetCoverage.SRS_STARTER + EPSGCode;
      // handle axes swap for geographic crs
      final boolean axisSwap = CRS.getAxisOrder(crs).equals(AxisOrder.EAST_NORTH);

      final AttributesImpl attributes = new AttributesImpl();
      helper.registerNamespaces(getNamespaceSupport(), attributes);

      // using Name as the ID
      attributes.addAttribute(
          "", "gml:id", "gml:id", "", gc2d.getName().toString(Locale.getDefault()));
      start("gml:RectifiedGridCoverage", attributes);

      // handle domain
      final StringBuilder builder = new StringBuilder();
      for (String axisName : axesNames) {
        builder.append(axisName).append(" ");
      }
      String axesLabel = builder.substring(0, builder.length() - 1);
      try {
        GeneralEnvelope envelope = new GeneralEnvelope(gc2d.getEnvelope());
        handleBoundedBy(envelope, axisSwap, srsName, axesLabel, null);
      } catch (IOException ex) {
        throw new WCS20Exception(ex);
      }

      // handle domain
      builder.setLength(0);
      axesNames =
          GMLTransformer.this.envelopeDimensionsMapper.getAxesNames(gc2d.getEnvelope2D(), false);
      for (String axisName : axesNames) {
        builder.append(axisName).append(" ");
      }
      axesLabel = builder.substring(0, builder.length() - 1);
      handleDomainSet(gc2d.getGridGeometry(), gc2d.getDimension(), gcName, srsName, axisSwap);

      // handle rangetype
      handleRangeType(gc2d);

      // handle coverage function
      final GridEnvelope2D ge2D = gc2d.getGridGeometry().getGridRange2D();
      handleCoverageFunction(ge2D, axisSwap);

      // handle range
      handleRange(gc2d);

      // handle metadata OPTIONAL
      try {
        handleMetadata(null, null);
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }

      end("gml:RectifiedGridCoverage");
    }