/** * Creates a {@link GridCoverage} for the provided {@link PlanarImage} using the {@link * #raster2Model} that was provided for this coverage. * * <p>This method is vital when working with coverages that have a raster to model transformation * that is not a simple scale and translate. * * @param image contains the data for the coverage to create. * @param raster2Model is the {@link MathTransform} that maps from the raster space to the model * space. * @return a {@link GridCoverage} * @throws IOException */ protected final GridCoverage2D createCoverage(PlanarImage image, MathTransform raster2Model) throws IOException { // creating bands final SampleModel sm = image.getSampleModel(); final ColorModel cm = image.getColorModel(); final int numBands = sm.getNumBands(); final GridSampleDimension[] bands = new GridSampleDimension[numBands]; // setting bands names. Category noDataCategory = null; final Map<String, Double> properties = new HashMap<String, Double>(); if (!Double.isNaN(noData)) { noDataCategory = new Category( Vocabulary.formatInternational(VocabularyKeys.NODATA), new Color[] {new Color(0, 0, 0, 0)}, NumberRange.create(noData, noData), NumberRange.create(noData, noData)); properties.put("GC_NODATA", new Double(noData)); } Set<String> bandNames = new HashSet<String>(); for (int i = 0; i < numBands; i++) { final ColorInterpretation colorInterpretation = TypeMap.getColorInterpretation(cm, i); if (colorInterpretation == null) throw new IOException("Unrecognized sample dimension type"); Category[] categories = null; if (noDataCategory != null) { categories = new Category[] {noDataCategory}; } String bandName = colorInterpretation.name(); // make sure we create no duplicate band names if (colorInterpretation == ColorInterpretation.UNDEFINED || bandNames.contains(bandName)) { bandName = "Band" + (i + 1); } bands[i] = new GridSampleDimension(bandName, categories, null).geophysics(true); } // creating coverage if (raster2Model != null) { return coverageFactory.create( coverageName, image, crs, raster2Model, bands, null, properties); } return coverageFactory.create( coverageName, image, new GeneralEnvelope(originalEnvelope), bands, null, properties); }
/** Add a metadata element to the FileGroup metadata map */ private void addMetadaElement( String name, Comparable min, Comparable max, Map<String, Object> metadataMap) { if (Utils.TIME_DOMAIN.equalsIgnoreCase(name) || min instanceof Date) { metadataMap.put(name.toUpperCase(), new DateRange((Date) min, (Date) max)); } else if (Utils.ELEVATION_DOMAIN.equalsIgnoreCase(name) || min instanceof Number) { metadataMap.put( name.toUpperCase(), NumberRange.create( ((Number) min).doubleValue(), true, ((Number) max).doubleValue(), true)); } else { metadataMap.put(name, new Range(String.class, (String) min, (String) max)); } }
@Override protected void setBoundedByElement(SpatioTemporalImageReader reader) { Map<String, String> map = getAttributesMap(reader); BoundedBy bb = getBoundedBy(); if (bb == null) throw new IllegalArgumentException("Provided BoundedBy element is null"); final String typeS = map.get(GRIB1ImageMetadata.GRID_TYPE); // TODO: Add more check on grid types // //////////////////////////////////////////////////////////////////// // // Setting Envelope // // //////////////////////////////////////////////////////////////////// if (typeS != null) { final int type = Integer.parseInt(typeS); final String lat1s = map.get(GRIB1ImageMetadata.GRID_LAT_1); final String lat2s = map.get(GRIB1ImageMetadata.GRID_LAT_2); final String lon1s = map.get(GRIB1ImageMetadata.GRID_LON_1); final String lon2s = map.get(GRIB1ImageMetadata.GRID_LON_2); if (lat1s != null && lat2s != null && lon1s != null && lon2s != null) { double[] lc = new double[] {Double.parseDouble(lon1s), Double.parseDouble(lat1s)}; double[] uc = new double[] {Double.parseDouble(lon2s), Double.parseDouble(lat2s)}; switch (type) { case 10: final String deltaX = map.get(GRIB1ImageMetadata.GRID_DELTA_X); final String deltaY = map.get(GRIB1ImageMetadata.GRID_DELTA_Y); final String latSP = map.get(GRIB1ImageMetadata.GRID_LAT_SP); final String lonSP = map.get(GRIB1ImageMetadata.GRID_LON_SP); final String nX = map.get(GRIB1ImageMetadata.GRID_N_X); final String nY = map.get(GRIB1ImageMetadata.GRID_N_Y); if (deltaX != null && deltaY != null && lonSP != null && latSP != null && nY != null && nX != null) { final double lonSp = Double.parseDouble(lonSP); final double latSp = Double.parseDouble(latSP); final double dX = Double.parseDouble(deltaX); final double dY = Double.parseDouble(deltaY); final double x = Double.parseDouble(nX); final double y = Double.parseDouble(nY); uc = getGridCoords(x * dX, y * dY, lc[0], lc[1], lonSp, latSp); lc = getGridCoords(0, 0, lc[0], lc[1], lonSp, latSp); } // TODO: Fix this case 0: if (lc[0] > uc[0]) { final double temp = lc[0]; lc[0] = uc[0]; uc[0] = temp; } if (lc[1] > uc[1]) { final double temp = lc[1]; lc[1] = uc[1]; uc[1] = temp; } } bb.setLowerCorner(lc); bb.setUpperCorner(uc); } } if (isHasVerticalCRS()) { final String pdsValues = map.get(GRIB1ImageMetadata.PDSL_VALUES); final String isNumeric = map.get(GRIB1ImageMetadata.PDSL_ISNUMERIC); if (isNumeric != null && Boolean.parseBoolean(isNumeric)) { final String[] values = pdsValues.split(GRIB1Utilities.VALUES_SEPARATOR); if (values != null) { if (values.length == 1) bb.setVerticalExtent(Double.parseDouble(values[0])); else if (values.length == 2) { final double d1 = Double.parseDouble(values[0]); final double d2 = Double.parseDouble(values[1]); if (d1 != d2) bb.setVerticalExtent(NumberRange.create(d1, d2)); else bb.setVerticalExtent(d1); } else { throw new IllegalArgumentException("Unable to set a proper Vertical Extent"); } } } else { bb.setVerticalExtent(0); } } if (isHasTemporalCRS()) { // // // // Setting temporal Extent // // // final String time = map.get(GRIB1ImageMetadata.PROD_TIME); if (Utilities.ensureValidString(time)) { // if (time.contains(GRIB1Utilities.DATE_SEPARATOR)) { // String beginEnd[] = time // .split(GRIB1Utilities.DATE_SEPARATOR); // bb.setTemporalExtent(beginEnd); // } else // bb.setTemporalExtent(time); } } }
/** * Takes a GetLegendGraphicRequest and produces a BufferedImage that then can be used by a * subclass to encode it to the appropriate output format. * * @param request the "parsed" request, where "parsed" means that it's values are already * validated so this method must not take care of verifying the requested layer exists and the * like. * @throws ServiceException if there are problems creating a "sample" feature instance for the * FeatureType <code>request</code> returns as the required layer (which should not occur). */ public BufferedImage buildLegendGraphic(GetLegendGraphicRequest request) throws ServiceException { // list of images to be rendered for the layers (more than one if // a layer group is given) List<RenderedImage> layersImages = new ArrayList<RenderedImage>(); List<LegendRequest> layers = request.getLegends(); // List<FeatureType> layers=request.getLayers(); // List<Style> styles=request.getStyles(); // List<String> rules=request.getRules(); boolean forceLabelsOn = false; boolean forceLabelsOff = false; if (request.getLegendOptions().get("forceLabels") instanceof String) { String forceLabelsOpt = (String) request.getLegendOptions().get("forceLabels"); if (forceLabelsOpt.equalsIgnoreCase("on")) { forceLabelsOn = true; } else if (forceLabelsOpt.equalsIgnoreCase("off")) { forceLabelsOff = true; } } boolean forceTitlesOff = false; if (request.getLegendOptions().get("forceTitles") instanceof String) { String forceTitlesOpt = (String) request.getLegendOptions().get("forceTitles"); if (forceTitlesOpt.equalsIgnoreCase("off")) { forceTitlesOff = true; } } for (LegendRequest legend : layers) { FeatureType layer = legend.getFeatureType(); // style and rule to use for the current layer Style gt2Style = legend.getStyle(); if (gt2Style == null) { throw new NullPointerException("request.getStyle()"); } // get rule corresponding to the layer index // normalize to null for NO RULE String ruleName = legend.getRule(); // was null // width and height, we might have to rescale those in case of DPI usage int w = request.getWidth(); int h = request.getHeight(); // apply dpi rescale double dpi = RendererUtilities.getDpi(request.getLegendOptions()); double standardDpi = RendererUtilities.getDpi(Collections.emptyMap()); if (dpi != standardDpi) { double scaleFactor = dpi / standardDpi; w = (int) Math.round(w * scaleFactor); h = (int) Math.round(h * scaleFactor); DpiRescaleStyleVisitor dpiVisitor = new DpiRescaleStyleVisitor(scaleFactor); dpiVisitor.visit(gt2Style); gt2Style = (Style) dpiVisitor.getCopy(); } // apply UOM rescaling if we have a scale if (request.getScale() > 0) { double pixelsPerMeters = RendererUtilities.calculatePixelsPerMeterRatio( request.getScale(), request.getLegendOptions()); UomRescaleStyleVisitor rescaleVisitor = new UomRescaleStyleVisitor(pixelsPerMeters); rescaleVisitor.visit(gt2Style); gt2Style = (Style) rescaleVisitor.getCopy(); } boolean strict = request.isStrict(); final boolean transparent = request.isTransparent(); RenderedImage titleImage = null; // if we have more than one layer, we put a title on top of each layer legend if (layers.size() > 1 && !forceTitlesOff) { titleImage = getLayerTitle(legend, w, h, transparent, request); } // Check for rendering transformation boolean hasVectorTransformation = false; boolean hasRasterTransformation = false; List<FeatureTypeStyle> ftsList = gt2Style.featureTypeStyles(); for (int i = 0; i < ftsList.size(); i++) { FeatureTypeStyle fts = ftsList.get(i); Expression exp = fts.getTransformation(); if (exp != null) { ProcessFunction processFunction = (ProcessFunction) exp; Name processName = processFunction.getProcessName(); Map<String, Parameter<?>> outputs = Processors.getResultInfo(processName, null); if (outputs.isEmpty()) { continue; } Parameter<?> output = outputs.values().iterator().next(); // we assume there is only one output if (SimpleFeatureCollection.class.isAssignableFrom(output.getType())) { hasVectorTransformation = true; break; } else if (GridCoverage2D.class.isAssignableFrom(output.getType())) { hasRasterTransformation = true; break; } } } final boolean buildRasterLegend = (!strict && layer == null && LegendUtils.checkRasterSymbolizer(gt2Style)) || (LegendUtils.checkGridLayer(layer) && !hasVectorTransformation) || hasRasterTransformation; // Just checks LegendInfo currently, should check gtStyle final boolean useProvidedLegend = layer != null && legend.getLayerInfo() != null; RenderedImage legendImage = null; if (useProvidedLegend) { legendImage = getLayerLegend(legend, w, h, transparent, request); } if (buildRasterLegend) { final RasterLayerLegendHelper rasterLegendHelper = new RasterLayerLegendHelper(request, gt2Style, ruleName); final BufferedImage image = rasterLegendHelper.getLegend(); if (image != null) { if (titleImage != null) { layersImages.add(titleImage); } layersImages.add(image); } } else if (useProvidedLegend && legendImage != null) { if (titleImage != null) { layersImages.add(titleImage); } layersImages.add(legendImage); } else { final Feature sampleFeature; if (layer == null || hasVectorTransformation) { sampleFeature = createSampleFeature(); } else { sampleFeature = createSampleFeature(layer); } final FeatureTypeStyle[] ftStyles = gt2Style.featureTypeStyles().toArray(new FeatureTypeStyle[0]); final double scaleDenominator = request.getScale(); final Rule[] applicableRules; if (ruleName != null) { Rule rule = LegendUtils.getRule(ftStyles, ruleName); if (rule == null) { throw new ServiceException( "Specified style does not contains a rule named " + ruleName); } applicableRules = new Rule[] {rule}; } else { applicableRules = LegendUtils.getApplicableRules(ftStyles, scaleDenominator); } final NumberRange<Double> scaleRange = NumberRange.create(scaleDenominator, scaleDenominator); final int ruleCount = applicableRules.length; /** * A legend graphic is produced for each applicable rule. They're being held here until the * process is done and then painted on a "stack" like legend. */ final List<RenderedImage> legendsStack = new ArrayList<RenderedImage>(ruleCount); final SLDStyleFactory styleFactory = new SLDStyleFactory(); double minimumSymbolSize = MINIMUM_SYMBOL_SIZE; // get minSymbolSize from LEGEND_OPTIONS, if defined if (request.getLegendOptions().get("minSymbolSize") instanceof String) { String minSymbolSizeOpt = (String) request.getLegendOptions().get("minSymbolSize"); try { minimumSymbolSize = Double.parseDouble(minSymbolSizeOpt); } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid minSymbolSize value: should be a number"); } } // calculate the symbols rescaling factor necessary for them to be // drawn inside the icon box double symbolScale = calcSymbolScale(w, h, layer, sampleFeature, applicableRules, minimumSymbolSize); for (int i = 0; i < ruleCount; i++) { final RenderedImage image = ImageUtils.createImage(w, h, (IndexColorModel) null, transparent); final Map<RenderingHints.Key, Object> hintsMap = new HashMap<RenderingHints.Key, Object>(); final Graphics2D graphics = ImageUtils.prepareTransparency( transparent, LegendUtils.getBackgroundColor(request), image, hintsMap); graphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Feature sample = getSampleFeatureForRule(layer, sampleFeature, applicableRules[i]); FilterFactory ff = CommonFactoryFinder.getFilterFactory(); final Symbolizer[] symbolizers = applicableRules[i].getSymbolizers(); final GraphicLegend graphic = applicableRules[i].getLegend(); // If this rule has a legend graphic defined in the SLD, use it if (graphic != null) { if (this.samplePoint == null) { Coordinate coord = new Coordinate(w / 2, h / 2); try { this.samplePoint = new LiteShape2(geomFac.createPoint(coord), null, null, false); } catch (Exception e) { this.samplePoint = null; } } shapePainter.paint(graphics, this.samplePoint, graphic, scaleDenominator, false); } else { for (int sIdx = 0; sIdx < symbolizers.length; sIdx++) { Symbolizer symbolizer = symbolizers[sIdx]; if (symbolizer instanceof RasterSymbolizer) { // skip it } else { // rescale symbols if needed if (symbolScale > 1.0 && symbolizer instanceof PointSymbolizer) { PointSymbolizer pointSymbolizer = cloneSymbolizer(symbolizer); if (pointSymbolizer.getGraphic() != null) { double size = getPointSymbolizerSize(sample, pointSymbolizer, Math.min(w, h) - 4); pointSymbolizer .getGraphic() .setSize(ff.literal(size / symbolScale + minimumSymbolSize)); symbolizer = pointSymbolizer; } } Style2D style2d = styleFactory.createStyle(sample, symbolizer, scaleRange); LiteShape2 shape = getSampleShape(symbolizer, w, h); if (style2d != null) { shapePainter.paint(graphics, shape, style2d, scaleDenominator); } } } } if (image != null && titleImage != null) { layersImages.add(titleImage); titleImage = null; } legendsStack.add(image); graphics.dispose(); } // JD: changed legend behavior, see GEOS-812 // this.legendGraphic = scaleImage(mergeLegends(legendsStack), request); BufferedImage image = mergeLegends(legendsStack, applicableRules, request, forceLabelsOn, forceLabelsOff); if (image != null) { layersImages.add(image); } } } // all legend graphics are merged if we have a layer group BufferedImage finalLegend = mergeLegends(layersImages, null, request, forceLabelsOn, forceLabelsOff); if (finalLegend == null) { throw new IllegalArgumentException("no legend passed"); } return finalLegend; }
/** Returns the expected range of values for the resulting image. */ protected NumberRange deriveRange(final NumberRange[] ranges, final Parameters parameters) { final NumberRange range = ranges[0]; final double min = Math.log(range.getMinimum()); final double max = Math.log(range.getMaximum()); return NumberRange.create(min, max); }
/** * Complex test for Postgis indexing on db. * * @throws Exception */ @Test public void testPostgisIndexing() throws Exception { final File workDir = new File(TestData.file(this, "."), "watertemp4"); assertTrue(workDir.mkdir()); FileUtils.copyFile(TestData.file(this, "watertemp.zip"), new File(workDir, "watertemp.zip")); TestData.unzipFile(this, "watertemp4/watertemp.zip"); final URL timeElevURL = TestData.url(this, "watertemp4"); // place datastore.properties file in the dir for the indexing FileWriter out = null; try { out = new FileWriter(new File(TestData.file(this, "."), "/watertemp4/datastore.properties")); final Set<Object> keyset = fixture.keySet(); for (Object key : keyset) { final String key_ = (String) key; final String value = fixture.getProperty(key_); out.write(key_.replace(" ", "\\ ") + "=" + value.replace(" ", "\\ ") + "\n"); } out.flush(); } finally { if (out != null) { IOUtils.closeQuietly(out); } } // now start the test final AbstractGridFormat format = TestUtils.getFormat(timeElevURL); assertNotNull(format); ImageMosaicReader reader = TestUtils.getReader(timeElevURL, format); assertNotNull(reader); final String[] metadataNames = reader.getMetadataNames(); assertNotNull(metadataNames); assertEquals(metadataNames.length, 10); assertEquals("true", reader.getMetadataValue("HAS_TIME_DOMAIN")); final String timeMetadata = reader.getMetadataValue("TIME_DOMAIN"); assertNotNull(timeMetadata); assertEquals(2, timeMetadata.split(",").length); assertEquals(timeMetadata.split(",")[0], reader.getMetadataValue("TIME_DOMAIN_MINIMUM")); assertEquals(timeMetadata.split(",")[1], reader.getMetadataValue("TIME_DOMAIN_MAXIMUM")); assertEquals("true", reader.getMetadataValue("HAS_ELEVATION_DOMAIN")); final String elevationMetadata = reader.getMetadataValue("ELEVATION_DOMAIN"); assertNotNull(elevationMetadata); assertEquals(2, elevationMetadata.split(",").length); assertEquals( Double.parseDouble(elevationMetadata.split(",")[0]), Double.parseDouble(reader.getMetadataValue("ELEVATION_DOMAIN_MINIMUM")), 1E-6); assertEquals( Double.parseDouble(elevationMetadata.split(",")[1]), Double.parseDouble(reader.getMetadataValue("ELEVATION_DOMAIN_MAXIMUM")), 1E-6); // limit yourself to reading just a bit of it final ParameterValue<GridGeometry2D> gg = AbstractGridFormat.READ_GRIDGEOMETRY2D.createValue(); final GeneralEnvelope envelope = reader.getOriginalEnvelope(); final Dimension dim = new Dimension(); dim.setSize( reader.getOriginalGridRange().getSpan(0) / 2.0, reader.getOriginalGridRange().getSpan(1) / 2.0); final Rectangle rasterArea = ((GridEnvelope2D) reader.getOriginalGridRange()); rasterArea.setSize(dim); final GridEnvelope2D range = new GridEnvelope2D(rasterArea); gg.setValue(new GridGeometry2D(range, envelope)); // use imageio with defined tiles final ParameterValue<List> time = ImageMosaicFormat.TIME.createValue(); final List<Date> timeValues = new ArrayList<Date>(); final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'"); sdf.setTimeZone(TimeZone.getTimeZone("GMT+0")); Date date = sdf.parse("2008-10-31T00:00:00.000Z"); timeValues.add(date); time.setValue(timeValues); final ParameterValue<double[]> bkg = ImageMosaicFormat.BACKGROUND_VALUES.createValue(); bkg.setValue(new double[] {-9999.0}); final ParameterValue<Boolean> direct = ImageMosaicFormat.USE_JAI_IMAGEREAD.createValue(); direct.setValue(false); final ParameterValue<List> elevation = ImageMosaicFormat.ELEVATION.createValue(); elevation.setValue(Arrays.asList(100.0)); // Test the output coverage TestUtils.checkCoverage( reader, new GeneralParameterValue[] {gg, time, bkg, elevation, direct}, "Time-Elevation Test"); reader = TestUtils.getReader(timeElevURL, format); elevation.setValue(Arrays.asList(NumberRange.create(0.0, 10.0))); // Test the output coverage TestUtils.checkCoverage( reader, new GeneralParameterValue[] {gg, time, bkg, elevation, direct}, "Time-Elevation Test"); }
@Test public void testFileInfo() throws NoSuchAuthorityCodeException, FactoryException, IOException, ParseException { File nc2 = new File(TestData.file(this, "."), "nc2"); if (nc2.exists()) { FileUtils.deleteDirectory(nc2); } assertTrue(nc2.mkdirs()); File file = TestData.file(this, "O3-NO2.nc"); FileUtils.copyFileToDirectory(file, nc2); file = new File(nc2, "O3-NO2.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); CloseableIterator<FileGroup> files = null; try { String[] names = reader.getGridCoverageNames(); names = new String[] {names[1]}; for (String coverageName : names) { final String[] metadataNames = reader.getMetadataNames(coverageName); assertNotNull(metadataNames); assertEquals(metadataNames.length, 12); ResourceInfo info = reader.getInfo(coverageName); assertTrue(info instanceof FileResourceInfo); FileResourceInfo fileInfo = (FileResourceInfo) info; files = fileInfo.getFiles(null); int fileGroups = 0; FileGroup fg = null; while (files.hasNext()) { fg = files.next(); fileGroups++; } assertEquals(1, fileGroups); File mainFile = fg.getMainFile(); assertEquals("O3-NO2", FilenameUtils.getBaseName(mainFile.getAbsolutePath())); Map<String, Object> metadata = fg.getMetadata(); assertNotNull(metadata); assertFalse(metadata.isEmpty()); Set<String> keys = metadata.keySet(); // envelope, time, elevation = 3 elements assertEquals(3, keys.size()); // Check time final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'"); sdf.setTimeZone(TimeZone.getTimeZone("GMT+0")); Date start = sdf.parse("2012-04-01T00:00:00.000Z"); Date end = sdf.parse("2012-04-01T01:00:00.000Z"); DateRange timeRange = new DateRange(start, end); assertEquals(timeRange, metadata.get(Utils.TIME_DOMAIN)); // Check elevation NumberRange<Double> elevationRange = NumberRange.create(10.0, 450.0); assertEquals(elevationRange, metadata.get(Utils.ELEVATION_DOMAIN)); } } catch (Throwable t) { throw new RuntimeException(t); } finally { if (files != null) { files.close(); } if (reader != null) { try { reader.dispose(); } catch (Throwable t) { // Does nothing } } } }