sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 02/02: Base class for image operations.
Date Tue, 31 Dec 2019 18:08:22 GMT
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit ae19e93ae89372ea2bc668f3131ba3b52e7e795a
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Tue Dec 31 19:06:48 2019 +0100

    Base class for image operations.
---
 .../java/org/apache/sis/image/PlanarImage.java     |  36 +---
 .../sis/internal/coverage/j2d/CachedImage.java     |  16 +-
 .../sis/internal/coverage/j2d/ImageOperation.java  | 234 +++++++++++++++++++++
 .../sis/internal/coverage/j2d/ImageUtilities.java  |  43 ++++
 .../org/apache/sis/internal/feature/Resources.java |  10 +
 .../sis/internal/feature/Resources.properties      |   2 +
 .../sis/internal/feature/Resources_fr.properties   |   2 +
 .../org/apache/sis/internal/util/Numerics.java     |  14 +-
 .../main/java/org/apache/sis/measure/Scalar.java   |   3 +-
 9 files changed, 324 insertions(+), 36 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/PlanarImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/PlanarImage.java
index c924ad4..e8e51dc 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/PlanarImage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/PlanarImage.java
@@ -22,9 +22,7 @@ import java.awt.color.ColorSpace;
 import java.awt.image.ColorModel;
 import java.awt.image.IndexColorModel;
 import java.awt.image.SampleModel;
-import java.awt.image.DataBuffer;
 import java.awt.image.Raster;
-import java.awt.image.RasterFormatException;
 import java.awt.image.WritableRaster;
 import java.awt.image.RenderedImage;
 import java.util.Vector;
