/** * 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(); }
/** * 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; }
/** * 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"); }