/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2013, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.display3d.scene.loader; import java.awt.Dimension; import java.awt.image.BufferedImage; import java.awt.image.WritableRaster; import java.util.List; import org.geotoolkit.display.PortrayalException; import org.opengis.geometry.DirectPosition; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.CoordinateReferenceSystem; /** * Create a stack of elevation models. * * It will takes values from the first elevation loader. * If it contains NaN values then the next elevation loader is used to fill those NaN. * And so on until there are not more NaN or no more elevation loaders. * * @author Johann Sorel (Geomatys) */ public class StackElevationLoader implements ElevationLoader{ private final List<ElevationLoader> stack; private double min; private double max; public StackElevationLoader(List<ElevationLoader> stack) { this.stack = stack; min = stack.get(0).getMinimumElevation(); max = stack.get(0).getMaximumElevation(); for(int i=1,n=stack.size();i<n;i++){ min = Math.min(min, stack.get(i).getMinimumElevation()); max = Math.max(max, stack.get(i).getMaximumElevation()); } } @Override public double getMinimumElevation() { return min; } @Override public double getMaximumElevation() { return max; } @Override public void setOutputCRS(CoordinateReferenceSystem outputCrs) throws PortrayalException { for(ElevationLoader e : stack){ e.setOutputCRS(outputCrs); } } @Override public BufferedImage getBufferedImageOf(Envelope outputEnv, Dimension outputDimension) throws PortrayalException { BufferedImage image = stack.get(0).getBufferedImageOf(outputEnv, outputDimension); final boolean[][] mask = new boolean[outputDimension.height][outputDimension.width]; for(int i=1,n=stack.size();i<n;i++){ if(hasNaN(image, mask)){ //get next elevation image and merge them final BufferedImage nextimg = stack.get(i).getBufferedImageOf(outputEnv, outputDimension); merge(image,nextimg,mask); } } return image; } @Override public double getSmoothValueOf(DirectPosition position, double scale) throws PortrayalException { return stack.get(0).getSmoothValueOf(position, scale); } @Override public double getValueOf(DirectPosition position, double scale) throws PortrayalException { return stack.get(0).getValueOf(position, scale); } private static boolean hasNaN(BufferedImage buffer, boolean[][] mask){ final WritableRaster raster = buffer.getRaster(); final double[] sample = new double[raster.getNumBands()]; boolean hasnan = false; for(int y=0;y<mask.length;y++){ for(int x=0;x<mask[0].length;x++){ raster.getPixel(x, y, sample); mask[y][x] = Double.isNaN(sample[0]); hasnan = hasnan || mask[y][x]; } } return hasnan; } private static void merge(BufferedImage base, BufferedImage next, boolean[][] mask){ final WritableRaster baseRaster = base.getRaster(); final WritableRaster nextRaster = next.getRaster(); final double[] sample = new double[nextRaster.getNumBands()]; for(int y=0;y<mask.length;y++){ for(int x=0;x<mask[0].length;x++){ if(mask[y][x]){ nextRaster.getPixel(x, y, sample); baseRaster.setPixel(x, y, sample); } } } } }