@@ -84,12 +82,6 @@ import org.apache.sis.internal.coverage.j2d.ScaledColorSpace;
  */
 public abstract class PlanarImage implements RenderedImage {
     /**
-     * Approximate size of the buffer to use for copying data from the image to a raster,
in bits.
-     * The actual buffer size may be smaller or larger, depending on the actual tile size.
-     */
-    private static final int BUFFER_SIZE = 8192 * Byte.SIZE;
-
-    /**
      * Creates a new rendered image.
      */
     protected PlanarImage() {
@@ -261,22 +253,6 @@ public abstract class PlanarImage implements RenderedImage {
     }
 
     /**
-     * Returns the size in bits of the transfer type, or an arbitrary value if that type
is unknown.
-     * For this class it is okay if the value is not accurate; this method is used only for
adjusting
-     * the {@link #BUFFER_SIZE} value.
-     *
-     * @param  raster  the raster for which to get transfer type size.
-     * @return size in bits of transfer type. May be an arbitrary size.
-     */
-    private static int getTransferTypeSize(final Raster raster) {
-        try {
-            return DataBuffer.getDataTypeSize(raster.getTransferType());
-        } catch (IllegalArgumentException e) {
-            return Short.SIZE;
-        }
-    }
-
-    /**
      * Returns a copy of this image as one large tile.
      * The returned raster will not be updated if this image is changed.
      *
@@ -352,6 +328,8 @@ public abstract class PlanarImage implements RenderedImage {
          * Iterate over all tiles that interesect the area of interest. For each tile,
          * copy a few rows in a temporary buffer, then copy that buffer to destination.
          * The buffer will be reused for each transfer, unless its size is insufficient.
+         * Note that `tb` should never be empty since we restrict iteration to the tiles
+         * that intersect the given area of interest.
          */
         Object buffer = null;
         int bufferCapacity = 0;
@@ -359,15 +337,7 @@ public abstract class PlanarImage implements RenderedImage {
             for (int tx = minTileX; tx <= maxTileX; tx++) {
                 final Raster tile = getTile(tx, ty);
                 final Rectangle tb = aoi.intersection(tile.getBounds());        // Bounds
of transfer buffer.
-                if (tb.isEmpty()) {
-                    /*
-                     * Should never happen since we iterate only over the tiles
-                     * that intersect the given area of interest.
-                     */
-                    throw new RasterFormatException("Inconsistent tile matrix.");
-                }
-                final int afterLastRow = Math.addExact(tb.y, tb.height);
-                tb.height = Math.max(1, Math.min(BUFFER_SIZE / (getTransferTypeSize(tile)
* tb.width), tb.height));
+                final int afterLastRow = ImageUtilities.prepareTransferRegion(tb, tile.getTransferType());
                 final int transferCapacity = tb.width * tb.height;
                 if (transferCapacity > bufferCapacity) {
                     bufferCapacity = transferCapacity;
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/CachedImage.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/CachedImage.java
index f518429..8436b8e 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/CachedImage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/CachedImage.java
@@ -26,6 +26,7 @@ import java.awt.image.RenderedImage;
 import java.awt.image.SampleModel;
 import java.lang.ref.WeakReference;
 import org.apache.sis.internal.system.ReferenceQueueConsumer;
+import org.apache.sis.internal.feature.Resources;
 import org.apache.sis.image.PlanarImage;
 import org.apache.sis.util.collection.Cache;
 import org.apache.sis.util.ArgumentChecks;
@@ -161,6 +162,19 @@ public abstract class CachedImage extends PlanarImage {
     }
 
     /**
+     * Returns the sample model associated with this image.
+     * All rasters returned from this image will have this sample model.
+     * In {@code CachedImage} implementation, the sample model determines the tile size
+     * (this is not necessarily true for all {@link RenderedImage} implementations).
+     *
+     * @return the sample model of this image.
+     */
+    @Override
+    public SampleModel getSampleModel() {
+        return sampleModel;
+    }
+
+    /**
      * Returns the width of tiles in this image. The default implementation returns {@link
SampleModel#getWidth()}.
      *
      * <div class="note"><b>Note:</b>
@@ -221,7 +235,7 @@ public abstract class CachedImage extends PlanarImage {
                 if (tile == null) {
                     tile = computeTile(tileX, tileY);
                     if (tile == null) {
-                        throw new ImagingOpException("No data");    // TODO
+                        throw new ImagingOpException(Resources.format(Resources.Keys.CanNotComputeTile_2,
tileX, tileY));
                     }
                 }
             } finally {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageOperation.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageOperation.java
new file mode 100644
index 0000000..f46ccaf
--- /dev/null
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageOperation.java
@@ -0,0 +1,234 @@
+/*
+ * 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.internal.coverage.j2d;
+
+import java.util.Arrays;
+import java.util.Vector;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.awt.image.ColorModel;
+import org.apache.sis.util.ArgumentChecks;
+
+
+/**
+ * An image which is computed on-the-fly, usually from other images.
+ * Computations are performed on a tile-by-tile basis and the result
+ * is stored in a cache shared by all images on the platform.
+ *
+ * @todo Add an API providing operation parameters.
+ *
+ * <p>Subclasses need to implement the following methods:</p>
+ * <ul>
+ *   <li>{@link #computeTile(int, int)}</li>
+ * </ul>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.1
+ * @since   1.1
+ * @module
+ */
+public abstract class ImageOperation extends CachedImage {
+    /**
+     * The sources of this image. Never null and does not contain any null element.
+     */
+    private final RenderedImage[] sources;
+
+    /**
+     * The color model associated to this image, or {@code null} if unspecified.
+     */
+    private final ColorModel colorModel;
+
+    /**
+     * Image size in pixels.
+     */
+    private final int width, height;
+
+    /**
+     * Coordinate of the pixel in upper-left corner.
+     */
+    private final int minX, minY;
+
+    /**
+     * Coordinate of the tile in the upper-left corner.
+     */
+    private final int minTileX, minTileY;
+
+    /**
+     * Creates a new operation with a single image as the main source.
+     * This {@code ImageOperation} will use the same color model, data type,
+     * tile size, image size and minimum coordinates than the given image.
+     *
+     * @param  image   the main source of this operation.
+     * @param  others  additional sources, or {@code null} if none.
+     */
+    protected ImageOperation(final RenderedImage image, final RenderedImage... others) {
+        super(image);
+        if (others == null) {
+            sources = new RenderedImage[] {image};
+        } else {
+            sources = new RenderedImage[others.length + 1];
+            sources[0] = image;
+            System.arraycopy(others, 0, sources, 1, others.length);
+            for (int i=1; i<sources.length; i++) {
+                ArgumentChecks.ensureNonNullElement("others", i-1, sources[i]);
+            }
+        }
+        colorModel = image.getColorModel();
+        width      = image.getWidth();
+        height     = image.getHeight();
+        minX       = image.getMinX();
+        minY       = image.getMinY();
+        minTileX   = image.getMinTileX();
+        minTileY   = image.getMinTileY();
+    }
+
+    /**
+     * Creates a new operation with an arbitrary amount of images as the sources.
+     * The tile size will be the width and height of the given sample model.
+     *
+     * @param  sampleModel  the sample model shared by all tiles in this image.
+     * @param  colorModel   the color model for all rasters, or {@code null} if unspecified.
+     * @param  width        the image width  in pixels, as a strictly positive number.
+     * @param  height       the image height in pixels, as a strictly positive number.
+     * @param  minX         <var>x</var> coordinate (column) of the pixel in
upper-left corner.
+     * @param  minY         <var>y</var> coordinate (row) of the pixel in upper-left
corner.
+     * @param  minTileX     <var>x</var> index of the tile in upper-left corner.
+     * @param  minTileY     <var>y</var> index of the tile in upper-left corner.
+     * @param  sources      all sources of this image. May be an empty array.
+     */
+    protected ImageOperation(final SampleModel sampleModel, final ColorModel colorModel,
+                             final int width, final int height, final int minX, final int
minY,
+                             final int minTileX, final int minTileY, RenderedImage... sources)
+    {
+        super(sampleModel);
+        this.colorModel = colorModel;
+        this.width      = width;
+        this.height     = height;
+        this.minX       = minX;
+        this.minY       = minY;
+        this.minTileX   = minTileX;
+        this.minTileY   = minTileY;
+        ArgumentChecks.ensureStrictlyPositive("width",  width);
+        ArgumentChecks.ensureStrictlyPositive("height", height);
+        ArgumentChecks.ensureNonNull("sources", sources);
+        sources = sources.clone();
+        this.sources = sources;
+        for (int i=0; i<sources.length; i++) {
+            ArgumentChecks.ensureNonNullElement("sources", i, sources[i]);
+        }
+    }
+
+    /**
+     * Returns the source at the given index.
+     *
+     * @param  index  index of the desired source.
+     * @return source at the given index.
+     * @throws IndexOutOfBoundsException if the given index is out of bounds.
+     */
+    protected final RenderedImage getSource(final int index) {
+        return sources[index];
+    }
+
+    /**
+     * Returns the immediate sources of image data for this image.
+     * This method returns the source specified at construction time.
+     *
+     * @return the immediate sources, or an empty vector is none.
+     */
+    @Override
+    @SuppressWarnings("UseOfObsoleteCollectionType")
+    public Vector<RenderedImage> getSources() {
+        return new Vector<>(Arrays.asList(sources));
+    }
+
+    /**
+     * Returns the color model associated with this image (may be null).
+     * All rasters returned from this image will have this color model.
+     *
+     * @return the color model of this image, or {@code null} if unspecified.
+     */
+    @Override
+    public ColorModel getColorModel() {
+        return colorModel;
+    }
+
+    /**
+     * Returns the width of this image in pixels.
+     * This value is set at construction time.
+     *
+     * @return the width of this image.
+     */
+    @Override
+    public int getWidth() {
+        return width;
+    }
+
+    /**
+     * Returns the height of this image in pixels.
+     * This value is set at construction time.
+     *
+     * @return the height of this image.
+     */
+    @Override
+    public int getHeight() {
+        return height;
+    }
+
+    /**
+     * Returns the minimum <var>x</var> coordinate (inclusive) of this image.
+     * This value is set at construction time.
+     *
+     * @return the minimum <var>x</var> coordinate (column) of this image.
+     */
+    @Override
+    public int getMinX() {
+        return minX;
+    }
+
+    /**
+     * Returns the minimum <var>y</var> coordinate (inclusive) of this image.
+     * This value is set at construction time.
+     *
+     * @return the minimum <var>y</var> coordinate (row) of this image.
+     */
+    @Override
+    public int getMinY() {
+        return minY;
+    }
+
+    /**
+     * Returns the minimum tile index in the <var>x</var> direction.
+     * This value is set at construction time.
+     *
+     * @return the minimum tile index in the <var>x</var> direction.
+     */
+    @Override
+    public int getMinTileX() {
+        return minTileX;
+    }
+
+    /**
+     * Returns the minimum tile index in the <var>y</var> direction.
+     * This value is set at construction time.
+     *
+     * @return the minimum tile index in the <var>y</var> direction.
+     */
+    @Override
+    public int getMinTileY() {
+        return minTileY;
+    }
+}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java
index 6289f3b..6cd8807 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java
@@ -26,6 +26,7 @@ import java.awt.image.IndexColorModel;
 import java.awt.image.PackedColorModel;
 import java.awt.image.RenderedImage;
 import java.awt.image.Raster;
+import java.awt.image.RasterFormatException;
 import java.awt.image.SampleModel;
 import java.awt.image.SinglePixelPackedSampleModel;
 import org.apache.sis.internal.feature.Resources;
@@ -44,6 +45,20 @@ import org.apache.sis.util.resources.Vocabulary;
  */
 public final class ImageUtilities {
     /**
+     * Default width and height of tiles, in pixels.
+     */
+    public static final int DEFAULT_TILE_SIZE = 256;
+
+    /**
+     * Approximate size of the buffer to use for copying data from/to a raster, in bits.
+     * The actual buffer size may be smaller or larger, depending on the actual tile size.
+     * This value does not need to be very large. The current value is 8 kb.
+     *
+     * @see #prepareTransferRegion(Rectangle, int)
+     */
+    private static final int BUFFER_SIZE = 32 * DEFAULT_TILE_SIZE * Byte.SIZE;
+
+    /**
      * Do not allow instantiation of this class.
      */
     private ImageUtilities() {
@@ -274,4 +289,32 @@ public final class ImageUtilities {
         }
         return keys;
     }
+
+    /**
+     * Suggests the height of a transfer region for a tile of the given size. The given region
should be
+     * contained inside {@link Raster#getBounds()}. This method modifies {@link Rectangle#height}
in-place.
+     * The {@link Rectangle#width} value is never modified, so caller can iterate on all
raster rows without
+     * the need to check if the row is incomplete.
+     *
+     * @param  bounds    on input, the region of interest. On output, the suggested transfer
region bounds.
+     * @param  dataType  one of {@link DataBuffer} constant. It is okay if an unknown constant
is used since
+     *                   this information is used only as a hint for adjusting the {@link
#BUFFER_SIZE} value.
+     * @return the maximum <var>y</var> value plus 1. This can be used as stop
condition for iterating over rows.
+     * @throws ArithmeticException if the maximum <var>y</var> value overflows
32 bits integer capacity.
+     * @throws RasterFormatException if the given bounds is empty.
+     */
+    public static int prepareTransferRegion(final Rectangle bounds, final int dataType) {
+        if (bounds.isEmpty()) {
+            throw new RasterFormatException(Resources.format(Resources.Keys.EmptyTileOrImageRegion));
+        }
+        final int afterLastRow = Math.addExact(bounds.y, bounds.height);
+        int size;
+        try {
+            size = DataBuffer.getDataTypeSize(dataType);
+        } catch (IllegalArgumentException e) {
+            size = Short.SIZE;  // Arbitrary value is okay because this is only a hint for
choosing a buffer size.
+        }
+        bounds.height = Math.max(1, Math.min(BUFFER_SIZE / (size * bounds.width), bounds.height));
+        return afterLastRow;
+    }
 }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
index 6c2a399..97d152c 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
@@ -70,6 +70,11 @@ public final class Resources extends IndexedResourceBundle {
         public static final short CanNotAssignCharacteristics_1 = 2;
 
         /**
+         * Can not compute tile ({0}, {1}).
+         */
+        public static final short CanNotComputeTile_2 = 66;
+
+        /**
          * Can not create a two-dimensional reference system from the “{0}” system.
          */
         public static final short CanNotCreateTwoDimensionalCRS_1 = 60;
@@ -130,6 +135,11 @@ public final class Resources extends IndexedResourceBundle {
         public static final short DependencyNotFound_3 = 8;
 
         /**
+         * Empty tile or image region.
+         */
+        public static final short EmptyTileOrImageRegion = 67;
+
+        /**
          * Indices ({3}) are outside grid coverage. The value in dimension {0} shall be between
          * {1,number} and {2,number} inclusive.
          */
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
index 2355891..23f473b 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
@@ -21,6 +21,7 @@
 #
 AbstractFeatureType_1             = Feature type \u2018{0}\u2019 is abstract.
 CanNotAssignCharacteristics_1     = Can not assign characteristics to the \u201c{0}\u201d
property.
+CanNotComputeTile_2               = Can not compute tile ({0}, {1}).
 CanNotCreateTwoDimensionalCRS_1   = Can not create a two-dimensional reference system from
the \u201c{0}\u201d system.
 CanNotEnumerateValuesInRange_1    = Can not enumerate values in the {0} range.
 CanNotInstantiateProperty_1       = Property \u201c{0}\u201d is not a type that can be instantiated.
@@ -33,6 +34,7 @@ CategoryRangeOverlap_4            = The two categories \u201c{0}\u201d and
\u201
 CharacteristicsAlreadyExists_2    = Characteristics \u201c{1}\u201d already exists in attribute
\u201c{0}\u201d.
 CharacteristicsNotFound_2         = No characteristics named \u201c{1}\u201d has been found
in \u201c{0}\u201d attribute.
 DependencyNotFound_3              = Operation \u201c{0}\u201d requires a \u201c{1}\u201d
property, but no such property has been found in \u201c{2}\u201d.
+EmptyTileOrImageRegion            = Empty tile or image region.
 GridCoordinateOutsideCoverage_4   = Indices ({3}) are outside grid coverage. The value in
dimension {0} shall be between {1,number} and {2,number} inclusive.
 GridEnvelopeMustBeNDimensional_1  = The grid envelope must have at least {0} dimensions.
 GridEnvelopeOutsideCoverage_5     = Envelope is outside grid coverage. Indices [{3,number}
\u2026 {4,number}] in dimension {0} do not intersect the [{1,number} \u2026 {2,number}] grid
extent.
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
index bd333d7..ba6fac4 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
@@ -26,6 +26,7 @@
 #
 AbstractFeatureType_1             = Le type d\u2019entit\u00e9 \u2018{0}\u2019 est abstrait.
 CanNotAssignCharacteristics_1     = Ne peut pas assigner des caract\u00e9ristiques \u00e0
la propri\u00e9t\u00e9 \u00ab\u202f{0}\u202f\u00bb.
+CanNotComputeTile_2               = Ne peut pas calculer la tuile ({0}, {1}).
 CanNotCreateTwoDimensionalCRS_1   = Ne peut pas cr\u00e9er un syst\u00e8me de r\u00e9f\u00e9rence
bidimensionnel \u00e0 partir du syst\u00e8me \u00ab\u202f{0}\u202f\u00bb.
 CanNotEnumerateValuesInRange_1    = Ne peut pas \u00e9num\u00e9rer les valeurs dans la plage
{0}.
 CanNotInstantiateProperty_1       = La propri\u00e9t\u00e9 \u00ab\u202f{0}\u202f\u00bb n\u2019est
pas d\u2019un type qui peut \u00eatre instanci\u00e9.
@@ -38,6 +39,7 @@ CategoryRangeOverlap_4            = Les deux cat\u00e9gories \u00ab\u202f{0}\u20
 CharacteristicsAlreadyExists_2    = La caract\u00e9ristique \u00ab\u202f{1}\u202f\u00bb existe
d\u00e9j\u00e0 dans l\u2019attribut \u00ab\u202f{0}\u202f\u00bb.
 CharacteristicsNotFound_2         = Aucune caract\u00e9ristique nomm\u00e9e \u00ab\u202f{1}\u202f\u00bb
n\u2019a \u00e9t\u00e9 trouv\u00e9e dans l\u2019attribut \u00ab\u202f{0}\u202f\u00bb.
 DependencyNotFound_3              = L\u2019op\u00e9ration \u00ab\u202f{0}\u202f\u00bb n\u00e9cessite
une propri\u00e9t\u00e9 \u00ab\u202f{1}\u202f\u00bb, mais cette propri\u00e9t\u00e9 n\u2019a
pas \u00e9t\u00e9 trouv\u00e9e dans \u00ab\u202f{2}\u202f\u00bb.
+EmptyTileOrImageRegion            = La tuile ou la r\u00e9gion de l\u2019image est vide.
 GridCoordinateOutsideCoverage_4   = Les indices ({3}) sont en dehors du domaine de la grille.
La valeur dans la dimension {0} doit \u00eatre entre {1,number} et {2,number} inclusivement.
 GridEnvelopeMustBeNDimensional_1  = L\u2019enveloppe de la grille doit avoir au moins {0}
dimensions.
 GridEnvelopeOutsideCoverage_5     = L\u2019enveloppe est en dehors du domaine de la grille.
Les indices [{3,number} \u2026 {4,number}] dans la dimension {0} n\u2019interceptent pas l\u2019\u00e9tendue
[{1,number} \u2026 {2,number}] de la grille.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
index 296d78c..6222ef7 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
@@ -40,7 +40,7 @@ import static java.lang.Math.ulp;
  * Miscellaneous utilities methods working on floating point numbers.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
  * @since   0.3
  * @module
  */
@@ -222,6 +222,18 @@ public final class Numerics extends Static {
     }
 
     /**
+     * Returns the given value clamped to the range on 32 bits integer.
+     *
+     * @param  value  the value to clamp.
+     * @return the value clamped to the range of 32 bits integer.
+     */
+    public static int clamp(final long value) {
+        if (value < Integer.MIN_VALUE) return Integer.MIN_VALUE;
+        if (value > Integer.MAX_VALUE) return Integer.MAX_VALUE;
+        return (int) value;
+    }
+
+    /**
      * If the given value is presents in the cache, returns the cached value.
      * Otherwise returns the given value as-is.
      *
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/Scalar.java b/core/sis-utility/src/main/java/org/apache/sis/measure/Scalar.java
index e13f0cb..a425cb7 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/Scalar.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/Scalar.java
@@ -22,6 +22,7 @@ import javax.measure.Quantity;
 import javax.measure.UnitConverter;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.StringBuilders;
+import org.apache.sis.internal.util.Numerics;
 
 
 /**
@@ -155,7 +156,7 @@ abstract class Scalar<Q extends Quantity<Q>> extends Number
implements Quantity<
      */
     @Override
     public final int intValue() {
-        return (int) Math.max(Integer.MIN_VALUE, Math.min(Integer.MAX_VALUE, longValue()));
+        return Numerics.clamp(longValue());
     }
 
     /**


Mime
View raw message