| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.sis.coverage.grid; |
| |
| import java.awt.image.RenderedImage; |
| |
| // Specific to the geoapi-3.1 and geoapi-4.0 branches: |
| import org.opengis.coverage.CannotEvaluateException; |
| |
| |
| /** |
| * A grid coverage with the same data as the source coverage, |
| * with only a translation applied on grid coordinates. |
| * |
| * @author Martin Desruisseaux (Geomatys) |
| */ |
| final class TranslatedGridCoverage extends DerivedGridCoverage { |
| /** |
| * The translation to apply on the argument given to {@link #render(GridExtent)} |
| * before to delegate to the source. This is the conversion from this coverage to |
| * the source coverage. |
| */ |
| private final long[] translation; |
| |
| /** |
| * Constructs a new grid coverage which will delegate the rendering operation to the given source. |
| * This coverage will take the same sample dimensions as the source. |
| * The {@code domain} size must be the same as the source grid geometry size. |
| * |
| * @param source the source on which to delegate rendering operations. |
| * @param domain the grid extent, CRS and conversion from cell indices to CRS. |
| * @param translation translation to apply on the argument given to {@link #render(GridExtent)}. |
| */ |
| private TranslatedGridCoverage(final GridCoverage source, final GridGeometry domain, final long[] translation) { |
| super(source, domain); |
| this.translation = translation; |
| } |
| |
| /** |
| * Returns a grid coverage which will use the {@code domain} grid geometry. |
| * This coverage will take the same sample dimensions as the source. |
| * |
| * <p>If {@code domain} is non-null, then it should have the same size as the source grid geometry size. |
| * If this is not the case, then this method returns {@code null}.</p> |
| * |
| * @param source the source on which to delegate rendering operations. |
| * @param domain the geometry of the grid coverage to return, or {@code null} for automatic. |
| * @param translation translation to apply on the argument given to {@link #render(GridExtent)}. |
| * @return the coverage, or {@code null} if {@code domain} is non-null but does not have the expected size. |
| * May be the {@code source} returned as-is. |
| */ |
| static GridCoverage create(GridCoverage source, GridGeometry domain, long[] translation, |
| final boolean allowSourceReplacement) |
| { |
| if (allowSourceReplacement) { |
| while (source instanceof TranslatedGridCoverage) { |
| final TranslatedGridCoverage tc = (TranslatedGridCoverage) source; |
| final long[] shifted = tc.translation.clone(); |
| long tm = 0; |
| for (int i = Math.min(shifted.length, translation.length); --i >= 0;) { |
| shifted[i] = Math.addExact(shifted[i], translation[i]); |
| tm |= translation[i]; |
| } |
| if (tm == 0) return tc; // All translation terms are zero. |
| translation = shifted; |
| source = tc.source; |
| } |
| } |
| final GridGeometry gridGeometry = source.getGridGeometry(); |
| if (domain == null) { |
| domain = gridGeometry.shiftGrid(translation); |
| } else if (!domain.extent.isSameSize(gridGeometry.extent)) { |
| return null; |
| } |
| if (domain.equals(gridGeometry)) { |
| return source; // All (potentially updated) translation terms are zero. |
| } |
| return new TranslatedGridCoverage(source, domain, translation); |
| } |
| |
| /** |
| * Returns a grid coverage that contains real values or sample values, depending if {@code converted} |
| * is {@code true} or {@code false} respectively. This method delegates to the source and wraps the |
| * result in a {@link TranslatedGridCoverage} with the same {@linkplain #translation}. |
| */ |
| @Override |
| protected final GridCoverage createConvertedValues(final boolean converted) { |
| final GridCoverage cs = source.forConvertedValues(converted); |
| return (cs == source) ? this : new TranslatedGridCoverage(cs, gridGeometry, translation); |
| } |
| |
| /** |
| * Returns a two-dimensional slice of grid data as a rendered image. |
| * This method translates the {@code sliceExtent} argument, then delegates to the {@linkplain #source source}. |
| * It is okay to use the source result as-is because image coordinates are relative to the request; |
| * the rendered image shall not be translated. |
| */ |
| @Override |
| public RenderedImage render(GridExtent sliceExtent) throws CannotEvaluateException { |
| if (sliceExtent == null) { |
| sliceExtent = gridGeometry.extent; |
| } |
| if (sliceExtent != null) { |
| sliceExtent = sliceExtent.translate(translation); |
| } |
| return source.render(sliceExtent); |
| } |
| } |