sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: Avoid direct dependency to Java Topology Suite (JTS) library, and adjust exceptions.
Date Wed, 21 Aug 2019 16:40:18 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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new a4a4228  Avoid direct dependency to Java Topology Suite (JTS) library, and adjust
exceptions.
a4a4228 is described below

commit a4a422822c6df9485fd4e375b009b5fcd18ba8ef
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Wed Aug 21 18:39:12 2019 +0200

    Avoid direct dependency to Java Topology Suite (JTS) library, and adjust exceptions.
---
 .../src/main/java/org/apache/sis/filter/Node.java  |   2 +
 .../main/java/org/apache/sis/filter/ST_Buffer.java |  29 ++----
 .../java/org/apache/sis/filter/ST_Centroid.java    |  26 ++---
 .../java/org/apache/sis/filter/ST_Transform.java   |   6 +-
 .../java/org/apache/sis/internal/feature/ESRI.java |  17 +++-
 .../apache/sis/internal/feature/Geometries.java    | 109 ++++++++++++++++++---
 .../java/org/apache/sis/internal/feature/JTS.java  |  53 +++++++++-
 .../org/apache/sis/internal/feature/Java2D.java    |  22 ++++-
 .../storage/gpx/GroupAsPolylineOperation.java      |   3 +
 9 files changed, 209 insertions(+), 58 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/Node.java b/core/sis-feature/src/main/java/org/apache/sis/filter/Node.java
