@Test public void NetCDFNoDataOperation() throws NoSuchAuthorityCodeException, FactoryException, IOException, ParseException { File mosaic = new File(TestData.file(this, "."), "NetCDFGOME2"); if (mosaic.exists()) { FileUtils.deleteDirectory(mosaic); } assertTrue(mosaic.mkdirs()); File file = TestData.file(this, "DUMMY.GOME2.NO2.PGL.nc"); FileUtils.copyFileToDirectory(file, mosaic); file = new File(mosaic, "DUMMY.GOME2.NO2.PGL.nc"); final Hints hints = new Hints(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, CRS.decode("EPSG:4326", true)); // Get format final AbstractGridFormat format = (AbstractGridFormat) GridFormatFinder.findFormat(file.toURI().toURL(), hints); final NetCDFReader reader = (NetCDFReader) format.getReader(file.toURI().toURL(), hints); assertNotNull(format); GridCoverage2D gc = null; try { String[] names = reader.getGridCoverageNames(); names = new String[] {names[0]}; gc = reader.read(null); } catch (Throwable t) { throw new RuntimeException(t); } finally { if (reader != null) { try { reader.dispose(); } catch (Throwable t) { // Does nothing } } } // Checking NoData Object noData = CoverageUtilities.getNoDataProperty(gc); assertNotNull(noData); assertTrue(noData instanceof NoDataContainer); Double d = ((NoDataContainer) noData).getAsSingleValue(); assertEquals(d, -999d, DELTA); // Try to execute an operation on the NoData and check if the result contains also NoData CoverageProcessor instance = CoverageProcessor.getInstance(); Operation scale = instance.getOperation("Scale"); ParameterValueGroup params = scale.getParameters(); params.parameter("Source0").setValue(gc); params.parameter("backgroundValues").setValue(new double[] {0}); GridCoverage2D result = (GridCoverage2D) instance.doOperation(params); noData = CoverageUtilities.getNoDataProperty(result); assertNotNull(noData); assertTrue(noData instanceof NoDataContainer); d = ((NoDataContainer) noData).getAsSingleValue(); assertEquals(d, 0d, DELTA); }
/** * Gets resolution information about the coverage itself. * * @param reader an {@link ImageReader} to use for getting the resolution information. * @throws IOException * @throws TransformException * @throws DataSourceException */ private void getResolutionInfo(ImageReader reader) throws IOException, TransformException { // // // // get the dimension of the high resolution image and compute the // resolution // // // final Rectangle originalDim = new Rectangle(0, 0, reader.getWidth(0), reader.getHeight(0)); if (originalGridRange == null) { originalGridRange = new GridEnvelope2D(originalDim); } // /// // // setting the higher resolution available for this coverage // // /// highestRes = CoverageUtilities.getResolution((AffineTransform) raster2Model); if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine( new StringBuffer("Highest Resolution = [") .append(highestRes[0]) .append(",") .append(highestRes[1]) .toString()); }
public void handleSampleDimensionNilValues(GridCoverage2D gc2d, double[] nodataValues) { start("swe:nilValues"); start("swe:NilValues"); if (nodataValues != null && nodataValues.length > 0) { for (double nodata : nodataValues) { final AttributesImpl nodataAttr = new AttributesImpl(); nodataAttr.addAttribute( "", "reason", "reason", "", "http://www.opengis.net/def/nil/OGC/0/unknown"); element("swe:nilValue", String.valueOf(nodata), nodataAttr); } } else if (gc2d != null) { // do we have already a a NO_DATA value at hand? if (gc2d.getProperties().containsKey("GC_NODATA")) { String nodata = (String) gc2d.getProperties().get("GC_NODATA"); // TODO test me final AttributesImpl nodataAttr = new AttributesImpl(); nodataAttr.addAttribute( "", "reason", "reason", "", "http://www.opengis.net/def/nil/OGC/0/unknown"); element("swe:nilValue", nodata, nodataAttr); } else { // let's suggest some meaningful value from the data type of the underlying image Number nodata = CoverageUtilities.suggestNoDataValue( gc2d.getRenderedImage().getSampleModel().getDataType()); final AttributesImpl nodataAttr = new AttributesImpl(); nodataAttr.addAttribute( "", "reason", "reason", "", "http://www.opengis.net/def/nil/OGC/0/unknown"); element("swe:nilValue", nodata.toString(), nodataAttr); } } end("swe:NilValues"); end("swe:nilValues"); }
@Test public void NetCDFNoData() throws NoSuchAuthorityCodeException, FactoryException, IOException, ParseException { File mosaic = new File(TestData.file(this, "."), "NetCDFGOME2"); if (mosaic.exists()) { FileUtils.deleteDirectory(mosaic); } assertTrue(mosaic.mkdirs()); File file = TestData.file(this, "DUMMY.GOME2.NO2.PGL.nc"); FileUtils.copyFileToDirectory(file, mosaic); file = new File(mosaic, "DUMMY.GOME2.NO2.PGL.nc"); final Hints hints = new Hints(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, CRS.decode("EPSG:4326", true)); // Get format final AbstractGridFormat format = (AbstractGridFormat) GridFormatFinder.findFormat(file.toURI().toURL(), hints); final NetCDFReader reader = (NetCDFReader) format.getReader(file.toURI().toURL(), hints); assertNotNull(format); try { String[] names = reader.getGridCoverageNames(); names = new String[] {names[0]}; GridCoverage2D gc = reader.read(null); Object noData = CoverageUtilities.getNoDataProperty(gc); assertNotNull(noData); assertTrue(noData instanceof NoDataContainer); Double d = ((NoDataContainer) noData).getAsSingleValue(); assertEquals(d, -999d, DELTA); } catch (Throwable t) { throw new RuntimeException(t); } finally { if (reader != null) { try { reader.dispose(); } catch (Throwable t) { // Does nothing } } } }
/** * Applies the band select operation to a grid coverage. * * @param cropEnvelope the target envelope; always not null * @param cropROI the target ROI shape; nullable * @param roiTolerance; as read from op's params * @param sourceCoverage is the source {@link GridCoverage2D} that we want to crop. * @param hints A set of rendering hints, or {@code null} if none. * @param sourceGridToWorldTransform is the 2d grid-to-world transform for the source coverage. * @return The result as a grid coverage. */ private static GridCoverage2D buildResult( final GeneralEnvelope cropEnvelope, final Geometry cropROI, final double roiTolerance, final boolean forceMosaic, final Hints hints, final GridCoverage2D sourceCoverage, final AffineTransform sourceGridToWorldTransform) { // // Getting the source coverage and its child geolocation objects // final RenderedImage sourceImage = sourceCoverage.getRenderedImage(); final GridGeometry2D sourceGridGeometry = ((GridGeometry2D) sourceCoverage.getGridGeometry()); final GridEnvelope2D sourceGridRange = sourceGridGeometry.getGridRange2D(); // // Now we try to understand if we have a simple scale and translate or a // more elaborated grid-to-world transformation n which case a simple // crop could not be enough, but we may need a more elaborated chain of // operation in order to do a good job. As an instance if we // have a rotation which is not multiple of PI/2 we have to use // the mosaic with a ROI // final boolean isSimpleTransform = CoverageUtilities.isSimpleGridToWorldTransform(sourceGridToWorldTransform, EPS); // Do we need to explode the Palette to RGB(A)? // int actionTaken = 0; // // // // Layout // // // final RenderingHints targetHints = new RenderingHints(null); if (hints != null) targetHints.add(hints); final ImageLayout layout = initLayout(sourceImage, targetHints); targetHints.put(JAI.KEY_IMAGE_LAYOUT, layout); // // prepare the processor to use for this operation // final JAI processor = OperationJAI.getJAI(targetHints); final boolean useProvidedProcessor = !processor.equals(JAI.getDefaultInstance()); try { if (cropROI != null) { // replace the cropEnvelope with the envelope of the intersection // of the ROI and the cropEnvelope. // Remember that envelope(intersection(roi,cropEnvelope)) != intersection(cropEnvelope, // envelope(roi)) final Polygon modelSpaceROI = FeatureUtilities.getPolygon(cropEnvelope, GFACTORY); Geometry intersection = IntersectUtils.intersection(cropROI, modelSpaceROI); Envelope2D e2d = JTS.getEnvelope2D( intersection.getEnvelopeInternal(), cropEnvelope.getCoordinateReferenceSystem()); GeneralEnvelope ge = new GeneralEnvelope((org.opengis.geometry.Envelope) e2d); cropEnvelope.setEnvelope(ge); } // // // // Build the new range by keeping into // account translation of grid geometry constructor for respecting // OGC PIXEL-IS-CENTER ImageDatum assumption. // // // final AffineTransform sourceWorldToGridTransform = sourceGridToWorldTransform.createInverse(); // // // // finalRasterArea will hold the smallest rectangular integer raster area that contains the // floating point raster // area which we obtain when applying the world-to-grid transform to the cropEnvelope. Note // that we need to intersect // such an area with the area covered by the source coverage in order to be sure we do not try // to crop outside the // bounds of the source raster. // // // final Rectangle2D finalRasterAreaDouble = XAffineTransform.transform( sourceWorldToGridTransform, cropEnvelope.toRectangle2D(), null); final Rectangle finalRasterArea = finalRasterAreaDouble.getBounds(); // intersection with the original range in order to not try to crop outside the image bounds Rectangle.intersect(finalRasterArea, sourceGridRange, finalRasterArea); if (finalRasterArea.isEmpty()) throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP)); // // // // It is worth to point out that doing a crop the G2W transform // should not change while the envelope might change as // a consequence of the rounding of the underlying image datum // which uses integer factors or in case the G2W is very // complex. Note that we will always strive to // conserve the original grid-to-world transform. // // // // we do not have to crop in this case (should not really happen at // this time) if (finalRasterArea.equals(sourceGridRange) && isSimpleTransform && cropROI == null) return sourceCoverage; // // // // if I get here I have something to crop // using the world-to-grid transform for going from envelope to the // new grid range. // // // final double minX = finalRasterArea.getMinX(); final double minY = finalRasterArea.getMinY(); final double width = finalRasterArea.getWidth(); final double height = finalRasterArea.getHeight(); // // // // Check if we need to use mosaic or crop // // // final PlanarImage croppedImage; final ParameterBlock pbj = new ParameterBlock(); pbj.addSource(sourceImage); java.awt.Polygon rasterSpaceROI = null; String operatioName = null; if (!isSimpleTransform || cropROI != null) { // ///////////////////////////////////////////////////////////////////// // // We don't have a simple scale and translate transform, JAI // crop MAY NOT suffice. Let's decide whether or not we'll use // the Mosaic. // // ///////////////////////////////////////////////////////////////////// Polygon modelSpaceROI = FeatureUtilities.getPolygon(cropEnvelope, GFACTORY); // // // // Now convert this polygon back into a shape for the source // raster space. // // // final List<Point2D> points = new ArrayList<Point2D>(5); rasterSpaceROI = FeatureUtilities.convertPolygonToPointArray( modelSpaceROI, ProjectiveTransform.create(sourceWorldToGridTransform), points); if (rasterSpaceROI == null || rasterSpaceROI.getBounds().isEmpty()) if (finalRasterArea.isEmpty()) throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP)); final boolean doMosaic = forceMosaic ? true : decideJAIOperation(roiTolerance, rasterSpaceROI.getBounds2D(), points); if (doMosaic || cropROI != null) { // prepare the params for the mosaic final ROI[] roiarr; try { if (cropROI != null) { final LiteShape2 cropRoiLS2 = new LiteShape2( cropROI, ProjectiveTransform.create(sourceWorldToGridTransform), null, false); ROI cropRS = new ROIShape(cropRoiLS2); Rectangle2D rt = cropRoiLS2.getBounds2D(); if (!hasIntegerBounds(rt)) { // Approximate Geometry Geometry geo = (Geometry) cropRoiLS2.getGeometry().clone(); transformGeometry(geo); cropRS = new ROIShape(new LiteShape2(geo, null, null, false)); } roiarr = new ROI[] {cropRS}; } else { final ROIShape roi = new ROIShape(rasterSpaceROI); roiarr = new ROI[] {roi}; } } catch (FactoryException ex) { throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP), ex); } pbj.add(MosaicDescriptor.MOSAIC_TYPE_OVERLAY); pbj.add(null); pbj.add(roiarr); pbj.add(null); pbj.add(CoverageUtilities.getBackgroundValues(sourceCoverage)); // prepare the final layout final Rectangle bounds = rasterSpaceROI.getBounds2D().getBounds(); Rectangle.intersect(bounds, sourceGridRange, bounds); if (bounds.isEmpty()) throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP)); // we do not have to crop in this case (should not really happen at // this time) if (!doMosaic && bounds.getBounds().equals(sourceGridRange) && isSimpleTransform) return sourceCoverage; // nice trick, we use the layout to do the actual crop final Rectangle boundsInt = bounds.getBounds(); layout.setMinX(boundsInt.x); layout.setWidth(boundsInt.width); layout.setMinY(boundsInt.y); layout.setHeight(boundsInt.height); operatioName = "Mosaic"; } } // do we still have to set the operation name? If so that means we have to go for crop. if (operatioName == null) { // executing the crop pbj.add((float) minX); pbj.add((float) minY); pbj.add((float) width); pbj.add((float) height); operatioName = "GTCrop"; } // // // // Apply operation // // // if (!useProvidedProcessor) { croppedImage = JAI.create(operatioName, pbj, targetHints); } else { croppedImage = processor.createNS(operatioName, pbj, targetHints); } // conserve the input grid to world transformation Map sourceProperties = sourceCoverage.getProperties(); Map properties = null; if (sourceProperties != null && !sourceProperties.isEmpty()) { properties = new HashMap(sourceProperties); } if (rasterSpaceROI != null) { if (properties != null) { properties.put("GC_ROI", rasterSpaceROI); } else { properties = Collections.singletonMap("GC_ROI", rasterSpaceROI); } } return new GridCoverageFactory(hints) .create( sourceCoverage.getName(), croppedImage, new GridGeometry2D( new GridEnvelope2D(croppedImage.getBounds()), sourceGridGeometry.getGridToCRS2D(PixelOrientation.CENTER), sourceCoverage.getCoordinateReferenceSystem()), (GridSampleDimension[]) (actionTaken == 1 ? null : sourceCoverage.getSampleDimensions().clone()), new GridCoverage[] {sourceCoverage}, properties); } catch (TransformException e) { throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP), e); } catch (NoninvertibleTransformException e) { throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP), e); } }