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 e891f327a4dcef7f5c9ce97a9a17627085230fa2 Author: Martin Desruisseaux <[email protected]> AuthorDate: Tue Jan 8 20:48:43 2019 +0100 Move JTS specific methods to "jts" subpackage. --- .../apache/sis/internal/feature/Geometries.java | 52 ++----- .../java/org/apache/sis/internal/feature/JTS.java | 158 ++------------------- .../feature/jts/GeometryCoordinateTransform.java | 14 +- .../internal/feature/jts/GeometryTransform.java | 77 +++++----- .../org/apache/sis/internal/feature/jts/JTS.java | 156 ++++++++++++++++++++ .../sis/internal/feature/jts/package-info.java | 31 ++++ .../sis/internal/feature/GeometriesTestCase.java | 2 +- .../org/apache/sis/internal/feature/JTSTest.java | 71 --------- .../sis/internal/feature/{ => jts}/JTSTest.java | 71 ++------- .../apache/sis/test/suite/FeatureTestSuite.java | 1 + 10 files changed, 268 insertions(+), 365 deletions(-) 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 0d6beae..0c83667 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 @@ -19,8 +19,6 @@ package org.apache.sis.internal.feature; import java.util.Iterator; import java.util.logging.Level; import java.util.logging.LogRecord; -import org.opengis.util.FactoryException; -import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.apache.sis.util.logging.Logging; import org.apache.sis.internal.system.Loggers; import org.apache.sis.geometry.GeneralEnvelope; @@ -107,7 +105,7 @@ public abstract class Geometries<G> { String classname = Geometries.class.getName(); classname = classname.substring(0, classname.lastIndexOf('.')+1).concat(name); try { - implementation = (Geometries) Class.forName(classname).newInstance(); + implementation = (Geometries) Class.forName(classname).getDeclaredConstructor().newInstance(); } catch (ReflectiveOperationException | LinkageError e) { LogRecord record = Resources.forLocale(null).getLogRecord(Level.CONFIG, Resources.Keys.OptionalLibraryNotFound_2, name, e.toString()); @@ -163,8 +161,6 @@ public abstract class Geometries<G> { * or {@code null} if the given object is not a recognized implementation. * * @see #createPoint(double, double) - * - * @see #getCoordinateReferenceSystem(Object) */ public static double[] getCoordinate(final Object point) { for (Geometries<?> g = implementation; g != null; g = g.fallback) { @@ -227,6 +223,15 @@ public abstract class Geometries<G> { } /** + * Parses the given WKT. + * + * @param wkt the WKT to parse. + * @return the geometry object for the given WKT. + * @throws Exception if the WKT can not be parsed. The exception sub-class depends on the implementation. + */ + public abstract Object parseWKT(String wkt) throws Exception; + + /** * Creates a two-dimensional point from the given coordinate. If the CRS is geographic, then the * (x,y) values should be (longitude, latitude) for compliance with usage in ESRI and JTS libraries. * @@ -288,43 +293,6 @@ public abstract class Geometries<G> { } /** - * Parses the given WKT. - * - * @param wkt the WKT to parse. - * @return the geometry object for the given WKT. - * @throws Exception if the WKT can not be parsed. The exception sub-class depends on the implementation. - */ - public abstract Object parseWKT(String wkt) throws Exception; - - /** - * If the given geometry is an implementation of this library, returns its coordinate reference system. - * Otherwise returns {@code null}. - * - * @param geometry the geometry from which to get the CRS. - * @return the coordinate reference system, or {@code null} if none. - * @throws FactoryException if the CRS can not be created from the SRID code. - */ - CoordinateReferenceSystem tryGetCoordinateReferenceSystem(Object geometry) throws FactoryException { - return null; - } - - /** - * If the given object is one of the recognized geometry implementations, gets its Coordinate Reference System (CRS). - * Otherwise returns {@code null}. - * - * @param geometry the geometry from which to get the CRS. - * @return the coordinate reference system, or {@code null} if none. - * @throws FactoryException if the CRS can not be created from the SRID code. - */ - public static CoordinateReferenceSystem getCoordinateReferenceSystem(final Object geometry) throws FactoryException { - for (Geometries<?> g = implementation; g != null; g = g.fallback) { - CoordinateReferenceSystem crs = g.tryGetCoordinateReferenceSystem(geometry); - if (crs != null) return crs; - } - return null; - } - - /** * Returns an error message for an unsupported geometry object. * * @param dimension number of dimensions (2 or 3) requested for the geometry object. 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 27879af..9234435 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 @@ -20,12 +20,6 @@ import java.util.List; import java.util.Arrays; import java.util.ArrayList; import java.util.Iterator; -import java.util.Map; -import org.opengis.util.FactoryException; -import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.opengis.referencing.operation.CoordinateOperation; -import org.opengis.referencing.operation.MathTransform; -import org.opengis.referencing.operation.TransformException; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.Polygon; @@ -37,12 +31,9 @@ import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.io.WKTReader; import org.locationtech.jts.io.ParseException; import org.apache.sis.geometry.GeneralEnvelope; -import org.apache.sis.internal.feature.jts.GeometryCoordinateTransform; import org.apache.sis.setup.GeometryLibrary; import org.apache.sis.math.Vector; -import org.apache.sis.referencing.CRS; import org.apache.sis.util.Classes; -import org.apache.sis.util.Utilities; /** @@ -56,13 +47,7 @@ import org.apache.sis.util.Utilities; * @since 0.7 * @module */ -public final class JTS extends Geometries<Geometry> { - /** - * Key used in {@linkplain Geometry#getUserData() user data} map for storing - * an instance of {@link CoordinateReferenceSystem}. - */ - public static final String CRS_KEY = "CRS"; - +final class JTS extends Geometries<Geometry> { /** * The factory to use for creating JTS geometries. Currently set to a factory using * double-precision floating point numbers and a spatial-reference ID of 0. @@ -78,6 +63,17 @@ public final class JTS extends Geometries<Geometry> { } /** + * Parses the given WKT. + * + * @return the geometry object for the given WKT. + * @throws ParseException if the WKT can not be parsed. + */ + @Override + public Object parseWKT(final String wkt) throws ParseException { + return new WKTReader(factory).read(wkt); + } + + /** * If the given object is a JTS geometry, returns a short string representation of the class name. */ @Override @@ -260,134 +256,4 @@ public final class JTS extends Geometries<Geometry> { toLineString(coordinates, lines); return toGeometry(lines); } - - /** - * Parses the given WKT. - * - * @return the geometry object for the given WKT. - * @throws ParseException if the WKT can not be parsed. - */ - @Override - public Object parseWKT(final String wkt) throws ParseException { - return new WKTReader(factory).read(wkt); - } - - /** - * Gets the Coordinate Reference System (CRS) from the given geometry. - * This method expects the CRS to be stored in one the following ways: - * - * <ul> - * <li>Geometry {@linkplain Geometry#getUserData() user data} is an instance of {@code CoordinateReferenceSystem}.</li> - * <li>{@linkplain Geometry#getUserData() user data} is a (@link Map} with a value for the {@value #CRS_KEY} key.</li> - * <li>Geometry SRID is strictly positive, in which case it is interpreted as an EPSG code.</li> - * </ul> - * - * If none of the above is valid, {@code null} is returned. - * - * @param geometry the geometry from which to get the CRS. - * @return the coordinate reference system, or {@code null} if none. - * @throws FactoryException if the CRS can not be created from the SRID code. - */ - @Override - CoordinateReferenceSystem tryGetCoordinateReferenceSystem(final Object geometry) throws FactoryException { - if (geometry instanceof Geometry) { - final Geometry jts = (Geometry) geometry; - final Object userData = jts.getUserData(); - if (userData instanceof CoordinateReferenceSystem) { - return (CoordinateReferenceSystem) userData; - } else if (userData instanceof Map<?,?>) { - final Map<?,?> map = (Map<?,?>) userData; - final Object value = map.get(CRS_KEY); - if (value instanceof CoordinateReferenceSystem) { - return (CoordinateReferenceSystem) value; - } - } - /* - * Fallback on SRID. - */ - final int srid = jts.getSRID(); - if (srid > 0) { - return CRS.forCode("EPSG:" + srid); - } - } - return super.tryGetCoordinateReferenceSystem(geometry); - } - - /** - * Transform given geometry to a new CoordinateReferenceSystem. - * - * <p> - * If CoordinateReferenceSystem of geometry is null, geometry is returned unchanged. - * </p> - * <p> - * If geometry has no CoordinateReferenceSystem a TransformException is throwed. - * </p> - * - * @param geometry source geometry - * @param targetCrs target CoordinateReferenceSystem - * @return transformed geometry, or same geometry if it is already in target crs - * @throws org.opengis.referencing.operation.TransformException if geometry - * has no CRS or failed to apply transform. - * @throws org.opengis.util.FactoryException - */ - public static Geometry transform(Geometry geometry, CoordinateReferenceSystem targetCrs) - throws TransformException, FactoryException - { - if (geometry == null || targetCrs == null) { - return geometry; - } - final CoordinateReferenceSystem sourceCrs = getCoordinateReferenceSystem(geometry); - if (sourceCrs == null) { - throw new TransformException("Geometry CRS is undefined"); - } else if (Utilities.equalsIgnoreMetadata(sourceCrs, targetCrs)) { - return geometry; - } - return transform(geometry, CRS.findOperation(sourceCrs, targetCrs, null)); - } - - /** - * Transform geometry, result is a new geometry. - * - * <p> - * If geometry or operation is null, geometry is returned unchanged. - * </p> - * - * TODO : handle antemeridian cases. - * - * @param geometry - * @param operation - * @return - * @throws TransformException if transformation failed - */ - public static Geometry transform(Geometry geometry, CoordinateOperation operation) throws TransformException { - if (geometry == null || operation == null) { - return geometry; - } - geometry = transform(geometry, operation.getMathTransform()); - geometry.setUserData(operation.getTargetCRS()); - return geometry; - } - - /** - * Transform geometry, result is a new geometry. - * - * <p> - * If geometry or transform is null, geometry is returned unchanged. - * </p> - * - * @param geometry - * @param transform - * @return transformed geometry or null. - * @throws TransformException if transformation failed - */ - public static Geometry transform(Geometry geometry, MathTransform transform) throws TransformException { - if (geometry == null || transform == null) { - return geometry; - } - final GeometryCoordinateTransform gct = new GeometryCoordinateTransform(transform, geometry.getFactory()); - final Geometry result = gct.transform(geometry); - result.setSRID(geometry.getSRID()); - result.setUserData(geometry.getUserData()); - return result; - } } diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/GeometryCoordinateTransform.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/GeometryCoordinateTransform.java index fa9307d..43269e0 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/GeometryCoordinateTransform.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/GeometryCoordinateTransform.java @@ -22,17 +22,20 @@ import org.locationtech.jts.geom.GeometryFactory; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; + /** - * This implementation use a MathTransform to transform each coordinate of - * the geometry. + * A geometry transformer which uses a {@link MathTransform} for changing coordinate values. + * This class does not change the number of points. * - * @author Johann Sorel (Geomatys) + * @author Johann Sorel (Geomatys) * @version 1.0 * @since 1.0 * @module */ public class GeometryCoordinateTransform extends GeometryTransform { - + /** + * The transform to apply on coordinate values. + */ private final MathTransform transform; public GeometryCoordinateTransform(MathTransform transform) { @@ -53,7 +56,7 @@ public class GeometryCoordinateTransform extends GeometryTransform { protected CoordinateSequence transform(CoordinateSequence in, int minpoints) throws TransformException { final int dim = in.getDimension(); final int size = in.size(); - final CoordinateSequence out = csf.create(size, dim); + final CoordinateSequence out = coordinateFactory.create(size, dim); final double[] val = new double[dim]; for (int i = 0; i<size; i++) { @@ -78,5 +81,4 @@ public class GeometryCoordinateTransform extends GeometryTransform { } return out; } - } diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/GeometryTransform.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/GeometryTransform.java index 9c0be5c..4fca59d 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/GeometryTransform.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/GeometryTransform.java @@ -30,43 +30,49 @@ import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.Polygon; import org.opengis.referencing.operation.TransformException; + /** - * Abstract class parent to all JTS geometry transformations. - * This class decompose the geometry to it's most primitive element, the - * CoordinateSequence, then rebuild the geometry. + * An operation transforming a geometry into another geometry. This class decomposes the geometry into it's + * most primitive elements, the {@link CoordinateSequence}, applies an operation, then rebuilds the geometry. + * The operation may change coordinate values (for example a map projection), but not necessarily. An operation + * could also be a clipping for example. * - * @author Johann Sorel (Geomatys) + * @author Johann Sorel (Geomatys) * @version 1.0 * @since 1.0 * @module */ public abstract class GeometryTransform { + /** + * The factory to use for creating geometries. + */ + private final GeometryFactory geometryFactory; - protected final GeometryFactory gf; - protected final CoordinateSequenceFactory csf; + /** + * The factory to use for creating sequences of coordinate tuples. + */ + protected final CoordinateSequenceFactory coordinateFactory; - public GeometryTransform() { - this((CoordinateSequenceFactory) null); + protected GeometryTransform() { + this((GeometryFactory) null); } - public GeometryTransform(final CoordinateSequenceFactory csf) { - if (csf == null) { - this.gf = new GeometryFactory(); - this.csf = gf.getCoordinateSequenceFactory(); + protected GeometryTransform(final CoordinateSequenceFactory factory) { + if (factory == null) { + geometryFactory = new GeometryFactory(); + coordinateFactory = geometryFactory.getCoordinateSequenceFactory(); } else { - this.csf = csf; - this.gf = new GeometryFactory(csf); + coordinateFactory = factory; + geometryFactory = new GeometryFactory(factory); } } - public GeometryTransform(final GeometryFactory gf) { - if (gf == null) { - this.gf = new GeometryFactory(); - this.csf = gf.getCoordinateSequenceFactory(); - } else { - this.csf = gf.getCoordinateSequenceFactory(); - this.gf = gf; + protected GeometryTransform(GeometryFactory factory) { + if (factory == null) { + factory = new GeometryFactory(); } + geometryFactory = factory; + coordinateFactory = factory.getCoordinateSequenceFactory(); } public Geometry transform(final Geometry geom) throws TransformException { @@ -87,33 +93,32 @@ public abstract class GeometryTransform { } else if (geom instanceof GeometryCollection) { return transform((GeometryCollection) geom); } else { - throw new IllegalArgumentException("Geometry type is unknowed or null : " + geom); + throw new IllegalArgumentException("Geometry type is unknown or null: " + geom); } } protected Point transform(final Point geom) throws TransformException { final CoordinateSequence coord = geom.getCoordinateSequence(); - return gf.createPoint(transform(coord, 1)); + return geometryFactory.createPoint(transform(coord, 1)); } protected MultiPoint transform(final MultiPoint geom) throws TransformException { final int nbGeom = geom.getNumGeometries(); - final Point[] subs = new Point[geom.getNumGeometries()]; for (int i = 0; i < nbGeom; i++) { subs[i] = transform((Point) geom.getGeometryN(i)); } - return gf.createMultiPoint(subs); + return geometryFactory.createMultiPoint(subs); } protected LineString transform(final LineString geom) throws TransformException { final CoordinateSequence seq = transform(geom.getCoordinateSequence(), 2); - return gf.createLineString(seq); + return geometryFactory.createLineString(seq); } protected LinearRing transform(final LinearRing geom) throws TransformException { final CoordinateSequence seq = transform(geom.getCoordinateSequence(), 4); - return gf.createLinearRing(seq); + return geometryFactory.createLinearRing(seq); } protected MultiLineString transform(final MultiLineString geom) throws TransformException { @@ -121,7 +126,7 @@ public abstract class GeometryTransform { for (int i = 0; i < subs.length; i++) { subs[i] = transform((LineString) geom.getGeometryN(i)); } - return gf.createMultiLineString(subs); + return geometryFactory.createMultiLineString(subs); } protected Polygon transform(final Polygon geom) throws TransformException { @@ -130,7 +135,7 @@ public abstract class GeometryTransform { for (int i = 0; i < holes.length; i++) { holes[i] = transform((LinearRing) geom.getInteriorRingN(i)); } - return gf.createPolygon(exterior, holes); + return geometryFactory.createPolygon(exterior, holes); } protected MultiPolygon transform(final MultiPolygon geom) throws TransformException { @@ -138,7 +143,7 @@ public abstract class GeometryTransform { for (int i = 0; i < subs.length; i++) { subs[i] = transform((Polygon) geom.getGeometryN(i)); } - return gf.createMultiPolygon(subs); + return geometryFactory.createMultiPolygon(subs); } protected GeometryCollection transform(final GeometryCollection geom) throws TransformException { @@ -146,16 +151,16 @@ public abstract class GeometryTransform { for (int i = 0; i < subs.length; i++) { subs[i] = transform(geom.getGeometryN(i)); } - return gf.createGeometryCollection(subs); + return geometryFactory.createGeometryCollection(subs); } /** + * Transforms the given sequence of coordinate tuples, producing a new sequence of tuples. * - * @param sequence Sequence to transform - * @param minpoints Minimum number of point to preserve - * @return transformed sequence - * @throws TransformException + * @param sequence sequence of coordinate tuples to transform. + * @param minpoints minimum number of points to preserve. + * @return the transformed sequence of coordinate tuples. + * @throws TransformException if an error occurred while transforming a tuple. */ protected abstract CoordinateSequence transform(CoordinateSequence sequence, int minpoints) throws TransformException; - } diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/JTS.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/JTS.java new file mode 100644 index 0000000..019c7d1 --- /dev/null +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/JTS.java @@ -0,0 +1,156 @@ +/* + * 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.feature.jts; + +import java.util.Map; +import org.opengis.util.FactoryException; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.operation.CoordinateOperation; +import org.opengis.referencing.operation.MathTransform; +import org.opengis.referencing.operation.TransformException; +import org.apache.sis.internal.util.Constants; +import org.apache.sis.referencing.CRS; +import org.apache.sis.util.Static; +import org.apache.sis.util.Utilities; +import org.locationtech.jts.geom.Geometry; + + +/** + * Utilities for Java Topology Suite (JTS) objects. + * We use this class for functionalities not supported by Apache SIS with other libraries. + * For library-agnostic functionalities, see {@link org.apache.sis.internal.feature.Geometries} instead. + * + * @author Johann Sorel (Geomatys) + * @version 1.0 + * @since 1.0 + * @module + */ +public final class JTS extends Static { + /** + * Key used in {@linkplain Geometry#getUserData() user data} map for storing an instance of {@link CoordinateReferenceSystem}. + * + * @see #getCoordinateReferenceSystem(Geometry) + */ + public static final String CRS_KEY = "CRS"; + + /** + * Do not allow instantiation of this class. + */ + private JTS() { + } + + /** + * Gets the Coordinate Reference System (CRS) from the given geometry. + * This method expects the CRS to be stored in one the following ways: + * + * <ul> + * <li>Geometry {@linkplain Geometry#getUserData() user data} is an instance of {@code CoordinateReferenceSystem}.</li> + * <li>{@linkplain Geometry#getUserData() user data} is a (@link Map} with a value for the {@value #CRS_KEY} key.</li> + * <li>Geometry SRID is strictly positive, in which case it is interpreted as an EPSG code.</li> + * </ul> + * + * If none of the above is valid, {@code null} is returned. + * + * @param geometry the geometry from which to get the CRS, or {@code null}. + * @return the coordinate reference system, or {@code null} if none. + * @throws FactoryException if the CRS can not be created from the SRID code. + */ + public static CoordinateReferenceSystem getCoordinateReferenceSystem(final Geometry geometry) throws FactoryException { + if (geometry != null) { + final Object userData = geometry.getUserData(); + if (userData instanceof CoordinateReferenceSystem) { + return (CoordinateReferenceSystem) userData; + } else if (userData instanceof Map<?,?>) { + final Map<?,?> map = (Map<?,?>) userData; + final Object value = map.get(CRS_KEY); + if (value instanceof CoordinateReferenceSystem) { + return (CoordinateReferenceSystem) value; + } + } + /* + * Fallback on SRID with the assumption that they are EPSG codes. + */ + final int srid = geometry.getSRID(); + if (srid > 0) { + return CRS.forCode(Constants.EPSG + ':' + srid); + } + } + return null; + } + + /** + * Transform 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. + * + * @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. + * @throws TransformException if the given geometry has no CRS or can not be transformed. + * @throws FactoryException if transformation to the target CRS can not be constructed. + */ + public static Geometry transform(Geometry geometry, final CoordinateReferenceSystem targetCRS) + throws TransformException, FactoryException + { + if (geometry != null && targetCRS != null) { + final CoordinateReferenceSystem sourceCRS = getCoordinateReferenceSystem(geometry); + if (sourceCRS == null) { + throw new TransformException("Geometry CRS is undefined."); + } + if (!Utilities.equalsIgnoreMetadata(sourceCRS, targetCRS)) { + geometry = transform(geometry, CRS.findOperation(sourceCRS, targetCRS, null)); + } + } + return geometry; + } + + /** + * Transform the given geometry using the given coordinate operation. + * If the geometry or the operation is null, then the geometry is returned unchanged. + * + * @todo Handle antimeridian case. + * + * @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. + * @throws TransformException if the given geometry can not be transformed. + */ + public static Geometry transform(Geometry geometry, final CoordinateOperation operation) throws TransformException { + if (geometry != null && operation != null) { + geometry = transform(geometry, operation.getMathTransform()); + geometry.setUserData(operation.getTargetCRS()); + } + return geometry; + } + + /** + * Transform the given geometry using the given math transform. + * If the geometry or the transform is null or identity, then the geometry is returned unchanged. + * + * @param geometry the geometry to transform, or {@code null}. + * @param transform the transform to apply, or {@code null}. + * @return the transformed geometry, or the same geometry if it is already in target CRS. + * @throws TransformException if the given geometry can not be transformed. + */ + public static Geometry transform(Geometry geometry, MathTransform transform) throws TransformException { + if (geometry != null && transform != null) { + final GeometryCoordinateTransform gct = new GeometryCoordinateTransform(transform, geometry.getFactory()); + geometry = gct.transform(geometry); + } + return geometry; + } +} diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/package-info.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/package-info.java new file mode 100644 index 0000000..190a783 --- /dev/null +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/package-info.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +/** + * Methods specific to the Java Topology Suite (JTS). + * + * <STRONG>Do not use!</STRONG> + * + * This package is for internal use by SIS only. Classes in this package + * may change in incompatible ways in any future version without notice. + * + * @author Johann Sorel (Geomatys) + * @version 1.0 + * @since 1.0 + * @module + */ +package org.apache.sis.internal.feature.jts; diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometriesTestCase.java b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometriesTestCase.java index a6bb921..4105b5a 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometriesTestCase.java +++ b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometriesTestCase.java @@ -39,7 +39,7 @@ public abstract strictfp class GeometriesTestCase extends TestCase { /** * The factory to test. */ - final Geometries<?> factory; + private final Geometries<?> factory; /** * The geometry created by the test. Provided for allowing sub-classes to perform additional verifications. diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/JTSTest.java b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/JTSTest.java index 4fedb0f..8347c6b 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/JTSTest.java +++ b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/JTSTest.java @@ -16,17 +16,8 @@ */ package org.apache.sis.internal.feature; -import java.util.Collections; -import org.opengis.util.FactoryException; -import org.opengis.referencing.operation.TransformException; -import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.MultiLineString; -import org.apache.sis.referencing.CommonCRS; -import org.apache.sis.internal.referencing.j2d.AffineTransform2D; import org.junit.Test; import static org.junit.Assert.*; @@ -94,66 +85,4 @@ public final strictfp class JTSTest extends GeometriesTestCase { new Coordinate(15, 11), new Coordinate(13, 10)}, mp.getGeometryN(2).getCoordinates()); } - - /** - * Tests {@link JTS#tryGetCoordinateReferenceSystem(Object)}. - * - * @throws FactoryException if an EPSG code can not be resolved. - */ - @Test - public void testGetCoordinateReferenceSystem() throws FactoryException { - final GeometryFactory gf = new GeometryFactory(); - final Geometry geometry = gf.createPoint(new Coordinate(5, 6)); - - CoordinateReferenceSystem crs = factory.tryGetCoordinateReferenceSystem(geometry); - assertNull(crs); - - // Test CRS as user data. - geometry.setUserData(CommonCRS.ED50.geographic()); - assertEquals(CommonCRS.ED50.geographic(), factory.tryGetCoordinateReferenceSystem(geometry)); - - // Test CRS as map value. - geometry.setUserData(Collections.singletonMap(JTS.CRS_KEY, CommonCRS.NAD83.geographic())); - assertEquals(CommonCRS.NAD83.geographic(), factory.tryGetCoordinateReferenceSystem(geometry)); - - // Test CRS as srid. - geometry.setUserData(null); - geometry.setSRID(4326); - assertEquals(CommonCRS.WGS84.geographic(), factory.tryGetCoordinateReferenceSystem(geometry)); - } - - /** - * Tests {@link JTS#transform(org.locationtech.jts.geom.Geometry, org.opengis.referencing.crs.CoordinateReferenceSystem) }. - * Tests {@link JTS#transform(org.locationtech.jts.geom.Geometry, org.opengis.referencing.operation.CoordinateOperation) }. - * Tests {@link JTS#transform(org.locationtech.jts.geom.Geometry, org.opengis.referencing.operation.MathTransform) }. - */ - @Test - public void testTransform() throws FactoryException, TransformException { - final GeometryFactory gf = new GeometryFactory(); - final Geometry in = gf.createPoint(new Coordinate(5, 6)); - - // test exception when transforming geometry without CRS. - try { - JTS.transform(in, CommonCRS.WGS84.geographic()); - fail("Geometry has no CRS, transform should have failed"); - } catch (TransformException ex) { - //ok - } - - // test axes inversion transform - in.setUserData(CommonCRS.WGS84.normalizedGeographic()); - Geometry out = JTS.transform(in, CommonCRS.WGS84.geographic()); - assertTrue(out instanceof Point); - assertEquals(6.0, ((Point) out).getX(), 0.0); - assertEquals(5.0, ((Point) out).getY(), 0.0); - assertEquals(CommonCRS.WGS84.geographic(), out.getUserData()); - - // test affine transform, user data must be preserved - final AffineTransform2D trs = new AffineTransform2D(1,0,0,1,10,20); - out = JTS.transform(in, trs); - assertTrue(out instanceof Point); - assertEquals(15.0, ((Point) out).getX(), 0.0); - assertEquals(26.0, ((Point) out).getY(), 0.0); - assertEquals(CommonCRS.WGS84.normalizedGeographic(), out.getUserData()); - } } diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/JTSTest.java b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/jts/JTSTest.java similarity index 59% copy from core/sis-feature/src/test/java/org/apache/sis/internal/feature/JTSTest.java copy to core/sis-feature/src/test/java/org/apache/sis/internal/feature/jts/JTSTest.java index 4fedb0f..4959846 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/JTSTest.java +++ b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/jts/JTSTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.sis.internal.feature; +package org.apache.sis.internal.feature.jts; import java.util.Collections; import org.opengis.util.FactoryException; @@ -24,9 +24,9 @@ import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.GeometryFactory; -import org.locationtech.jts.geom.MultiLineString; import org.apache.sis.referencing.CommonCRS; import org.apache.sis.internal.referencing.j2d.AffineTransform2D; +import org.apache.sis.test.TestCase; import org.junit.Test; import static org.junit.Assert.*; @@ -35,68 +35,14 @@ import static org.junit.Assert.*; /** * Tests {@link JTS} implementation. * - * @author Martin Desruisseaux (Geomatys) * @author Johann Sorel (Geomatys) * @version 1.0 * @since 1.0 * @module */ -public final strictfp class JTSTest extends GeometriesTestCase { +public final strictfp class JTSTest extends TestCase { /** - * Creates a new test case. - */ - public JTSTest() { - super(new JTS()); - } - - /** - * Tests {@link JTS#createPolyline(int, Vector...)}. - */ - @Test - @Override - public void testCreatePolyline() { - super.testCreatePolyline(); - final MultiLineString mp = (MultiLineString) geometry; - assertEquals("numGeometries", 2, mp.getNumGeometries()); - verifyTwoFirstGeometries(mp); - } - - /** - * Verifies the coordinates of the two first geometries of the given multi line string. - * If there is more than 2 geometries, it is caller responsibility to verify the other ones. - */ - private static void verifyTwoFirstGeometries(final MultiLineString mp) { - assertArrayEquals(new Coordinate[] { - new Coordinate(4, 5), - new Coordinate(7, 9), - new Coordinate(9, 3), - new Coordinate(4, 5)}, mp.getGeometryN(0).getCoordinates()); - - assertArrayEquals(new Coordinate[] { - new Coordinate(-3, -2), - new Coordinate(-2, -5), - new Coordinate(-1, -6)}, mp.getGeometryN(1).getCoordinates()); - } - - /** - * Tests {@link Geometries#tryMergePolylines(Object, Iterator)}. - */ - @Test - @Override - public void testTryMergePolylines() { - super.testTryMergePolylines(); - final MultiLineString mp = (MultiLineString) geometry; - assertEquals("numGeometries", 3, mp.getNumGeometries()); - verifyTwoFirstGeometries(mp); - assertArrayEquals(new Coordinate[] { - new Coordinate(13, 11), - new Coordinate(14, 12), - new Coordinate(15, 11), - new Coordinate(13, 10)}, mp.getGeometryN(2).getCoordinates()); - } - - /** - * Tests {@link JTS#tryGetCoordinateReferenceSystem(Object)}. + * Tests {@link JTS#getCoordinateReferenceSystem(Geometry)}. * * @throws FactoryException if an EPSG code can not be resolved. */ @@ -105,21 +51,21 @@ public final strictfp class JTSTest extends GeometriesTestCase { final GeometryFactory gf = new GeometryFactory(); final Geometry geometry = gf.createPoint(new Coordinate(5, 6)); - CoordinateReferenceSystem crs = factory.tryGetCoordinateReferenceSystem(geometry); + CoordinateReferenceSystem crs = JTS.getCoordinateReferenceSystem(geometry); assertNull(crs); // Test CRS as user data. geometry.setUserData(CommonCRS.ED50.geographic()); - assertEquals(CommonCRS.ED50.geographic(), factory.tryGetCoordinateReferenceSystem(geometry)); + assertEquals(CommonCRS.ED50.geographic(), JTS.getCoordinateReferenceSystem(geometry)); // Test CRS as map value. geometry.setUserData(Collections.singletonMap(JTS.CRS_KEY, CommonCRS.NAD83.geographic())); - assertEquals(CommonCRS.NAD83.geographic(), factory.tryGetCoordinateReferenceSystem(geometry)); + assertEquals(CommonCRS.NAD83.geographic(), JTS.getCoordinateReferenceSystem(geometry)); // Test CRS as srid. geometry.setUserData(null); geometry.setSRID(4326); - assertEquals(CommonCRS.WGS84.geographic(), factory.tryGetCoordinateReferenceSystem(geometry)); + assertEquals(CommonCRS.WGS84.geographic(), JTS.getCoordinateReferenceSystem(geometry)); } /** @@ -154,6 +100,5 @@ public final strictfp class JTSTest extends GeometriesTestCase { assertTrue(out instanceof Point); assertEquals(15.0, ((Point) out).getX(), 0.0); assertEquals(26.0, ((Point) out).getY(), 0.0); - assertEquals(CommonCRS.WGS84.normalizedGeographic(), out.getUserData()); } } diff --git a/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java b/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java index 3c18e56..f2aa5c8 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java +++ b/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java @@ -55,6 +55,7 @@ import org.junit.BeforeClass; org.apache.sis.internal.feature.Java2DTest.class, org.apache.sis.internal.feature.ESRITest.class, org.apache.sis.internal.feature.JTSTest.class, + org.apache.sis.internal.feature.jts.JTSTest.class, org.apache.sis.feature.builder.CharacteristicTypeBuilderTest.class, org.apache.sis.feature.builder.AttributeTypeBuilderTest.class, org.apache.sis.feature.builder.AssociationRoleBuilderTest.class,