index 33c185a..c618c04 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/Node.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/Node.java
@@ -165,6 +165,8 @@ abstract class Node implements Serializable {
      * This method assumes that the warning occurred in an {@code evaluate(…)} method.
      *
      * @todo Consider defining a {@code Context} class providing, among other information,
listeners where to report warnings.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/SIS-460">SIS-460</a>
      */
     final void warning(final Exception e) {
         Logging.recoverableException(Logging.getLogger(Loggers.FILTER), getClass(), "evaluate",
e);
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Buffer.java b/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Buffer.java
index 46e8fca..603c982 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Buffer.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Buffer.java
@@ -22,21 +22,19 @@ import org.apache.sis.feature.builder.PropertyTypeBuilder;
 import org.apache.sis.internal.feature.FeatureExpression;
 import org.apache.sis.internal.feature.Geometries;
 import org.apache.sis.util.ArgumentChecks;
-import org.locationtech.jts.geom.Geometry;
 import org.opengis.feature.FeatureType;
 import org.opengis.filter.expression.Expression;
-import org.opengis.util.FactoryException;
 
 
 /**
- * An expression which compute a geometry buffer.
+ * An expression which computes a geometry buffer.
  * This expression expects two arguments:
  *
  * <ol class="verbose">
  *   <li>An expression returning a geometry object. The evaluated value shall be an
instance of
  *       one of the implementations enumerated in {@link org.apache.sis.setup.GeometryLibrary}.</li>
- *   <li>An expression returning a distance. The evaluated value shall be an instance
of
- *      Number. Distance is expressed in the geometry Coordinate reference system.</li>
+ *   <li>An expression returning a distance. The evaluated value shall be an instance
of {@link Number}.
+ *       Distance is expressed in units of the geometry Coordinate Reference System.</li>
  * </ol>
  *
  * @author  Johann Sorel (Geomatys)
@@ -49,7 +47,7 @@ final class ST_Buffer extends NamedFunction implements FeatureExpression
{
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = 1L;
+    private static final long serialVersionUID = 294412677972203232L;
 
     /**
      * Name of this function as defined by SQL/MM standard.
@@ -61,9 +59,8 @@ final class ST_Buffer extends NamedFunction implements FeatureExpression
{
      * that the given array is non-null, has been cloned and does not contain null elements.
      *
      * @throws IllegalArgumentException if the number of arguments is not equal to 2.
-     * @throws FactoryException if CRS can not be constructed from the second expression.
      */
-    ST_Buffer(final Expression[] parameters) throws FactoryException {
+    ST_Buffer(final Expression[] parameters) {
         super(parameters);
         ArgumentChecks.ensureExpectedCount("parameters", 2, parameters.length);
     }
@@ -77,21 +74,13 @@ final class ST_Buffer extends NamedFunction implements FeatureExpression
{
     }
 
     /**
-     * Evaluates the first expression as a geometry object, transforms that geometry to the
CRS given
-     * by the second expression and returns the result.
+     * Evaluates the first expression as a geometry object, gets the buffer of that geometry
and
+     * returns the result. If the geometry is not a supported implementation, returns {@code
null}.
      */
     @Override
     public Object evaluate(final Object value) {
-        Object geometry = parameters.get(0).evaluate(value);
-        if (geometry instanceof Geometry) {
-            final Geometry jts = (Geometry) geometry;
-            final double distance = parameters.get(1).evaluate(value, Number.class).doubleValue();
-            final Geometry buffer = jts.buffer(distance);
-            buffer.setSRID(jts.getSRID());
-            buffer.setUserData(jts.getUserData());
-            return buffer;
-        }
-        return null;
+        return Geometries.buffer(parameters.get(0).evaluate(value),
+                                 parameters.get(1).evaluate(value, Number.class).doubleValue());
     }
 
     /**
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Centroid.java b/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Centroid.java
index 665bcf1..99e8d13 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Centroid.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Centroid.java
@@ -22,16 +22,13 @@ import org.apache.sis.feature.builder.PropertyTypeBuilder;
 import org.apache.sis.internal.feature.FeatureExpression;
 import org.apache.sis.internal.feature.Geometries;
 import org.apache.sis.util.ArgumentChecks;
-import org.locationtech.jts.geom.Geometry;
-import org.locationtech.jts.geom.Point;
 import org.opengis.feature.FeatureType;
 import org.opengis.filter.expression.Expression;
-import org.opengis.util.FactoryException;
 
 
 /**
- * An expression which compute a geometry centroid.
- * This expression expects one arguments:
+ * An expression which computes the centroid of a geometry.
+ * This expression expects one argument:
  *
  * <ol class="verbose">
  *   <li>An expression returning a geometry object. The evaluated value shall be an
instance of
@@ -48,7 +45,7 @@ final class ST_Centroid extends NamedFunction implements FeatureExpression
{
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = 1L;
+    private static final long serialVersionUID = -3993074123019061170L;
 
     /**
      * Name of this function as defined by SQL/MM standard.
@@ -60,9 +57,8 @@ final class ST_Centroid extends NamedFunction implements FeatureExpression
{
      * that the given array is non-null, has been cloned and does not contain null elements.
      *
      * @throws IllegalArgumentException if the number of arguments is not equal to 1.
-     * @throws FactoryException if CRS can not be constructed from the second expression.
      */
-    ST_Centroid(final Expression[] parameters) throws FactoryException {
+    ST_Centroid(final Expression[] parameters) {
         super(parameters);
         ArgumentChecks.ensureExpectedCount("parameters", 1, parameters.length);
     }
@@ -76,20 +72,12 @@ final class ST_Centroid extends NamedFunction implements FeatureExpression
{
     }
 
     /**
-     * Evaluates the first expression as a geometry object, transforms that geometry to the
CRS given
-     * by the second expression and returns the result.
+     * Evaluates the first expression as a geometry object, gets the centroid of that geometry
and
+     * returns the result. If the geometry is not a supported implementation, returns {@code
null}.
      */
     @Override
     public Object evaluate(final Object value) {
-        Object geometry = parameters.get(0).evaluate(value);
-        if (geometry instanceof Geometry) {
-            final Geometry jts = (Geometry) geometry;
-            final Point centroid = jts.getCentroid();
-            centroid.setSRID(jts.getSRID());
-            centroid.setUserData(jts.getUserData());
-            return centroid;
-        }
-        return null;
+        return Geometries.getCentroid(parameters.get(0).evaluate(value));
     }
 
     /**
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Transform.java b/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Transform.java
index 7048f03..9f9724c 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Transform.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Transform.java
@@ -160,6 +160,10 @@ final class ST_Transform extends NamedFunction implements FeatureExpression
{
     /**
      * Evaluates the first expression as a geometry object, transforms that geometry to the
CRS given
      * by the second expression and returns the result.
+     *
+     * @param  value  the object from which to get a geometry.
+     * @return the transformed geometry, or {@code null} if the given object is not an instance
of
+     *         a supported geometry library (JTS, ERSI, Java2D…).
      */
     @Override
     public Object evaluate(final Object value) {
@@ -178,7 +182,7 @@ final class ST_Transform extends NamedFunction implements FeatureExpression
{
                 }
             }
             return Geometries.transform(geometry, targetCRS);
-        } catch (FactoryException | TransformException e) {
+        } catch (UnsupportedOperationException | FactoryException | TransformException e)
{
             warning(e);
         }
         return null;
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java
index bbd8780..f32b4f9 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java
@@ -29,6 +29,7 @@ import com.esri.core.geometry.WktImportFlags;
 import com.esri.core.geometry.WktExportFlags;
 import com.esri.core.geometry.OperatorImportFromWkt;
 import com.esri.core.geometry.OperatorExportToWkt;
+import com.esri.core.geometry.OperatorCentroid2D;
 import org.apache.sis.geometry.GeneralEnvelope;
 import org.apache.sis.setup.GeometryLibrary;
 import org.apache.sis.math.Vector;
@@ -114,6 +115,17 @@ final class ESRI extends Geometries<Geometry> {
     }
 
     /**
+     * If the given object is an ESRI geometry, returns its centroid. Otherwise returns {@code
null}.
+     */
+    @Override
+    final Object tryGetCentroid(final Object geometry) {
+        if (geometry instanceof Geometry) {
+            return OperatorCentroid2D.local().execute((Geometry) geometry, null);
+        }
+        return null;
+    }
+
+    /**
      * Creates a two-dimensional point from the given coordinate.
      */
     @Override
@@ -125,11 +137,14 @@ final class ESRI extends Geometries<Geometry> {
     /**
      * Creates a polyline from the given coordinate values.
      * Each {@link Double#NaN} coordinate value starts a new path.
+     *
+     * @param  dimension  the number of dimensions (2 or 3).
+     * @throws UnsupportedOperationException if this operation is not implemented for the
given number of dimensions.
      */
     @Override
     public Geometry createPolyline(final int dimension, final Vector... coordinates) {
         if (dimension != 2) {
-            throw unsupported(dimension);
+            throw new UnsupportedOperationException(unsupported(dimension));
         }
         boolean lineTo = false;
         final Polyline path = new Polyline();
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
index 0ed326d..f92634a 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
@@ -23,9 +23,11 @@ import org.opengis.util.FactoryException;
 import org.opengis.referencing.operation.TransformException;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.apache.sis.internal.referencing.ReferencingUtilities;
 import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.UnsupportedImplementationException;
+import org.apache.sis.util.Classes;
 import org.apache.sis.geometry.GeneralEnvelope;
 import org.apache.sis.setup.GeometryLibrary;
 import org.apache.sis.math.Vector;
@@ -243,6 +245,29 @@ public abstract class Geometries<G> {
     }
 
     /**
+     * If the given geometry is the type supported by this {@code Geometries} instance, returns
its
+     * centroid or center as a point instance of the same library. Otherwise returns {@code
null}.
+     */
+    abstract Object tryGetCentroid(Object geometry);
+
+    /**
+     * If the given object is one of the recognized types, returns its mathematical centroid
+     * (if possible) or center (as a fallback) as a point instance of the same library.
+     * Otherwise returns {@code null}.
+     *
+     * @param  geometry  the geometry from which to get the centroid, or {@code null}.
+     * @return the centroid of the given geometry, or {@code null} if the given object
+     *         is not a recognized geometry.
+     */
+    public static Object getCentroid(final Object geometry) {
+        for (Geometries<?> g = implementation; g != null; g = g.fallback) {
+            Object center = g.tryGetCentroid(geometry);
+            if (center != null) return center;
+        }
+        return null;
+    }
+
+    /**
      * If the given geometry is the type supported by this {@code Geometries} instance,
      * returns a short string representation of the class name. Otherwise returns {@code
null}.
      */
@@ -347,7 +372,8 @@ public abstract class Geometries<G> {
      *
      * @param  paths  the points or polylines to merge in a single polyline object.
      * @return the merged polyline, or {@code null} if the given iterator has no element.
-     * @throws ClassCastException if not all elements in the given iterator are instances
of the same library.
+     * @throws ClassCastException if collection elements are not instances of a supported
library,
+     *         or not all elements are instances of the same library.
      */
     public static Object mergePolylines(final Iterator<?> paths) {
         while (paths.hasNext()) {
@@ -359,20 +385,52 @@ public abstract class Geometries<G> {
                         return merged;
                     }
                 }
-                throw unsupported(2);
+                /*
+                 * Use the same exception type than `tryMergePolylines(…)` implementations.
+                 * Also the same type than exception occurring elsewhere in the code of the
+                 * caller (GroupAsPolylineOperation).
+                 */
+                throw new ClassCastException(unsupportedImplementation(first));
             }
         }
         return null;
     }
 
     /**
+     * If the given geometry is the type supported by this {@code Geometries} instance, computes
+     * its buffer as a geometry instance of the same library. Otherwise returns {@code null}.
+     */
+    Object tryBuffer(Object geometry, double distance) {
+        if (rootClass.isInstance(geometry)) {
+            throw new UnsupportedImplementationException(unsupported("buffer"));
+        }
+        return null;
+    }
+
+    /**
+     * If the given object is one of the recognized types, computes its buffer as a geometry
instance
+     * of the same library. Otherwise returns {@code null}.
+     *
+     * @param  geometry  the geometry from which to compute a buffer, or {@code null}.
+     * @param  distance  the buffer distance in the CRS of the geometry object.
+     * @return the buffer of the given geometry, or {@code null} if the given object is not
recognized.
+     */
+    public static Object buffer(final Object geometry, final double distance) {
+        for (Geometries<?> g = implementation; g != null; g = g.fallback) {
+            Object center = g.tryBuffer(geometry, distance);
+            if (center != null) return center;
+        }
+        return null;
+    }
+
+    /**
      * Tries to transforms the given geometry to the specified Coordinate Reference System
(CRS),
      * or returns {@code null} if this method can not perform this operation on the given
object.
      * Exactly one of {@code operation} and {@code targetCRS} shall be non-null. If operation
is
      * null and geometry has no Coordinate Reference System, a {@link TransformException}
is thrown.
      *
-     * <p>Current default implementation returns {@code null} because current Apache
SIS implementation
-     * supports geometry transformations only with JTS geometries.</p>
+     * <p>Default implementation throws {@link UnsupportedImplementationException} because
current
+     * Apache SIS implementation supports geometry transformations only with JTS geometries.</p>
      *
      * @param  geometry   the geometry to transform.
      * @param  operation  the coordinate operation to apply, or {@code null}.
@@ -384,6 +442,9 @@ public abstract class Geometries<G> {
     Object tryTransform(Object geometry, CoordinateOperation operation, CoordinateReferenceSystem
targetCRS)
             throws FactoryException, TransformException
     {
+        if (rootClass.isInstance(geometry)) {
+            throw new UnsupportedImplementationException(unsupported("transform"));
+        }
         return null;
     }
 
@@ -392,13 +453,15 @@ public abstract class Geometries<G> {
      * If the geometry or the operation is null, then the geometry is returned unchanged.
      * If the geometry uses a different CRS than the source CRS of the given operation,
      * then a new operation to the target CRS will be used.
+     * If the given object is not a known implementation, then this method returns {@code
null}.
      *
      * <p>This method is preferred to {@link #transform(Object, CoordinateReferenceSystem)}
      * when possible because not all geometry libraries store the CRS of their objects.</p>
      *
      * @param  geometry   the geometry to transform, or {@code null}.
      * @param  operation  the coordinate operation to apply, or {@code null}.
-     * @return the transformed geometry, or the same geometry if it is already in target
CRS.
+     * @return the transformed geometry (may be the same geometry instance), or {@code null}.
+     * @throws UnsupportedImplementationException if this operation is not supported for
the given geometry.
      * @throws FactoryException if transformation to the target CRS can not be constructed.
      * @throws TransformException if the given geometry can not be transformed.
      */
@@ -417,8 +480,7 @@ public abstract class Geometries<G> {
                 }
             }
             if (!operation.getMathTransform().isIdentity()) {
-                final int dimension = ReferencingUtilities.getDimension(operation.getTargetCRS());
-                throw unsupported(dimension != 0 ? dimension : 2);
+                return null;
             }
         }
         return geometry;
@@ -428,6 +490,7 @@ public abstract class Geometries<G> {
      * Transforms the given geometry to the specified Coordinate Reference System (CRS).
      * If the given CRS or the given geometry is null, the geometry is returned unchanged.
      * If the geometry has no Coordinate Reference System, a {@link TransformException} is
thrown.
+     * If the given object is not a known implementation, then this method returns {@code
null}.
      *
      * <p>Consider using {@link #transform(Object, CoordinateOperation)} instead of
this method
      * as much as possible, both for performance reasons and because not all geometry libraries
@@ -435,7 +498,8 @@ public abstract class Geometries<G> {
      *
      * @param  geometry   the geometry to transform, or {@code null}.
      * @param  targetCRS  the target coordinate reference system, or {@code null}.
-     * @return the transformed geometry, or the same geometry if it is already in target
CRS.
+     * @return the transformed geometry (may be the same geometry instance), or {@code null}.
+     * @throws UnsupportedImplementationException if this operation is not supported for
the given geometry.
      * @throws FactoryException if transformation to the target CRS can not be constructed.
      * @throws TransformException if the given geometry has no CRS or can not be transformed.
      *
@@ -451,18 +515,35 @@ public abstract class Geometries<G> {
                     return result;
                 }
             }
-            final int dimension = ReferencingUtilities.getDimension(targetCRS);
-            throw unsupported(dimension != 0 ? dimension : 2);
+            return null;
         }
         return geometry;
     }
 
     /**
-     * Returns an error message for an unsupported geometry object.
+     * Returns an error message for an unsupported operation. This error message is used
by non-abstract methods
+     * in {@code Geometries} subclasses, after we identified the geometry library implementation
to use but that
+     * library does not provided the required functionality.
+     */
+    static String unsupported(final String operation) {
+        return Errors.format(Errors.Keys.UnsupportedOperation_1, operation);
+    }
+
+    /**
+     * Returns an error message for an unsupported number of dimensions in a geometry object.
      *
      * @param  dimension  number of dimensions (2 or 3) requested for the geometry object.
      */
-    static UnsupportedOperationException unsupported(final int dimension) {
-        return new UnsupportedOperationException(Resources.format(Resources.Keys.UnsupportedGeometryObject_1,
dimension));
+    static String unsupported(final int dimension) {
+        return Resources.format(Resources.Keys.UnsupportedGeometryObject_1, dimension);
+    }
+
+    /**
+     * Returns an error message for an unsupported geometry object implementation.
+     *
+     * @param  geometry  the unsupported object.
+     */
+    private static String unsupportedImplementation(final Object geometry) {
+        return Errors.format(Errors.Keys.UnsupportedType_1, Classes.getClass(geometry));
     }
 }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java
index 8a9c76a..b5ded9f 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.feature;
 
+import java.util.Map;
 import java.util.List;
 import java.util.Arrays;
 import java.util.ArrayList;
@@ -158,6 +159,40 @@ final class JTS extends Geometries<Geometry> {
     }
 
     /**
+     * Copies coordinate reference system information from the given source geometry to the
target geometry.
+     * Current implementation copies only CRS information, but future implementations could
copy some other
+     * values if they may apply to the target geometry as well.
+     */
+    private static void copyMetadata(final Geometry source, final Geometry target) {
+        target.setSRID(source.getSRID());
+        Object crs = source.getUserData();
+        if (!(crs instanceof CoordinateReferenceSystem)) {
+            if (!(crs instanceof Map<?,?>)) {
+                return;
+            }
+            crs = ((Map<?,?>) crs).get(org.apache.sis.internal.feature.jts.JTS.CRS_KEY);
+            if (!(crs instanceof CoordinateReferenceSystem)) {
+                return;
+            }
+        }
+        target.setUserData(crs);
+    }
+
+    /**
+     * If the given object is a JTS geometry, returns its centroid. Otherwise returns {@code
null}.
+     */
+    @Override
+    final Object tryGetCentroid(final Object geometry) {
+        if (geometry instanceof Geometry) {
+            final Geometry jts = (Geometry) geometry;
+            final Point centroid = jts.getCentroid();
+            copyMetadata(jts, centroid);
+            return centroid;
+        }
+        return null;
+    }
+
+    /**
      * Creates a two-dimensional point from the given coordinate.
      *
      * @return the point for the given coordinate values.
@@ -171,13 +206,15 @@ final class JTS extends Geometries<Geometry> {
      * Creates a polyline from the given coordinate values.
      * Each {@link Double#NaN} coordinate value starts a new path.
      *
+     * @param  dimension  the number of dimensions (2 or 3).
      * @return the geometric object for the given points.
+     * @throws UnsupportedOperationException if this operation is not implemented for the
given number of dimensions.
      */
     @Override
     public Geometry createPolyline(final int dimension, final Vector... coords) {
         final boolean is3D = (dimension == 3);
         if (!is3D && dimension != 2) {
-            throw unsupported(dimension);
+            throw new UnsupportedOperationException(unsupported(dimension));
         }
         final List<Coordinate> coordinates = new ArrayList<>(32);
         final List<LineString> lines = new ArrayList<>();
@@ -285,6 +322,20 @@ add:    for (;;) {
     }
 
     /**
+     * If the given geometry is a JTS geometry, computes its buffer. Otherwise returns {@code
null}.
+     */
+    @Override
+    Object tryBuffer(final Object geometry, final double distance) {
+        if (geometry instanceof Geometry) {
+            final Geometry jts = (Geometry) geometry;
+            final Geometry buffer = jts.buffer(distance);
+            copyMetadata(jts, buffer);
+            return buffer;
+        }
+        return null;
+    }
+
+    /**
      * Tries to transforms the given geometry to the specified Coordinate Reference System
(CRS),
      * or returns {@code null} if this method can not perform this operation on the given
object.
      * Exactly one of {@code operation} and {@code targetCRS} shall be non-null.
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java
index f0a70f3..19a019a 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java
@@ -22,6 +22,7 @@ import java.awt.geom.Line2D;
 import java.awt.geom.Path2D;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
+import java.awt.geom.RectangularShape;
 import org.apache.sis.geometry.GeneralEnvelope;
 import org.apache.sis.setup.GeometryLibrary;
 import org.apache.sis.internal.feature.j2d.ShapeProperties;
@@ -29,6 +30,7 @@ import org.apache.sis.internal.referencing.j2d.ShapeUtilities;
 import org.apache.sis.math.Vector;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.Numbers;
+import org.apache.sis.util.UnsupportedImplementationException;
 
 
 /**
@@ -103,6 +105,19 @@ final class Java2D extends Geometries<Shape> {
     }
 
     /**
+     * If the given object is a Java2D geometry, returns its centroid. Otherwise returns
{@code null}.
+     */
+    @Override
+    final Object tryGetCentroid(final Object geometry) {
+        if (geometry instanceof Shape) {
+            final RectangularShape frame = (geometry instanceof RectangularShape)
+                    ? (RectangularShape) geometry : ((Shape) geometry).getBounds2D();
+            return new Point2D.Double(frame.getCenterX(), frame.getCenterY());
+        }
+        return null;
+    }
+
+    /**
      * Creates a two-dimensional point from the given coordinate.
      */
     @Override
@@ -115,11 +130,14 @@ final class Java2D extends Geometries<Shape> {
      * Each {@link Double#NaN} coordinate value starts a new path.
      * The geometry may be backed by {@code float} or {@code double} primitive type,
      * depending on the type used by the given vectors.
+     *
+     * @param  dimension  the number of dimensions (2 or 3).
+     * @throws UnsupportedOperationException if this operation is not implemented for the
given number of dimensions.
      */
     @Override
     public Shape createPolyline(final int dimension, final Vector... coordinates) {
         if (dimension != 2) {
-            throw unsupported(dimension);
+            throw new UnsupportedOperationException(unsupported(dimension));
         }
         /*
          * Computes the total length of all vectors and verifies if any vector
@@ -236,6 +254,6 @@ add:    for (;;) {
      */
     @Override
     public Object parseWKT(final String wkt) {
-        throw unsupported(2);
+        throw new UnsupportedImplementationException(unsupported("parseWKT"));
     }
 }
diff --git a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java
b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java
index 4591ac8..83d044a 100644
--- a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java
+++ b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java
@@ -179,6 +179,9 @@ final class GroupAsPolylineOperation extends AbstractOperation {
 
         /**
          * Computes the geometry from all points or polylines found in the associated feature.
+         *
+         * @throws ClassCastException if a feature, a property value or a geometry is not
of the expected class.
+         *         This exception should not happen since we use {@link #feature} in contexts
where types are known.
          */
         @Override
         public G getValue() {


Mime
View raw message