From 7004fb389cfe57f1b3d6c7e50f457f7851a1abf6 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Fri, 6 Dec 2019 10:52:56 +0100 Subject: [PATCH 1/5] Create a branch for a future version based on GeoAPI 4. --- example/README.md | 2 +- pom.xml | 23 ++- src/main/cpp/CMakeLists.txt | 2 +- src/main/cpp/org_kortforsyningen_proj_Type.h | 6 + .../proj/AuthorityFactory.java | 38 +++- .../java/org/kortforsyningen/proj/Axis.java | 27 +-- .../org/kortforsyningen/proj/CompoundCS.java | 52 +----- .../proj/IdentifiableObject.java | 8 +- .../kortforsyningen/proj/ObjectFactory.java | 58 +++++- .../proj/ObjectIdentifier.java | 9 +- .../org/kortforsyningen/proj/Operation.java | 17 +- .../proj/OperationFactory.java | 34 +++- .../org/kortforsyningen/proj/Parameter.java | 14 +- .../kortforsyningen/proj/SimpleCitation.java | 135 +------------- .../kortforsyningen/proj/SimpleExtent.java | 35 +--- .../java/org/kortforsyningen/proj/Type.java | 7 +- .../kortforsyningen/proj/UnitOfMeasure.java | 4 +- .../java/org/kortforsyningen/proj/Units.java | 16 +- .../kortforsyningen/proj/package-info.java | 2 +- .../proj/spi/CRSAuthorityFactoryProvider.java | 8 +- .../proj/spi/OperationFactoryProvider.java | 13 +- .../proj/spi/package-info.java | 2 +- .../proj/AuthorityFactoryTest.java | 8 +- .../proj/ObjectFactoryTest.java | 11 +- .../kortforsyningen/proj/UnitProvider.java | 168 ++++++++++++++++++ .../javax.measure.spi.ServiceProvider | 2 + 26 files changed, 401 insertions(+), 300 deletions(-) create mode 100644 src/test/java/org/kortforsyningen/proj/UnitProvider.java create mode 100644 src/test/resources/META-INF/services/javax.measure.spi.ServiceProvider diff --git a/example/README.md b/example/README.md index fdf480f..dd659de 100644 --- a/example/README.md +++ b/example/README.md @@ -4,5 +4,5 @@ on-the-fly by the `java` command. ``` mvn install -java --class-path target/proj-1.0-SNAPSHOT.jar example/TransformPoints.java +java --class-path target/proj-2.0-SNAPSHOT.jar example/TransformPoints.java ``` diff --git a/pom.xml b/pom.xml index b36767d..a250e3a 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ org.kortforsyningen proj - 1.0-SNAPSHOT + 2.0-SNAPSHOT PROJ bindings https://github.com/Kortforsyningen/PROJ-JNI @@ -73,12 +73,12 @@ org.opengis geoapi - 3.0.1 + 4.0-M12 org.opengis geoapi-conformance - 3.0.1 + 4.0-M12 test @@ -211,4 +211,21 @@ + + + + + + geotk + Geotk repository + http://maven.geotoolkit.org + + false + + + diff --git a/src/main/cpp/CMakeLists.txt b/src/main/cpp/CMakeLists.txt index 9327aab..e9c2aaa 100644 --- a/src/main/cpp/CMakeLists.txt +++ b/src/main/cpp/CMakeLists.txt @@ -51,7 +51,7 @@ cmake_minimum_required(VERSION 3.5) # Set the project name and version. -project(PROJ-JNI VERSION 1.0 LANGUAGES CXX) +project(PROJ-JNI VERSION 2.0 LANGUAGES CXX) # Specify the C++ standard. set(CMAKE_CXX_STANDARD 11) diff --git a/src/main/cpp/org_kortforsyningen_proj_Type.h b/src/main/cpp/org_kortforsyningen_proj_Type.h index 7d25729..232a807 100644 --- a/src/main/cpp/org_kortforsyningen_proj_Type.h +++ b/src/main/cpp/org_kortforsyningen_proj_Type.h @@ -69,6 +69,12 @@ extern "C" { #define org_kortforsyningen_proj_Type_TRANSFORMATION 29L #undef org_kortforsyningen_proj_Type_PARAMETER #define org_kortforsyningen_proj_Type_PARAMETER 30L +#undef org_kortforsyningen_proj_Type_PARAMETRIC_CS +#define org_kortforsyningen_proj_Type_PARAMETRIC_CS 31L +#undef org_kortforsyningen_proj_Type_PARAMETRIC_CRS +#define org_kortforsyningen_proj_Type_PARAMETRIC_CRS 32L +#undef org_kortforsyningen_proj_Type_PARAMETRIC_DATUM +#define org_kortforsyningen_proj_Type_PARAMETRIC_DATUM 33L #ifdef __cplusplus } #endif diff --git a/src/main/java/org/kortforsyningen/proj/AuthorityFactory.java b/src/main/java/org/kortforsyningen/proj/AuthorityFactory.java index 9cd3dde..e25a617 100644 --- a/src/main/java/org/kortforsyningen/proj/AuthorityFactory.java +++ b/src/main/java/org/kortforsyningen/proj/AuthorityFactory.java @@ -47,7 +47,7 @@ * same thread.

* * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ final class AuthorityFactory extends NativeResource { @@ -359,6 +359,18 @@ public TimeCS createTimeCS(final String code) throws FactoryException { return createGeodeticObject(CS.Time.class, Type.TEMPORAL_CS, code); } + /** + * Returns a coordinate system which is expected to be parametric. + * + * @param code value allocated by authority. + * @return the coordinate system for the given code. + * @throws FactoryException if the object creation failed or the CS is another type. + */ + @Override + public ParametricCS createParametricCS(final String code) throws FactoryException { + throw new FactoryException(UNSUPPORTED); + } + /** * Returns a coordinate system which is expected to be polar. * PROJ does not yet support this type of coordinate system. @@ -457,6 +469,18 @@ public TemporalDatum createTemporalDatum(final String code) throws FactoryExcept return createGeodeticObject(Datum.Temporal.class, Type.TEMPORAL_DATUM, code); } + /** + * Returns a datum for parametric CRS. + * + * @param code value allocated by authority. + * @return the datum for the given code. + * @throws FactoryException if the object creation failed or the datum is another type. + */ + @Override + public ParametricDatum createParametricDatum(final String code) throws FactoryException { + throw new FactoryException(UNSUPPORTED); + } + /** * Returns a datum for engineering CRS. * @@ -553,6 +577,18 @@ public TemporalCRS createTemporalCRS(final String code) throws FactoryException return createGeodeticObject(CRS.Temporal.class, Type.TEMPORAL_CRS, code); } + /** + * Returns a coordinate reference system which is expected to be parametric. + * + * @param code value allocated by authority. + * @return the CRS for the given code. + * @throws FactoryException if the object creation failed or the CRS is another type. + */ + @Override + public ParametricCRS createParametricCRS(final String code) throws FactoryException { + throw new FactoryException(UNSUPPORTED); + } + /** * Returns a coordinate reference system which is expected to be engineering. * diff --git a/src/main/java/org/kortforsyningen/proj/Axis.java b/src/main/java/org/kortforsyningen/proj/Axis.java index f428549..0735b30 100644 --- a/src/main/java/org/kortforsyningen/proj/Axis.java +++ b/src/main/java/org/kortforsyningen/proj/Axis.java @@ -25,14 +25,13 @@ import org.opengis.util.CodeList; import org.opengis.referencing.cs.CoordinateSystemAxis; import org.opengis.referencing.cs.AxisDirection; -import org.opengis.referencing.cs.RangeMeaning; /** * Wrappers around {@code osgeo::proj::cs::CoordinateSystemAxis}. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ final class Axis extends IdentifiableObject implements CoordinateSystemAxis { @@ -79,16 +78,9 @@ public AxisDirection getDirection() { * @return the code list for the given UML identifier. */ private static > T search(final Class type, final String code) { - return CodeList.valueOf(type, new CodeList.Filter() { - @Override public String codename() { - return code; - } - - @Override public boolean accept(final CodeList candidate) { - return code.equalsIgnoreCase(candidate.identifier()) || - code.equalsIgnoreCase(candidate.name()); - } - }); + return CodeList.valueOf(type, (candidate) -> + code.equalsIgnoreCase(candidate.identifier()) || + code.equalsIgnoreCase(candidate.name()), code); } /** @@ -124,15 +116,4 @@ public double getMaximumValue() { final double v = impl.getNumericProperty(Property.MAXIMUM); return Double.isNaN(v) ? Double.POSITIVE_INFINITY : v; } - - /** - * Returns the meaning of axis value range specified by the {@linkplain #getMinimumValue() - * minimum} and {@linkplain #getMaximumValue() maximum} values. - * - * @return the range meaning, or {@code null} in none. - */ - @Override - public RangeMeaning getRangeMeaning() { - return null; - } } diff --git a/src/main/java/org/kortforsyningen/proj/CompoundCS.java b/src/main/java/org/kortforsyningen/proj/CompoundCS.java index d3918b2..86d9099 100644 --- a/src/main/java/org/kortforsyningen/proj/CompoundCS.java +++ b/src/main/java/org/kortforsyningen/proj/CompoundCS.java @@ -21,14 +21,9 @@ */ package org.kortforsyningen.proj; -import java.util.Collection; -import java.util.Collections; -import java.util.Set; -import org.opengis.referencing.ReferenceIdentifier; +import org.opengis.metadata.Identifier; import org.opengis.referencing.cs.CoordinateSystem; import org.opengis.referencing.cs.CoordinateSystemAxis; -import org.opengis.util.GenericName; -import org.opengis.util.InternationalString; /** @@ -37,7 +32,7 @@ * but GeoAPI does for user convenience. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ public class CompoundCS implements CoordinateSystem { @@ -62,51 +57,10 @@ public class CompoundCS implements CoordinateSystem { * @return null. */ @Override - public ReferenceIdentifier getName() { + public Identifier getName() { return null; } - /** - * Returns an empty set since this coordinate system has no name. - * - * @return empty. - */ - @Override - public Collection getAlias() { - return Collections.emptySet(); - } - - /** - * Returns an empty set since this coordinate system has no identifier. - * - * @return empty. - */ - @Override - public Set getIdentifiers() { - return Collections.emptySet(); - } - - /** - * Returns {@code null} since this coordinate system has no remarks. - * - * @return null. - */ - @Override - public InternationalString getRemarks() { - return null; - } - - /** - * Always throws an exception since this coordinate system can not be formatted in WKT. - * - * @return never return - * @throws UnsupportedOperationException always thrown. - */ - @Override - public String toWKT() { - throw new UnsupportedOperationException(); - } - /** * Returns the number of dimensions in this coordinate system. * diff --git a/src/main/java/org/kortforsyningen/proj/IdentifiableObject.java b/src/main/java/org/kortforsyningen/proj/IdentifiableObject.java index 8235c3b..bf71864 100644 --- a/src/main/java/org/kortforsyningen/proj/IdentifiableObject.java +++ b/src/main/java/org/kortforsyningen/proj/IdentifiableObject.java @@ -37,8 +37,8 @@ import javax.measure.Quantity; import org.opengis.util.GenericName; import org.opengis.util.InternationalString; -import org.opengis.referencing.ReferenceIdentifier; import org.opengis.metadata.extent.Extent; +import org.opengis.metadata.Identifier; /** @@ -50,7 +50,7 @@ * from EPSG codes. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ abstract class IdentifiableObject implements Formattable { @@ -129,7 +129,7 @@ String getNameString(final boolean alternate) { * * @return the primary name, or {@code null} if this object does not provide a name. */ - public ReferenceIdentifier getName() { + public Identifier getName() { return ((ObjectIdentifier) impl.getObjectProperty(Property.NAME)).new PrimaryName(this); } @@ -147,7 +147,7 @@ public Collection getAlias() { * * @return this object identifiers, or an empty collection if there is none. */ - public Set getIdentifiers() { + public Set getIdentifiers() { return new PropertySet<>(ObjectIdentifier.class, Property.IDENTIFIER); } diff --git a/src/main/java/org/kortforsyningen/proj/ObjectFactory.java b/src/main/java/org/kortforsyningen/proj/ObjectFactory.java index 2787921..ce93724 100644 --- a/src/main/java/org/kortforsyningen/proj/ObjectFactory.java +++ b/src/main/java/org/kortforsyningen/proj/ObjectFactory.java @@ -32,7 +32,6 @@ import org.opengis.metadata.Identifier; import org.opengis.metadata.citation.Citation; import org.opengis.referencing.IdentifiedObject; -import org.opengis.referencing.ReferenceIdentifier; import org.opengis.referencing.operation.Conversion; import org.opengis.referencing.operation.CoordinateOperationFactory; import org.opengis.referencing.datum.*; @@ -44,7 +43,7 @@ * Creates geodetic objects from their components. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 * @module */ @@ -167,9 +166,9 @@ private static String[] flat(final Map properties) { if (value == null) { continue; } - if (i == IDENTIFIER && id instanceof ReferenceIdentifier) { + if (i == IDENTIFIER) { if (array == null) array = new String[CODESPACE + 1]; - array[CODESPACE] = ((ReferenceIdentifier) id).getCodeSpace(); + array[CODESPACE] = id.getCodeSpace(); } } else if (value instanceof Date) { value = ((Date) value).toInstant(); // ISO 8601 representation. @@ -499,6 +498,23 @@ public TimeCS createTimeCS( components(axis), null, null, 0, Type.TEMPORAL_CS); } + /** + * Creates a parametric coordinate system. + * + * @param properties name and other properties to give to the new object. + * @param axis the axis. + * @return the coordinate system for the given properties and axes. + * @throws FactoryException if the object creation failed. + */ + @Override + public ParametricCS createParametricCS( + final Map properties, + final CoordinateSystemAxis axis) throws FactoryException + { + return (ParametricCS) create(flat(properties), + components(axis), null, null, 0, Type.PARAMETRIC_CS); + } + /** * Creates a linear coordinate system. * @@ -606,6 +622,21 @@ public TemporalDatum createTemporalDatum( null, new String[] {origin.toInstant().toString()}, null, 0, Type.TEMPORAL_DATUM); } + /** + * Creates a parametric datum from an enumerated type value. + * + * @param properties name and other properties to give to the new object. + * @return the datum for the given properties. + * @throws FactoryException if the object creation failed. + */ + @Override + public ParametricDatum createParametricDatum( + final Map properties) throws FactoryException + { + return (ParametricDatum) create(flat(properties), + null, null, null, 0, Type.PARAMETRIC_DATUM); + } + /** * Creates an engineering datum. * @@ -730,6 +761,25 @@ public TemporalCRS createTemporalCRS( components(datum, cs), null, null, 0, Type.TEMPORAL_CRS); } + /** + * Creates a parametric coordinate reference system. + * + * @param properties name and other properties to give to the new object. + * @param datum parametric datum to use in created CRS. + * @param cs the parametric coordinate system for the created CRS. + * @return the coordinate reference system for the given properties. + * @throws FactoryException if the object creation failed. + */ + @Override + public ParametricCRS createParametricCRS( + final Map properties, + final ParametricDatum datum, + final ParametricCS cs) throws FactoryException + { + return (ParametricCRS) create(flat(properties), + components(datum, cs), null, null, 0, Type.PARAMETRIC_CRS); + } + /** * Creates a engineering coordinate reference system. * diff --git a/src/main/java/org/kortforsyningen/proj/ObjectIdentifier.java b/src/main/java/org/kortforsyningen/proj/ObjectIdentifier.java index 1fc19a1..3c05fc9 100644 --- a/src/main/java/org/kortforsyningen/proj/ObjectIdentifier.java +++ b/src/main/java/org/kortforsyningen/proj/ObjectIdentifier.java @@ -24,7 +24,6 @@ import java.util.StringJoiner; import org.opengis.metadata.Identifier; import org.opengis.metadata.citation.Citation; -import org.opengis.referencing.ReferenceIdentifier; /** @@ -32,11 +31,11 @@ * around an {@code osgeo::proj::metadata::Identifier}. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 * @module */ -final class ObjectIdentifier extends IdentifiableObject implements ReferenceIdentifier { +final class ObjectIdentifier extends IdentifiableObject implements Identifier { /** * Creates a new wrapper for the given {@code osgeo::proj::metadata::Identifier}. * @@ -117,7 +116,7 @@ public String getVersion() { * The identifier code should be mandatory, but PROJ does not always provide it. * This class is a workaround for the case where the code is missing. */ - final class PrimaryName implements ReferenceIdentifier { + final class PrimaryName implements Identifier { /** * The object from which to fetch {@link Property#NAME_STRING} if needed. */ @@ -211,7 +210,7 @@ public String toString() { * @param id the identifier for which to get string representation. * @return a pseudo-WKT for the given identifier. */ - private static String format(final ReferenceIdentifier id) { + private static String format(final Identifier id) { final StringBuilder buffer = new StringBuilder("ID[\""); String t = id.getCodeSpace(); if (t != null) { diff --git a/src/main/java/org/kortforsyningen/proj/Operation.java b/src/main/java/org/kortforsyningen/proj/Operation.java index c9851eb..e93d76a 100644 --- a/src/main/java/org/kortforsyningen/proj/Operation.java +++ b/src/main/java/org/kortforsyningen/proj/Operation.java @@ -31,6 +31,7 @@ import java.security.PrivilegedAction; import org.opengis.util.GenericName; import org.opengis.util.InternationalString; +import org.opengis.metadata.Identifier; import org.opengis.geometry.DirectPosition; import org.opengis.geometry.MismatchedDimensionException; import org.opengis.metadata.citation.Citation; @@ -38,7 +39,8 @@ import org.opengis.metadata.quality.PositionalAccuracy; import org.opengis.parameter.ParameterDescriptorGroup; import org.opengis.parameter.ParameterValueGroup; -import org.opengis.referencing.ReferenceIdentifier; +import org.opengis.referencing.crs.GeographicCRS; +import org.opengis.referencing.crs.ProjectedCRS; import org.opengis.referencing.crs.GeneralDerivedCRS; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.CoordinateOperation; @@ -55,7 +57,7 @@ * Each subtype is represented by an inner class in this file. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ class Operation extends ParameterGroup implements CoordinateOperation, MathTransform { @@ -314,9 +316,6 @@ static final class Method extends ParameterGroup implements OperationMethod, Par super(ptr); } - /** Removed from ISO 19111:2019. */ @Override public Integer getSourceDimensions() {return null;} - /** Removed from ISO 19111:2019. */ @Override public Integer getTargetDimensions() {return null;} - /** * The property to request for getting parameter descriptors. * This is the value of the fist argument to be given to @@ -432,9 +431,9 @@ static final class Projection implements org.opengis.referencing.operation.Proje this.op = op; } - @Override public ReferenceIdentifier getName() {return op.getName();} + @Override public Identifier getName() {return op.getName();} @Override public Collection getAlias() {return op.getAlias();} - @Override public Set getIdentifiers() {return op.getIdentifiers();} + @Override public Set getIdentifiers() {return op.getIdentifiers();} @Override public InternationalString getRemarks() {return op.getRemarks();} @Override public String getOperationVersion() {return op.getOperationVersion();} @Override public OperationMethod getMethod() {return op.getMethod();} @@ -445,8 +444,8 @@ static final class Projection implements org.opengis.referencing.operation.Proje @Override public MathTransform getMathTransform() {return op.getMathTransform();} @Override public String toWKT() {return op.toWKT();} @Override public String toString() {return op.toString();} - @Override public CoordinateReferenceSystem getTargetCRS() {return crs;} - @Override public CoordinateReferenceSystem getSourceCRS() {return crs.getBaseCRS();} + @Override public ProjectedCRS getTargetCRS() {return crs;} + @Override public GeographicCRS getSourceCRS() {return crs.getBaseCRS();} @Override public int hashCode() {return crs.hashCode() ^ 37;} @Override public boolean equals(final Object other) { // Since the conversion was obtained from the CRS, comparing the CRS is sufficient. diff --git a/src/main/java/org/kortforsyningen/proj/OperationFactory.java b/src/main/java/org/kortforsyningen/proj/OperationFactory.java index 53a4f7e..ce70924 100644 --- a/src/main/java/org/kortforsyningen/proj/OperationFactory.java +++ b/src/main/java/org/kortforsyningen/proj/OperationFactory.java @@ -28,6 +28,7 @@ import org.opengis.metadata.extent.GeographicExtent; import org.opengis.metadata.extent.GeographicBoundingBox; import org.opengis.parameter.ParameterValueGroup; +import org.opengis.parameter.ParameterDescriptorGroup; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.Conversion; import org.opengis.referencing.operation.CoordinateOperation; @@ -41,7 +42,7 @@ * Creates coordinate operations from a pair of CRS, optionally with some contextual information. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ final class OperationFactory implements CoordinateOperationFactory { @@ -229,4 +230,35 @@ public Conversion createDefiningConversion(final Map properties, { throw new FactoryException("Not supported yet."); } + + /** + * Creates an operation method from a set of properties and a descriptor group. + * + * @param properties set of properties. Shall contains at least {@code "name"}. + * @param sourceDimension number of dimensions in the source CRS of the operation method, or {@code null}. + * @param targetDimension number of dimensions in the target CRS of the operation method, or {@code null}. + * @param parameters a description of the parameters for the operation method. + * @return the operation method. + * @throws FactoryException if the object creation failed. + * + * @since 2.0 + */ + @Override + public OperationMethod createOperationMethod(Map properties, + Integer sourceDimension, + Integer targetDimension, + ParameterDescriptorGroup parameters) throws FactoryException + { + throw new UnsupportedOperationException("Not supported yet."); + } + + /** + * Returns the build-in operation method of the given name. + * + * @since 2.0 + */ + @Override + public OperationMethod getOperationMethod(String name) throws FactoryException { + throw new UnsupportedOperationException("Not supported yet."); + } } diff --git a/src/main/java/org/kortforsyningen/proj/Parameter.java b/src/main/java/org/kortforsyningen/proj/Parameter.java index 440ef45..949b597 100644 --- a/src/main/java/org/kortforsyningen/proj/Parameter.java +++ b/src/main/java/org/kortforsyningen/proj/Parameter.java @@ -23,10 +23,9 @@ import java.io.File; import java.net.URI; -import java.util.Set; import javax.measure.Unit; import javax.measure.IncommensurableException; -import org.opengis.referencing.ReferenceIdentifier; +import org.opengis.metadata.Identifier; import org.opengis.parameter.InvalidParameterTypeException; import org.opengis.parameter.ParameterDescriptor; import org.opengis.parameter.ParameterValue; @@ -44,7 +43,7 @@ * is known only in native code.

* * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ @SuppressWarnings("rawtypes") @@ -70,13 +69,6 @@ public ParameterDescriptor getDescriptor() { return this; } - @Override public int getMinimumOccurs() {return 1;} - @Override public int getMaximumOccurs() {return 1;} - @Override public Set getValidValues() {return null;} - @Override public Comparable getMinimumValue() {return null;} - @Override public Comparable getMaximumValue() {return null;} - @Override public Object getDefaultValue() {return null;} - /** * Returns the type of this parameter. * @@ -283,7 +275,7 @@ public String toString() { final StringBuilder buffer = new StringBuilder("PARAMETER[\""); String name = getNameString(false); if (name == null) { - for (final ReferenceIdentifier id : getIdentifiers()) { + for (final Identifier id : getIdentifiers()) { name = id.getCode(); if (name != null) { final String cs = id.getCodeSpace(); diff --git a/src/main/java/org/kortforsyningen/proj/SimpleCitation.java b/src/main/java/org/kortforsyningen/proj/SimpleCitation.java index e33f8b5..8db6f1e 100644 --- a/src/main/java/org/kortforsyningen/proj/SimpleCitation.java +++ b/src/main/java/org/kortforsyningen/proj/SimpleCitation.java @@ -21,18 +21,10 @@ */ package org.kortforsyningen.proj; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; import java.util.Locale; import java.util.Objects; import org.opengis.util.InternationalString; -import org.opengis.metadata.Identifier; import org.opengis.metadata.citation.Citation; -import org.opengis.metadata.citation.CitationDate; -import org.opengis.metadata.citation.PresentationForm; -import org.opengis.metadata.citation.ResponsibleParty; -import org.opengis.metadata.citation.Series; /** @@ -44,7 +36,7 @@ * about the value represented by the citation or the international string.

* * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 * @module */ @@ -166,131 +158,6 @@ public InternationalString getTitle() { return this; } - /** - * Short names or other language names by which the cited information is known. - * This implementation has none. - * - * @return an empty set. - */ - @Override - public Collection getAlternateTitles() { - return Collections.emptySet(); - } - - /** - * Common title with holdings note. This implementation has none. - * - * @return null. - */ - @Override - @Deprecated - public InternationalString getCollectiveTitle() { - return null; - } - - /** - * Reference dates for the cited resource. This implementation has none. - * - * @return an empty set. - */ - @Override - public Collection getDates() { - return Collections.emptySet(); - } - - /** - * Version of the cited resource. - * - * @return default to null. - */ - @Override - public InternationalString getEdition() { - return null; - } - - /** - * Date of the edition. This implementation has none. - * - * @return null. - */ - @Override - public Date getEditionDate() { - return null; - } - - /** - * Unique identifier for the resource. This implementation has none. - * - * @return an empty set. - */ - @Override - public Collection getIdentifiers() { - return Collections.emptySet(); - } - - /** - * Role, name, contact and position information for individuals or organizations - * that are responsible for the resource. This implementation has none. - * - * @return an empty set. - */ - @Override - public Collection getCitedResponsibleParties() { - return Collections.emptySet(); - } - - /** - * Mode in which the resource is represented. - * - * @return default to an empty set. - */ - @Override - public Collection getPresentationForms() { - return Collections.emptySet(); - } - - /** - * Information about the series, or aggregate dataset, of which the dataset is a part. - * This implementation has none. - * - * @return null. - */ - @Override - public Series getSeries() { - return null; - } - - /** - * Other information required to complete the citation that is not recorded elsewhere. - * This implementation has none. - * - * @return null. - */ - @Override - public InternationalString getOtherCitationDetails() { - return null; - } - - /** - * International Standard Book Number. This implementation has none. - * - * @return null. - */ - @Override - public String getISBN() { - return null; - } - - /** - * International Standard Serial Number. This implementation has none. - * - * @return null. - */ - @Override - public String getISSN() { - return null; - } - /** * Compares the {@linkplain #getTitle() title} with the string representation * of the given object for order. diff --git a/src/main/java/org/kortforsyningen/proj/SimpleExtent.java b/src/main/java/org/kortforsyningen/proj/SimpleExtent.java index 70ad024..a92b877 100644 --- a/src/main/java/org/kortforsyningen/proj/SimpleExtent.java +++ b/src/main/java/org/kortforsyningen/proj/SimpleExtent.java @@ -28,9 +28,6 @@ import org.opengis.metadata.extent.Extent; import org.opengis.metadata.extent.GeographicExtent; import org.opengis.metadata.extent.GeographicBoundingBox; -import org.opengis.metadata.extent.TemporalExtent; -import org.opengis.metadata.extent.VerticalExtent; -import org.opengis.util.InternationalString; /** @@ -42,7 +39,7 @@ * The exact datum does not matter since this information is only approximate.

* * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ final class SimpleExtent implements GeographicBoundingBox, Extent, Serializable { @@ -118,16 +115,6 @@ final class SimpleExtent implements GeographicBoundingBox, Extent, Serializable throw new IllegalArgumentException("Illegal " + dim + " range: [" + min + " … " + max + "]."); } - /** - * The spatial and temporal extent for the referring object. - * - * @return the spatial and temporal extent, or {@code null} in none. - */ - @Override - public InternationalString getDescription() { - return null; - } - /** * Returns the western-most coordinate of the limit of the dataset extent. * The value is expressed in longitude in decimal degrees (positive east). @@ -196,26 +183,6 @@ public Collection getGeographicElements() { return Collections.singleton(this); } - /** - * Provides vertical component of the extent of the referring object. - * - * @return the vertical extent, or an empty list if none. - */ - @Override - public Collection getVerticalElements() { - return Collections.emptyList(); - } - - /** - * Provides temporal component of the extent of the referring object. - * - * @return the temporal extent, or an empty list if none. - */ - @Override - public Collection getTemporalElements() { - return Collections.emptyList(); - } - /** * Returns {@code true} if the given floating point values are equal. * diff --git a/src/main/java/org/kortforsyningen/proj/Type.java b/src/main/java/org/kortforsyningen/proj/Type.java index 2c53caa..1e79aa5 100644 --- a/src/main/java/org/kortforsyningen/proj/Type.java +++ b/src/main/java/org/kortforsyningen/proj/Type.java @@ -28,7 +28,7 @@ * Identification of object types. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ final class Type { @@ -73,5 +73,8 @@ private Type() { OPERATION_METHOD = 27, CONVERSION = 28, TRANSFORMATION = 29, - PARAMETER = 30; + PARAMETER = 30, + PARAMETRIC_CS = 31, + PARAMETRIC_CRS = 32, + PARAMETRIC_DATUM = 33; } diff --git a/src/main/java/org/kortforsyningen/proj/UnitOfMeasure.java b/src/main/java/org/kortforsyningen/proj/UnitOfMeasure.java index f7046d5..3573543 100644 --- a/src/main/java/org/kortforsyningen/proj/UnitOfMeasure.java +++ b/src/main/java/org/kortforsyningen/proj/UnitOfMeasure.java @@ -41,7 +41,7 @@ * It is used only as a fallback when no JSR-363 implementation has been found on the classpath. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ final class UnitOfMeasure> implements Unit { @@ -101,7 +101,7 @@ private UnitOfMeasure(final int type, final String name, final double toSI) { * @param type the type of quantity represented by the unit of measurement. * @param toSI the conversion factory to system unit (provided by PROJ). */ - private UnitOfMeasure(final Class type, final double toSI) { + UnitOfMeasure(final Class type, final double toSI) { this.type = type; this.name = null; this.toSI = toSI; diff --git a/src/main/java/org/kortforsyningen/proj/Units.java b/src/main/java/org/kortforsyningen/proj/Units.java index 173953c..24395e3 100644 --- a/src/main/java/org/kortforsyningen/proj/Units.java +++ b/src/main/java/org/kortforsyningen/proj/Units.java @@ -21,6 +21,7 @@ */ package org.kortforsyningen.proj; +import java.util.Set; import java.util.Objects; import javax.measure.Unit; import javax.measure.Quantity; @@ -62,13 +63,17 @@ public final class Units { SystemOfUnits system = null; try { final SystemOfUnitsService service = ServiceProvider.current().getSystemOfUnitsService(); - if (service != null) { + // Exclude our own UnitProvider class (defined in test package). + if (service != null && !service.getClass().getPackageName().equals(Units.class.getPackageName())) { system = service.getSystemOfUnits("SI"); if (system == null) { system = service.getSystemOfUnits(); } } } catch (IllegalStateException e) { + // Ignore: logging message below. + } + if (system == null) { /* * The call to NativeResource.logger() is necessary - do not replace by * System.getLogger(NativeResource.LOGGER_NAME). The code below has the @@ -199,6 +204,15 @@ private static > Unit create(final Class type, final private Units() { } + /** + * Returns all predefined units. + * + * @return all predefined units. + */ + static Set> predefined() { + return Set.of(PREDEFINED); + } + /** * Returns a unit of measurement for this given {@link UnitOfMeasure} constant. * This method is invoked by {@link UnitType#getPredefinedUnit(double)} for diff --git a/src/main/java/org/kortforsyningen/proj/package-info.java b/src/main/java/org/kortforsyningen/proj/package-info.java index 1ab48aa..0165ee0 100644 --- a/src/main/java/org/kortforsyningen/proj/package-info.java +++ b/src/main/java/org/kortforsyningen/proj/package-info.java @@ -128,7 +128,7 @@ * * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ package org.kortforsyningen.proj; diff --git a/src/main/java/org/kortforsyningen/proj/spi/CRSAuthorityFactoryProvider.java b/src/main/java/org/kortforsyningen/proj/spi/CRSAuthorityFactoryProvider.java index 010f17b..f881335 100644 --- a/src/main/java/org/kortforsyningen/proj/spi/CRSAuthorityFactoryProvider.java +++ b/src/main/java/org/kortforsyningen/proj/spi/CRSAuthorityFactoryProvider.java @@ -33,6 +33,7 @@ import org.opengis.referencing.crs.GeocentricCRS; import org.opengis.referencing.crs.GeographicCRS; import org.opengis.referencing.crs.ImageCRS; +import org.opengis.referencing.crs.ParametricCRS; import org.opengis.referencing.crs.ProjectedCRS; import org.opengis.referencing.crs.TemporalCRS; import org.opengis.referencing.crs.VerticalCRS; @@ -47,7 +48,7 @@ * should be sufficient. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 * * @see Issue #15 @@ -141,4 +142,9 @@ public TemporalCRS createTemporalCRS(String code) throws FactoryException { public VerticalCRS createVerticalCRS(String code) throws FactoryException { return impl.createVerticalCRS(code); } + + @Override + public ParametricCRS createParametricCRS(String code) throws FactoryException { + return impl.createParametricCRS(code); + } } diff --git a/src/main/java/org/kortforsyningen/proj/spi/OperationFactoryProvider.java b/src/main/java/org/kortforsyningen/proj/spi/OperationFactoryProvider.java index fbda348..c5017cc 100644 --- a/src/main/java/org/kortforsyningen/proj/spi/OperationFactoryProvider.java +++ b/src/main/java/org/kortforsyningen/proj/spi/OperationFactoryProvider.java @@ -25,6 +25,7 @@ import org.kortforsyningen.proj.Proj; import org.opengis.metadata.citation.Citation; import org.opengis.parameter.ParameterValueGroup; +import org.opengis.parameter.ParameterDescriptorGroup; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.Conversion; import org.opengis.referencing.operation.CoordinateOperation; @@ -39,7 +40,7 @@ * in which case the public static {@code provider()} method should be sufficient. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 * * @see Issue #15 @@ -81,4 +82,14 @@ public CoordinateOperation createConcatenatedOperation(Map map, Coord public Conversion createDefiningConversion(Map map, OperationMethod om, ParameterValueGroup pvg) throws FactoryException { return impl.createDefiningConversion(map, om, pvg); } + + @Override + public OperationMethod createOperationMethod(Map map, Integer intgr, Integer intgr1, ParameterDescriptorGroup pdg) throws FactoryException { + return impl.createOperationMethod(map, intgr, intgr1, pdg); + } + + @Override + public OperationMethod getOperationMethod(String code) throws FactoryException { + return impl.getOperationMethod(code); + } } diff --git a/src/main/java/org/kortforsyningen/proj/spi/package-info.java b/src/main/java/org/kortforsyningen/proj/spi/package-info.java index 48d36f6..a339737 100644 --- a/src/main/java/org/kortforsyningen/proj/spi/package-info.java +++ b/src/main/java/org/kortforsyningen/proj/spi/package-info.java @@ -33,7 +33,7 @@ * While the classes in this packages are public, they usually don't need to be used directly. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ package org.kortforsyningen.proj.spi; diff --git a/src/test/java/org/kortforsyningen/proj/AuthorityFactoryTest.java b/src/test/java/org/kortforsyningen/proj/AuthorityFactoryTest.java index 7553514..322a727 100644 --- a/src/test/java/org/kortforsyningen/proj/AuthorityFactoryTest.java +++ b/src/test/java/org/kortforsyningen/proj/AuthorityFactoryTest.java @@ -24,7 +24,7 @@ import java.util.List; import org.opengis.util.FactoryException; import org.opengis.util.InternationalString; -import org.opengis.referencing.ReferenceIdentifier; +import org.opengis.metadata.Identifier; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.crs.GeographicCRS; @@ -50,7 +50,7 @@ * Tests the {@link AuthorityFactory} class. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ public final strictfp class AuthorityFactoryTest { @@ -258,10 +258,10 @@ public void testCache() throws FactoryException { * @param identifiers the collection to verify. */ private static void assertIdentifierEquals(final String codeSpace, final String code, - final Iterable identifiers) + final Iterable identifiers) { boolean found = false; - for (final ReferenceIdentifier id : identifiers) { + for (final Identifier id : identifiers) { if (codeSpace.equalsIgnoreCase(id.getCodeSpace())) { assertEquals("code", code, id.getCode()); found = true; diff --git a/src/test/java/org/kortforsyningen/proj/ObjectFactoryTest.java b/src/test/java/org/kortforsyningen/proj/ObjectFactoryTest.java index 8479f92..4980ff9 100644 --- a/src/test/java/org/kortforsyningen/proj/ObjectFactoryTest.java +++ b/src/test/java/org/kortforsyningen/proj/ObjectFactoryTest.java @@ -42,8 +42,7 @@ import org.opengis.referencing.crs.TemporalCRS; import org.opengis.referencing.crs.CompoundCRS; import org.opengis.referencing.crs.CoordinateReferenceSystem; -import org.opengis.referencing.ReferenceIdentifier; -import org.opengis.metadata.citation.Citation; +import org.opengis.metadata.Identifier; import org.junit.Test; import static org.junit.Assert.*; @@ -53,7 +52,7 @@ * Tests {@link ObjectFactory}. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ public final strictfp class ObjectFactoryTest { @@ -157,11 +156,9 @@ public void testCartesianCS() throws FactoryException, IncommensurableException */ @Test public void testEllipsoid() throws FactoryException { - final ReferenceIdentifier id = new ReferenceIdentifier() { + final Identifier id = new Identifier() { @Override public String getCode() {return "My code";} @Override public String getCodeSpace() {return "My codespace";} - @Override public Citation getAuthority() {return null;} - @Override public String getVersion() {return null;} }; semiMajorAxis = 12.1 + 4*StrictMath.random(); Ellipsoid ellipsoid = factory.createEllipsoid( @@ -175,7 +172,7 @@ public void testEllipsoid() throws FactoryException { assertSame ( Units.METRE, ellipsoid.getAxisUnit()); assertFalse (ellipsoid.isIvfDefinitive()); - final ReferenceIdentifier firstID = ellipsoid.getIdentifiers().iterator().next(); + final Identifier firstID = ellipsoid.getIdentifiers().iterator().next(); assertEquals("My code", firstID.getCode()); assertEquals("My codespace", firstID.getCodeSpace()); } diff --git a/src/test/java/org/kortforsyningen/proj/UnitProvider.java b/src/test/java/org/kortforsyningen/proj/UnitProvider.java new file mode 100644 index 0000000..ad9ebce --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/UnitProvider.java @@ -0,0 +1,168 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import java.util.Set; +import java.util.Collection; +import java.util.Collections; +import javax.measure.Unit; +import javax.measure.Dimension; +import javax.measure.Quantity; +import javax.measure.quantity.Time; +import javax.measure.quantity.Angle; +import javax.measure.quantity.Length; +import javax.measure.quantity.Dimensionless; +import javax.measure.quantity.Pressure; +import javax.measure.spi.QuantityFactory; +import javax.measure.spi.ServiceProvider; +import javax.measure.spi.SystemOfUnits; +import javax.measure.spi.SystemOfUnitsService; +import javax.measure.spi.UnitFormatService; + + +/** + * Services provider for units of measurement, for testing purpose only. + * This is required for running GeoAPI tests. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +public final class UnitProvider extends ServiceProvider implements SystemOfUnitsService, SystemOfUnits { + /** + * Creates a new provider of units of measurements. + */ + public UnitProvider() { + } + + /** + * Returns a name for the system of units provided by this class. + * The name shall be different than {@code "SI"} for preventing + * {@link Units} to select this provider. + * + * @return an arbitrary name different than {@code "SI"}. + */ + @Override + public String getName() { + return "Proj fallback"; + } + + /** + * Returns the default unit for the specified quantity or {@code null} if none. + * + * @param the compile-time quantity type. + * @param type the quantity type. + * @return the unit for the specified quantity. + */ + @Override + @SuppressWarnings("unchecked") + public > Unit getUnit(final Class type) { + if (Length .class.equals(type)) return (Unit) Units.METRE; + if (Angle .class.equals(type)) return (Unit) Units.RADIAN; + if (Time .class.equals(type)) return (Unit) Units.SECOND; + if (Dimensionless.class.equals(type)) return (Unit) Units.SCALE_UNITY; + if (Pressure .class.equals(type)) return (Unit) new UnitOfMeasure<>(Pressure.class, 1); + return null; + } + + /** + * Returns the units explicitly defined by this system. + * + * @return all predefined units. + */ + @Override + public Set> getUnits() { + return Units.predefined(); + } + + /** + * Returns the units defined in this system having the specified dimension (convenience method). + * + * @param dim the dimension of the units to be returned. + * @return the units of specified dimension. + */ + @Override + public Set> getUnits(final Dimension dim) { + throw new UnsupportedOperationException(); + } + + /** + * Returns the only system of units services provided by this implementation. + * + * @return {@code this}. + */ + @Override + public SystemOfUnits getSystemOfUnits() { + return this; + } + + /** + * Returns the system of units having the specified name or {@code null} if none. + * + * @param name the system of unit name. + * @return the system of units for the given name. + */ + @Override + public SystemOfUnits getSystemOfUnits(final String name) { + return getName().equals(name) ? this : null; + } + + /** + * Returns the only system of units services provided by this implementation. + * + * @return {@code this} as a singleton. + */ + @Override + public Collection getAvailableSystemsOfUnits() { + return Collections.singleton(this); + } + + /** + * Returns the only system of units services provided by this implementation. + * + * @return {@code this}. + */ + @Override + public SystemOfUnitsService getSystemOfUnitsService() { + return this; + } + + /** + * Unsupported in this implementation. + * + * @return {@code null}. + */ + @Override + public UnitFormatService getUnitFormatService() { + return null; + } + + /** + * Unsupported in this implementation. + * + * @return {@code null}. + */ + @Override + public > QuantityFactory getQuantityFactory(Class type) { + return null; + } +} diff --git a/src/test/resources/META-INF/services/javax.measure.spi.ServiceProvider b/src/test/resources/META-INF/services/javax.measure.spi.ServiceProvider new file mode 100644 index 0000000..94ebb4f --- /dev/null +++ b/src/test/resources/META-INF/services/javax.measure.spi.ServiceProvider @@ -0,0 +1,2 @@ +# For testing purpose only. +org.kortforsyningen.proj.UnitProvider From 580e576312dbf1c58e76658e6a6de7994d28f048 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Fri, 6 Dec 2019 11:26:16 +0100 Subject: [PATCH 2/5] Complete implementation of ParametricCRS (available only in GeoAPI 4.0). --- src/main/cpp/bindings.cpp | 27 +++++++++++++++ .../proj/AuthorityFactory.java | 6 ++-- .../java/org/kortforsyningen/proj/CRS.java | 34 ++++++++++++++++++- .../java/org/kortforsyningen/proj/CS.java | 16 ++++++++- .../java/org/kortforsyningen/proj/Datum.java | 16 ++++++++- .../kortforsyningen/proj/NativeResource.java | 5 ++- .../java/org/kortforsyningen/proj/Type.java | 2 +- 7 files changed, 98 insertions(+), 8 deletions(-) diff --git a/src/main/cpp/bindings.cpp b/src/main/cpp/bindings.cpp index f61324e..b4af448 100644 --- a/src/main/cpp/bindings.cpp +++ b/src/main/cpp/bindings.cpp @@ -68,6 +68,7 @@ using osgeo::proj::crs::EngineeringCRS; using osgeo::proj::crs::GeodeticCRS; using osgeo::proj::crs::GeodeticCRSNNPtr; using osgeo::proj::crs::GeographicCRS; +using osgeo::proj::crs::ParametricCRS; using osgeo::proj::crs::ProjectedCRS; using osgeo::proj::crs::SingleCRS; using osgeo::proj::crs::SingleCRSPtr; @@ -85,6 +86,8 @@ using osgeo::proj::cs::CoordinateSystemNNPtr; using osgeo::proj::cs::CoordinateSystemPtr; using osgeo::proj::cs::EllipsoidalCS; using osgeo::proj::cs::EllipsoidalCSNNPtr; +using osgeo::proj::cs::ParametricCS; +using osgeo::proj::cs::ParametricCSNNPtr; using osgeo::proj::cs::SphericalCS; using osgeo::proj::cs::SphericalCSNNPtr; using osgeo::proj::cs::SphericalCSPtr; @@ -100,6 +103,8 @@ using osgeo::proj::datum::EngineeringDatum; using osgeo::proj::datum::EngineeringDatumNNPtr; using osgeo::proj::datum::GeodeticReferenceFrame; using osgeo::proj::datum::GeodeticReferenceFrameNNPtr; +using osgeo::proj::datum::ParametricDatum; +using osgeo::proj::datum::ParametricDatumNNPtr; using osgeo::proj::datum::PrimeMeridian; using osgeo::proj::datum::PrimeMeridianNNPtr; using osgeo::proj::datum::TemporalDatum; @@ -587,6 +592,7 @@ again: switch (type) { else if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_GEOGRAPHIC_CRS; else if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_VERTICAL_CRS; else if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_TEMPORAL_CRS; + else if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_PARAMETRIC_CRS; else if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_ENGINEERING_CRS; else { GeodeticCRS *gc = dynamic_cast(rp); @@ -605,12 +611,14 @@ again: switch (type) { else if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_ELLIPSOIDAL_CS; else if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_VERTICAL_CS; else if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_TEMPORAL_CS; + else if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_PARAMETRIC_CS; break; } case org_kortforsyningen_proj_Type_DATUM: { if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_GEODETIC_REFERENCE_FRAME; else if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_VERTICAL_REFERENCE_FRAME; else if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_TEMPORAL_DATUM; + else if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_PARAMETRIC_DATUM; else if (dynamic_cast(rp)) type = org_kortforsyningen_proj_Type_ENGINEERING_DATUM; break; } @@ -2033,6 +2041,11 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_ObjectFactory_create object = TemporalMeasureCS::create(propertyMap, axis).as_nullable(); break; } + case org_kortforsyningen_proj_Type_PARAMETRIC_CS: { + CoordinateSystemAxisNNPtr axis = get_component(env, components, 0); + object = ParametricCS::create(propertyMap, axis).as_nullable(); + break; + } case org_kortforsyningen_proj_Type_CARTESIAN_CS: case org_kortforsyningen_proj_Type_SPHERICAL_CS: case org_kortforsyningen_proj_Type_ELLIPSOIDAL_CS: { @@ -2071,6 +2084,11 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_ObjectFactory_create object = TemporalDatum::create(propertyMap, origin, TemporalDatum::CALENDAR_PROLEPTIC_GREGORIAN).as_nullable(); break; } + case org_kortforsyningen_proj_Type_PARAMETRIC_DATUM: { + optional anchor = get_anchor(propertyMap); + object = ParametricDatum::create(propertyMap, anchor).as_nullable(); + break; + } case org_kortforsyningen_proj_Type_ENGINEERING_DATUM: { optional anchor = get_anchor(propertyMap); object = EngineeringDatum::create(propertyMap, anchor).as_nullable(); @@ -2105,6 +2123,12 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_ObjectFactory_create object = TemporalCRS::create(propertyMap, datum, cs).as_nullable(); break; } + case org_kortforsyningen_proj_Type_PARAMETRIC_CRS: { + ParametricDatumNNPtr datum = get_component(env, components, 0); + ParametricCSNNPtr cs = get_component (env, components, 1); + object = ParametricCRS::create(propertyMap, datum, cs).as_nullable(); + break; + } case org_kortforsyningen_proj_Type_ENGINEERING_CRS: { EngineeringDatumNNPtr datum = get_component(env, components, 0); CoordinateSystemNNPtr cs = get_component(env, components, 1); @@ -2275,6 +2299,7 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_AuthorityFactory_createG case org_kortforsyningen_proj_Type_GEODETIC_REFERENCE_FRAME: rp = pf->createGeodeticDatum (code_str).as_nullable(); break; case org_kortforsyningen_proj_Type_VERTICAL_REFERENCE_FRAME: rp = pf->createVerticalDatum (code_str).as_nullable(); break; case org_kortforsyningen_proj_Type_TEMPORAL_DATUM: // No specific function - use generic one. + case org_kortforsyningen_proj_Type_PARAMETRIC_DATUM: // No specific function - use generic one. case org_kortforsyningen_proj_Type_ENGINEERING_DATUM: // No specific function - use generic one. case org_kortforsyningen_proj_Type_DATUM: rp = pf->createDatum (code_str).as_nullable(); break; case org_kortforsyningen_proj_Type_CARTESIAN_CS: // No specific function - use generic one. @@ -2282,6 +2307,7 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_AuthorityFactory_createG case org_kortforsyningen_proj_Type_ELLIPSOIDAL_CS: // No specific function - use generic one. case org_kortforsyningen_proj_Type_VERTICAL_CS: // No specific function - use generic one. case org_kortforsyningen_proj_Type_TEMPORAL_CS: // No specific function - use generic one. + case org_kortforsyningen_proj_Type_PARAMETRIC_CS: // No specific function - use generic one. case org_kortforsyningen_proj_Type_COORDINATE_SYSTEM: rp = pf->createCoordinateSystem (code_str).as_nullable(); break; case org_kortforsyningen_proj_Type_GEOCENTRIC_CRS: // Handled as GeodeticCRS by ISO 19111. case org_kortforsyningen_proj_Type_GEODETIC_CRS: rp = pf->createGeodeticCRS (code_str).as_nullable(); break; @@ -2290,6 +2316,7 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_AuthorityFactory_createG case org_kortforsyningen_proj_Type_PROJECTED_CRS: rp = pf->createProjectedCRS (code_str).as_nullable(); break; case org_kortforsyningen_proj_Type_COMPOUND_CRS: rp = pf->createCompoundCRS (code_str).as_nullable(); break; case org_kortforsyningen_proj_Type_TEMPORAL_CRS: // No specific function - use generic one. + case org_kortforsyningen_proj_Type_PARAMETRIC_CRS: // No specific function - use generic one. case org_kortforsyningen_proj_Type_ENGINEERING_CRS: // No specific function - use generic one. case org_kortforsyningen_proj_Type_COORDINATE_REFERENCE_SYSTEM: rp = pf->createCoordinateReferenceSystem (code_str).as_nullable(); break; case org_kortforsyningen_proj_Type_CONVERSION: rp = pf->createConversion (code_str).as_nullable(); break; diff --git a/src/main/java/org/kortforsyningen/proj/AuthorityFactory.java b/src/main/java/org/kortforsyningen/proj/AuthorityFactory.java index e25a617..0ecf66a 100644 --- a/src/main/java/org/kortforsyningen/proj/AuthorityFactory.java +++ b/src/main/java/org/kortforsyningen/proj/AuthorityFactory.java @@ -368,7 +368,7 @@ public TimeCS createTimeCS(final String code) throws FactoryException { */ @Override public ParametricCS createParametricCS(final String code) throws FactoryException { - throw new FactoryException(UNSUPPORTED); + return createGeodeticObject(CS.Parametric.class, Type.PARAMETRIC_CS, code); } /** @@ -478,7 +478,7 @@ public TemporalDatum createTemporalDatum(final String code) throws FactoryExcept */ @Override public ParametricDatum createParametricDatum(final String code) throws FactoryException { - throw new FactoryException(UNSUPPORTED); + return createGeodeticObject(Datum.Parametric.class, Type.PARAMETRIC_DATUM, code); } /** @@ -586,7 +586,7 @@ public TemporalCRS createTemporalCRS(final String code) throws FactoryException */ @Override public ParametricCRS createParametricCRS(final String code) throws FactoryException { - throw new FactoryException(UNSUPPORTED); + return createGeodeticObject(CRS.Parametric.class, Type.PARAMETRIC_CRS, code); } /** diff --git a/src/main/java/org/kortforsyningen/proj/CRS.java b/src/main/java/org/kortforsyningen/proj/CRS.java index b1b4820..0425a78 100644 --- a/src/main/java/org/kortforsyningen/proj/CRS.java +++ b/src/main/java/org/kortforsyningen/proj/CRS.java @@ -27,10 +27,12 @@ import org.opengis.referencing.cs.EllipsoidalCS; import org.opengis.referencing.cs.TimeCS; import org.opengis.referencing.cs.VerticalCS; +import org.opengis.referencing.cs.ParametricCS; // org.opengis.referencing.datum.Datum — Not imported because we use Datum class from this package. import org.opengis.referencing.datum.GeodeticDatum; import org.opengis.referencing.datum.VerticalDatum; import org.opengis.referencing.datum.TemporalDatum; +import org.opengis.referencing.datum.ParametricDatum; import org.opengis.referencing.datum.EngineeringDatum; import org.opengis.referencing.operation.Projection; import org.opengis.referencing.crs.CoordinateReferenceSystem; @@ -40,6 +42,7 @@ import org.opengis.referencing.crs.ProjectedCRS; import org.opengis.referencing.crs.VerticalCRS; import org.opengis.referencing.crs.TemporalCRS; +import org.opengis.referencing.crs.ParametricCRS; import org.opengis.referencing.crs.EngineeringCRS; import org.opengis.referencing.crs.CompoundCRS; @@ -49,7 +52,7 @@ * Each subtype is represented by an inner class in this file. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ class CRS extends IdentifiableObject implements CoordinateReferenceSystem { @@ -236,6 +239,35 @@ public TemporalDatum getDatum() { } } + /** + * A coordinate reference system specialization. + */ + static final class Parametric extends CRS implements ParametricCRS { + /** + * Invoked by {@link AuthorityFactory#wrapGeodeticObject} only. + * @param ptr pointer to the wrapped PROJ object. + */ + Parametric(final long ptr) { + super(ptr); + } + + /** + * Returns the parametric specialization of the coordinate system. + */ + @Override + public ParametricCS getCoordinateSystem() { + return getCoordinateSystem(CS.Parametric.class); + } + + /** + * Returns the parametric specialization of the datum. + */ + @Override + public ParametricDatum getDatum() { + return getDatum(Datum.Parametric.class); + } + } + /** * A coordinate reference system specialization. */ diff --git a/src/main/java/org/kortforsyningen/proj/CS.java b/src/main/java/org/kortforsyningen/proj/CS.java index 9f88e7d..58dcb29 100644 --- a/src/main/java/org/kortforsyningen/proj/CS.java +++ b/src/main/java/org/kortforsyningen/proj/CS.java @@ -26,6 +26,7 @@ import org.opengis.referencing.cs.CartesianCS; import org.opengis.referencing.cs.SphericalCS; import org.opengis.referencing.cs.EllipsoidalCS; +import org.opengis.referencing.cs.ParametricCS; import org.opengis.referencing.cs.VerticalCS; import org.opengis.referencing.cs.TimeCS; @@ -35,7 +36,7 @@ * Each subtype is represented by an inner class in this file. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ class CS extends IdentifiableObject implements CoordinateSystem { @@ -135,4 +136,17 @@ static final class Time extends CS implements TimeCS { super(ptr); } } + + /** + * A coordinate system specialization. No new properties compared to parent CS. + */ + static final class Parametric extends CS implements ParametricCS { + /** + * Invoked by {@link AuthorityFactory#wrapGeodeticObject} only. + * @param ptr pointer to the wrapped PROJ object. + */ + Parametric(final long ptr) { + super(ptr); + } + } } diff --git a/src/main/java/org/kortforsyningen/proj/Datum.java b/src/main/java/org/kortforsyningen/proj/Datum.java index 9564e24..f75ab84 100644 --- a/src/main/java/org/kortforsyningen/proj/Datum.java +++ b/src/main/java/org/kortforsyningen/proj/Datum.java @@ -34,6 +34,7 @@ import org.opengis.referencing.datum.VerticalDatum; import org.opengis.referencing.datum.VerticalDatumType; import org.opengis.referencing.datum.EngineeringDatum; +import org.opengis.referencing.datum.ParametricDatum; /** @@ -47,7 +48,7 @@ * implementation is offset by the user convenience.

* * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ class Datum extends IdentifiableObject implements org.opengis.referencing.datum.Datum { @@ -192,6 +193,19 @@ public Date getOrigin() { } } + /** + * A datum specialization. No new properties compared to parent CS. + */ + static final class Parametric extends Datum implements ParametricDatum { + /** + * Invoked by {@link AuthorityFactory#wrapGeodeticObject} only. + * @param ptr pointer to the wrapped PROJ object. + */ + Parametric(final long ptr) { + super(ptr); + } + } + /** * A datum specialization. No new properties compared to parent CS. */ diff --git a/src/main/java/org/kortforsyningen/proj/NativeResource.java b/src/main/java/org/kortforsyningen/proj/NativeResource.java index 625d722..dd081f7 100644 --- a/src/main/java/org/kortforsyningen/proj/NativeResource.java +++ b/src/main/java/org/kortforsyningen/proj/NativeResource.java @@ -45,7 +45,7 @@ * by {@link #ptr} when no longer referenced. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 2.0 * @since 1.0 */ abstract class NativeResource { @@ -248,10 +248,12 @@ private IdentifiableObject wrapGeodeticObject(final short type, final long rawPo case Type.ELLIPSOIDAL_CS: obj = new CS.Ellipsoidal (rawPointer); break; case Type.VERTICAL_CS: obj = new CS.Vertical (rawPointer); break; case Type.TEMPORAL_CS: obj = new CS.Time (rawPointer); break; + case Type.PARAMETRIC_CS: obj = new CS.Parametric (rawPointer); break; case Type.DATUM: obj = new Datum (rawPointer); break; case Type.GEODETIC_REFERENCE_FRAME: obj = new Datum.Geodetic (rawPointer); break; case Type.VERTICAL_REFERENCE_FRAME: obj = new Datum.Vertical (rawPointer); break; case Type.TEMPORAL_DATUM: obj = new Datum.Temporal (rawPointer); break; + case Type.PARAMETRIC_DATUM: obj = new Datum.Parametric (rawPointer); break; case Type.ENGINEERING_DATUM: obj = new Datum.Engineering (rawPointer); break; case Type.ELLIPSOID: obj = new Datum.Ellipsoid (rawPointer); break; case Type.PRIME_MERIDIAN: obj = new Datum.PrimeMeridian (rawPointer); break; @@ -262,6 +264,7 @@ private IdentifiableObject wrapGeodeticObject(final short type, final long rawPo case Type.PROJECTED_CRS: obj = new CRS.Projected (rawPointer); break; case Type.VERTICAL_CRS: obj = new CRS.Vertical (rawPointer); break; case Type.TEMPORAL_CRS: obj = new CRS.Temporal (rawPointer); break; + case Type.PARAMETRIC_CRS: obj = new CRS.Parametric (rawPointer); break; case Type.ENGINEERING_CRS: obj = new CRS.Engineering (rawPointer); break; case Type.COMPOUND_CRS: obj = new CRS.Compound (rawPointer); break; case Type.COORDINATE_OPERATION: obj = new Operation (rawPointer); break; diff --git a/src/main/java/org/kortforsyningen/proj/Type.java b/src/main/java/org/kortforsyningen/proj/Type.java index 1e79aa5..64994c0 100644 --- a/src/main/java/org/kortforsyningen/proj/Type.java +++ b/src/main/java/org/kortforsyningen/proj/Type.java @@ -74,7 +74,7 @@ private Type() { CONVERSION = 28, TRANSFORMATION = 29, PARAMETER = 30, - PARAMETRIC_CS = 31, + PARAMETRIC_CS = 31, // From ISO 19111:2019 PARAMETRIC_CRS = 32, PARAMETRIC_DATUM = 33; } From aac33e8344509fe894c1dcad4ce6c696a38b2bac Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Sat, 7 Dec 2019 15:22:38 +0100 Subject: [PATCH 3/5] Apply GIGS tests. Those tests revelead a few bugs which have been fixed in this commit too. Those bugs where: garbage letters in the operation version string, missing anchor description, more effort in the handling of UnitOfMeasurement names, inverse flattening factor of spheres, implementation of Parameter.getValueClass()/getUnit() when the parameter is only a description. https://github.com/Kortforsyningen/PROJ-JNI/issues/17 --- pom.xml | 1 + src/main/cpp/bindings.cpp | 76 ++-- .../cpp/org_kortforsyningen_proj_Property.h | 8 +- src/main/cpp/org_kortforsyningen_proj_Type.h | 8 +- .../java/org/kortforsyningen/proj/Datum.java | 7 +- .../proj/IdentifiableObject.java | 6 +- .../kortforsyningen/proj/NativeResource.java | 1 + .../org/kortforsyningen/proj/Parameter.java | 368 ++++++++++-------- .../kortforsyningen/proj/ParameterType.java | 10 +- .../org/kortforsyningen/proj/Property.java | 7 +- .../kortforsyningen/proj/SharedObjects.java | 2 +- .../kortforsyningen/proj/SimpleExtent.java | 6 +- .../java/org/kortforsyningen/proj/Type.java | 7 +- .../kortforsyningen/proj/UnitOfMeasure.java | 25 +- .../org/kortforsyningen/proj/UnitType.java | 15 +- .../kortforsyningen/proj/GIGS2001Test.java | 59 +++ .../kortforsyningen/proj/GIGS2002Test.java | 48 +++ .../kortforsyningen/proj/GIGS2003Test.java | 48 +++ .../kortforsyningen/proj/GIGS2004Test.java | 60 +++ .../kortforsyningen/proj/GIGS2005Test.java | 47 +++ .../kortforsyningen/proj/GIGS2006Test.java | 71 ++++ .../kortforsyningen/proj/GIGS2007Test.java | 47 +++ .../kortforsyningen/proj/GIGS2008Test.java | 47 +++ .../kortforsyningen/proj/GIGS2009Test.java | 46 +++ .../kortforsyningen/proj/GIGS3002Test.java | 47 +++ .../kortforsyningen/proj/GIGS3003Test.java | 47 +++ .../kortforsyningen/proj/GIGS3004Test.java | 47 +++ .../proj/OperationFactoryTest.java | 2 +- .../kortforsyningen/proj/OperationTest.java | 4 +- .../kortforsyningen/proj/ParameterTest.java | 2 +- .../proj/ReferencingFormatTest.java | 8 +- .../proj/TestFactorySource.java | 68 ++++ .../org/kortforsyningen/proj/UnitsTest.java | 2 +- 33 files changed, 996 insertions(+), 251 deletions(-) create mode 100644 src/test/java/org/kortforsyningen/proj/GIGS2001Test.java create mode 100644 src/test/java/org/kortforsyningen/proj/GIGS2002Test.java create mode 100644 src/test/java/org/kortforsyningen/proj/GIGS2003Test.java create mode 100644 src/test/java/org/kortforsyningen/proj/GIGS2004Test.java create mode 100644 src/test/java/org/kortforsyningen/proj/GIGS2005Test.java create mode 100644 src/test/java/org/kortforsyningen/proj/GIGS2006Test.java create mode 100644 src/test/java/org/kortforsyningen/proj/GIGS2007Test.java create mode 100644 src/test/java/org/kortforsyningen/proj/GIGS2008Test.java create mode 100644 src/test/java/org/kortforsyningen/proj/GIGS2009Test.java create mode 100644 src/test/java/org/kortforsyningen/proj/GIGS3002Test.java create mode 100644 src/test/java/org/kortforsyningen/proj/GIGS3003Test.java create mode 100644 src/test/java/org/kortforsyningen/proj/GIGS3004Test.java create mode 100644 src/test/java/org/kortforsyningen/proj/TestFactorySource.java diff --git a/pom.xml b/pom.xml index a250e3a..600d645 100644 --- a/pom.xml +++ b/pom.xml @@ -119,6 +119,7 @@ ${project.basedir}/src/config/logging.properties -Xcheck:jni + false diff --git a/src/main/cpp/bindings.cpp b/src/main/cpp/bindings.cpp index 789f950..eb1d0ac 100644 --- a/src/main/cpp/bindings.cpp +++ b/src/main/cpp/bindings.cpp @@ -309,6 +309,11 @@ JNIEXPORT jstring JNICALL Java_org_kortforsyningen_proj_NativeResource_version(J */ +/** + * A constant for empty string. + */ +const std::string empty_string = std::string(); + /** * Converts the given C++ string into a Java string if non-empty, or returns null if the string is empty. * This function assumes UTF-8 encoding with no null character and no supplementary Unicode characters. @@ -699,8 +704,9 @@ inline jobject create_unit_fallback(JNIEnv *env, jclass uomClass, const UnitOfMe if (unit) { jmethodID c = env->GetMethodID(uomClass, "", "(ILjava/lang/String;D)V"); if (c) { - jstring name = env->NewStringUTF(unit->name().c_str()); - if (name) { + jstring name = nullptr; + std::string sn = unit->name(); + if (sn.empty() || (name = env->NewStringUTF(sn.c_str()))) { return env->NewObject(uomClass, c, (jint) static_cast(unit->type()), name, (jdouble) unit->conversionToSI()); } @@ -817,7 +823,7 @@ DatabaseContextPtr get_database_context(JNIEnv *env, jobject context) { db = unwrap_shared_ptr(dbPtr); } else { log(env, "Creating PROJ database context."); - db = DatabaseContext::create(std::string(), std::vector(), get_context(env, context)).as_nullable(); + db = DatabaseContext::create(empty_string, std::vector(), get_context(env, context)).as_nullable(); dbPtr = wrap_shared_ptr(db); env->SetLongField(context, fid, dbPtr); // dbPtr may be 0 if out of memory, but the only consequence is that DatabaseContext is not cached. @@ -985,12 +991,14 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_SharedPointer_searchVect { const char *name_utf = env->GetStringUTFChars(name, nullptr); if (name_utf) { + jshort type; try { BaseObjectPtr value; switch (property) { case org_kortforsyningen_proj_Property_METHOD_PARAMETER: { for (GeneralOperationParameterNNPtr param : get_shared_object(env, object)->parameters()) { if (!strcasecmp(name_utf, param->nameStr().c_str())) { + type = org_kortforsyningen_proj_Type_PARAMETER; value = param.as_nullable(); break; } @@ -1001,6 +1009,7 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_SharedPointer_searchVect for (GeneralParameterValueNNPtr param : get_shared_object(env, object)->parameterValues()) { OperationParameterValuePtr single = std::dynamic_pointer_cast(param.as_nullable()); if (single && !strcasecmp(name_utf, single->parameter()->nameStr().c_str())) { + type = org_kortforsyningen_proj_Type_PARAMETER_VALUE; value = single; break; } @@ -1012,7 +1021,7 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_SharedPointer_searchVect } } if (value) { - return specific_subclass(env, object, value, org_kortforsyningen_proj_Type_PARAMETER); + return specific_subclass(env, object, value, type); } } catch (const std::exception &e) { rethrow_as_java_exception(env, JPJ_RUNTIME_EXCEPTION, e); @@ -1056,7 +1065,7 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_SharedPointer_getVectorE } case org_kortforsyningen_proj_Property_OPERATION_PARAMETER: { value = get_shared_object(env, object)->parameterValues().at(index).as_nullable(); - type = org_kortforsyningen_proj_Type_PARAMETER; + type = org_kortforsyningen_proj_Type_PARAMETER_VALUE; break; } case org_kortforsyningen_proj_Property_CRS_COMPONENT: { @@ -1129,8 +1138,8 @@ JNIEXPORT jint JNICALL Java_org_kortforsyningen_proj_SharedPointer_getVectorSize * @param text the optional string to return as a plain string. * @return the plain string, or an empty string if absent. */ -inline std::string string_or_empty(const optional& text) { - return text.has_value() ? *text : std::string(); +inline const std::string& string_or_empty(const optional& text) { + return text.has_value() ? *text : empty_string; } @@ -1140,8 +1149,8 @@ inline std::string string_or_empty(const optional& text) { * @param citation the citation from which to get the title. * @return title of the given citation, or an empty string if absent. */ -inline std::string citation_title(const optional& citation) { - return citation.has_value() ? string_or_empty(citation->title()) : std::string(); +inline const std::string& citation_title(const optional& citation) { + return citation.has_value() ? string_or_empty(citation->title()) : empty_string; } @@ -1439,6 +1448,10 @@ JNIEXPORT jboolean JNICALL Java_org_kortforsyningen_proj_SharedPointer_getBoolea { try { switch (property) { + case org_kortforsyningen_proj_Property_HAS_NAME: { + IdentifiedObjectNNPtr id = get_identified_object(env, object); + return !id->name()->code().empty() || !id->nameStr().empty(); + } case org_kortforsyningen_proj_Property_IS_SPHERE: { return get_shared_object(env, object)->isSphere(); } @@ -1920,7 +1933,7 @@ UnitOfMeasure unit_from_identifier(JNIEnv *env, int code) { UnitOfMeasure::Type type = static_cast((int) values[0]); double scale = values[1]; env->ReleaseDoubleArrayElements(array, values, JNI_ABORT); - return UnitOfMeasure(std::string(), scale, type); + return UnitOfMeasure(empty_string, scale, type); } } } @@ -1967,27 +1980,6 @@ template inline osgeo::proj::util::nn> get_componen } -/** - * A key used for a temporary entry in `PropertyMap`. - */ -static const std::string ANCHOR_POINT_KEY = "anchorPoint"; - -/** - * Returns the value associated to `ANCHOR_POINT_KEY` in the given property map. - * - * @todo As of PROJ 6.2, call to getStringValue causes a JVM crash with the following message: - * "undefined symbol: (snip)PropertyMap14getStringValue(snip)" - * - * @param the map from which to get the anchor point. - * @return the anchor point. - */ -inline optional get_anchor(const PropertyMap& propertyMap) { - optional anchor = optional(); -// propertyMap.getStringValue(ANCHOR_POINT_KEY, anchor); - return anchor; -} - - /** * Creates a geodetic object of the given type. * @@ -2016,6 +2008,7 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_ObjectFactory_create * so it is okay to check only the first letter for 't' value. */ PropertyMap propertyMap = PropertyMap(); + optional anchor = optional(); if (properties) { PropertyMap identifierMap = PropertyMap(); for (int i = env->GetArrayLength(properties); --i >= 0;) { @@ -2025,16 +2018,16 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_ObjectFactory_create if (!utf) return nullptr; // May be an OutOfMemoryError — abort. try { switch (i) { - case org_kortforsyningen_proj_ObjectFactory_NAME: propertyMap.set(IdentifiedObject::NAME_KEY, utf); break; - case org_kortforsyningen_proj_ObjectFactory_ALIAS: propertyMap.set(IdentifiedObject::ALIAS_KEY, utf); break; - case org_kortforsyningen_proj_ObjectFactory_REMARKS: propertyMap.set(IdentifiedObject::REMARKS_KEY, utf); break; - case org_kortforsyningen_proj_ObjectFactory_DEPRECATED: propertyMap.set(IdentifiedObject::DEPRECATED_KEY, *utf == 't'); break; - case org_kortforsyningen_proj_ObjectFactory_ANCHOR_POINT: propertyMap.set( ANCHOR_POINT_KEY, utf); break; - case org_kortforsyningen_proj_ObjectFactory_SCOPE: propertyMap.set(ObjectUsage:: SCOPE_KEY, utf); break; - case org_kortforsyningen_proj_ObjectFactory_CODESPACE: identifierMap.set(Identifier:: CODESPACE_KEY, utf); break; + case org_kortforsyningen_proj_ObjectFactory_NAME: propertyMap.set(IdentifiedObject::NAME_KEY, utf); break; + case org_kortforsyningen_proj_ObjectFactory_ALIAS: propertyMap.set(IdentifiedObject::ALIAS_KEY, utf); break; + case org_kortforsyningen_proj_ObjectFactory_REMARKS: propertyMap.set(IdentifiedObject::REMARKS_KEY, utf); break; + case org_kortforsyningen_proj_ObjectFactory_DEPRECATED: propertyMap.set(IdentifiedObject::DEPRECATED_KEY, *utf == 't'); break; + case org_kortforsyningen_proj_ObjectFactory_SCOPE: propertyMap.set(ObjectUsage:: SCOPE_KEY, utf); break; + case org_kortforsyningen_proj_ObjectFactory_ANCHOR_POINT: anchor = optional(std::string(utf)); break; + case org_kortforsyningen_proj_ObjectFactory_CODESPACE: identifierMap.set(Identifier:: CODESPACE_KEY, utf); break; case org_kortforsyningen_proj_ObjectFactory_IDENTIFIER: { identifierMap.set(Identifier::CODE_KEY, utf); - IdentifierNNPtr id = Identifier::create(std::string(), identifierMap); + IdentifierNNPtr id = Identifier::create(empty_string, identifierMap); propertyMap.set(IdentifiedObject::IDENTIFIERS_KEY, id); break; } @@ -2130,12 +2123,10 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_ObjectFactory_create case org_kortforsyningen_proj_Type_GEODETIC_REFERENCE_FRAME: { EllipsoidNNPtr ellipsoid = get_component (env, components, 0); PrimeMeridianNNPtr primeMeridian = get_component(env, components, 1); - optional anchor = get_anchor(propertyMap); object = GeodeticReferenceFrame::create(propertyMap, ellipsoid, anchor, primeMeridian).as_nullable(); break; } case org_kortforsyningen_proj_Type_VERTICAL_REFERENCE_FRAME: { - optional anchor = get_anchor(propertyMap); object = VerticalReferenceFrame::create(propertyMap, anchor).as_nullable(); break; } @@ -2146,12 +2137,10 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_ObjectFactory_create break; } case org_kortforsyningen_proj_Type_PARAMETRIC_DATUM: { - optional anchor = get_anchor(propertyMap); object = ParametricDatum::create(propertyMap, anchor).as_nullable(); break; } case org_kortforsyningen_proj_Type_ENGINEERING_DATUM: { - optional anchor = get_anchor(propertyMap); object = EngineeringDatum::create(propertyMap, anchor).as_nullable(); break; } @@ -2165,6 +2154,7 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_ObjectFactory_create SphericalCSPtr spherical = std::dynamic_pointer_cast(cs); object = GeodeticCRS::create(propertyMap, datum, NN_CHECK_THROW(spherical)).as_nullable(); } + break; } case org_kortforsyningen_proj_Type_GEOGRAPHIC_CRS: { GeodeticReferenceFrameNNPtr datum = get_component(env, components, 0); diff --git a/src/main/cpp/org_kortforsyningen_proj_Property.h b/src/main/cpp/org_kortforsyningen_proj_Property.h index 5334b39..0e2b679 100644 --- a/src/main/cpp/org_kortforsyningen_proj_Property.h +++ b/src/main/cpp/org_kortforsyningen_proj_Property.h @@ -101,12 +101,14 @@ extern "C" { #define org_kortforsyningen_proj_Property_PARAMETER_TYPE 500L #undef org_kortforsyningen_proj_Property_PARAMETER_INT #define org_kortforsyningen_proj_Property_PARAMETER_INT 501L +#undef org_kortforsyningen_proj_Property_HAS_NAME +#define org_kortforsyningen_proj_Property_HAS_NAME 600L #undef org_kortforsyningen_proj_Property_IS_SPHERE -#define org_kortforsyningen_proj_Property_IS_SPHERE 600L +#define org_kortforsyningen_proj_Property_IS_SPHERE 601L #undef org_kortforsyningen_proj_Property_IVF_DEFINITIVE -#define org_kortforsyningen_proj_Property_IVF_DEFINITIVE 601L +#define org_kortforsyningen_proj_Property_IVF_DEFINITIVE 602L #undef org_kortforsyningen_proj_Property_PARAMETER_BOOL -#define org_kortforsyningen_proj_Property_PARAMETER_BOOL 602L +#define org_kortforsyningen_proj_Property_PARAMETER_BOOL 603L #ifdef __cplusplus } #endif diff --git a/src/main/cpp/org_kortforsyningen_proj_Type.h b/src/main/cpp/org_kortforsyningen_proj_Type.h index 232a807..2a13922 100644 --- a/src/main/cpp/org_kortforsyningen_proj_Type.h +++ b/src/main/cpp/org_kortforsyningen_proj_Type.h @@ -69,12 +69,14 @@ extern "C" { #define org_kortforsyningen_proj_Type_TRANSFORMATION 29L #undef org_kortforsyningen_proj_Type_PARAMETER #define org_kortforsyningen_proj_Type_PARAMETER 30L +#undef org_kortforsyningen_proj_Type_PARAMETER_VALUE +#define org_kortforsyningen_proj_Type_PARAMETER_VALUE 31L #undef org_kortforsyningen_proj_Type_PARAMETRIC_CS -#define org_kortforsyningen_proj_Type_PARAMETRIC_CS 31L +#define org_kortforsyningen_proj_Type_PARAMETRIC_CS 32L #undef org_kortforsyningen_proj_Type_PARAMETRIC_CRS -#define org_kortforsyningen_proj_Type_PARAMETRIC_CRS 32L +#define org_kortforsyningen_proj_Type_PARAMETRIC_CRS 33L #undef org_kortforsyningen_proj_Type_PARAMETRIC_DATUM -#define org_kortforsyningen_proj_Type_PARAMETRIC_DATUM 33L +#define org_kortforsyningen_proj_Type_PARAMETRIC_DATUM 34L #ifdef __cplusplus } #endif diff --git a/src/main/java/org/kortforsyningen/proj/Datum.java b/src/main/java/org/kortforsyningen/proj/Datum.java index f75ab84..433c416 100644 --- a/src/main/java/org/kortforsyningen/proj/Datum.java +++ b/src/main/java/org/kortforsyningen/proj/Datum.java @@ -98,9 +98,12 @@ static final class Ellipsoid extends IdentifiableObject implements org.opengis.r @Override public Unit getAxisUnit() {return getUnit(Length.class, Property.ELLIPSOID_UNIT);} @Override public double getSemiMajorAxis() {return impl.getNumericProperty(Property.SEMI_MAJOR);} @Override public double getSemiMinorAxis() {return impl.getNumericProperty(Property.SEMI_MINOR);} - @Override public double getInverseFlattening() {return impl.getNumericProperty(Property.INVERSE_FLAT);} @Override public boolean isIvfDefinitive() {return impl.getBooleanProperty(Property.IVF_DEFINITIVE);} @Override public boolean isSphere() {return impl.getBooleanProperty(Property.IS_SPHERE);} + @Override public double getInverseFlattening() { + final double f = impl.getNumericProperty(Property.INVERSE_FLAT); + return (f == 0) ? Double.POSITIVE_INFINITY : f; + } } /** @@ -168,7 +171,7 @@ static final class Vertical extends Datum implements VerticalDatum { */ @Override public VerticalDatumType getVerticalDatumType() { - return null; + return VerticalDatumType.valueOf("Unspecified"); } } diff --git a/src/main/java/org/kortforsyningen/proj/IdentifiableObject.java b/src/main/java/org/kortforsyningen/proj/IdentifiableObject.java index a4d74d3..5cf66b5 100644 --- a/src/main/java/org/kortforsyningen/proj/IdentifiableObject.java +++ b/src/main/java/org/kortforsyningen/proj/IdentifiableObject.java @@ -130,7 +130,11 @@ String getNameString(final boolean alternate) { * @return the primary name, or {@code null} if this object does not provide a name. */ public Identifier getName() { - return ((ObjectIdentifier) impl.getObjectProperty(Property.NAME)).new PrimaryName(this); + if (impl.getBooleanProperty(Property.HAS_NAME)) { + return ((ObjectIdentifier) impl.getObjectProperty(Property.NAME)).new PrimaryName(this); + } else { + return null; + } } /** diff --git a/src/main/java/org/kortforsyningen/proj/NativeResource.java b/src/main/java/org/kortforsyningen/proj/NativeResource.java index dd081f7..e74db11 100644 --- a/src/main/java/org/kortforsyningen/proj/NativeResource.java +++ b/src/main/java/org/kortforsyningen/proj/NativeResource.java @@ -272,6 +272,7 @@ private IdentifiableObject wrapGeodeticObject(final short type, final long rawPo case Type.CONVERSION: obj = new Operation.Conversion (rawPointer); break; case Type.TRANSFORMATION: obj = new Operation.Transformation(rawPointer); break; case Type.PARAMETER: obj = new Parameter (rawPointer); break; + case Type.PARAMETER_VALUE: obj = new Parameter.Value (rawPointer); break; default: throw new FactoryException("Unknown object type."); } return obj.releaseWhenUnreachable(); diff --git a/src/main/java/org/kortforsyningen/proj/Parameter.java b/src/main/java/org/kortforsyningen/proj/Parameter.java index 949b597..0b2e39a 100644 --- a/src/main/java/org/kortforsyningen/proj/Parameter.java +++ b/src/main/java/org/kortforsyningen/proj/Parameter.java @@ -47,7 +47,7 @@ * @since 1.0 */ @SuppressWarnings("rawtypes") -final class Parameter extends IdentifiableObject implements ParameterDescriptor, ParameterValue { +class Parameter extends IdentifiableObject implements ParameterDescriptor { /** * Creates a new wrapper for the given {@code osgeo::proj::operation::OperationParameterValue}. * May also be a {@code osgeo::proj::operation::OperationParameter}, in which case the call to @@ -60,186 +60,225 @@ final class Parameter extends IdentifiableObject implements ParameterDescriptor, } /** - * Returns a description of this parameter. - * - * @return {@code this}. - */ - @Override - public ParameterDescriptor getDescriptor() { - return this; - } - - /** - * Returns the type of this parameter. + * Returns the type of this parameter. This base class returns {@code Object.class} because PROJ + * defines units of measurements with the parameter value instead than the parameter descriptor, + * so the actual class is unknown. The {@link Value} subclass override this method. * * @return the type of this parameter. - * @throws UnsupportedOperationException if the type is unknown. - * It may happen if new type has been added in a new PROJ version, - * in which case we may need to upgrade PROJ-JNI accordingly. - */ - private ParameterType type() { - return ParameterType.get(impl.getIntegerProperty(Property.PARAMETER_TYPE)); - } - - /** - * Returns the class of parameter values. - * - * @return the type of parameter values. */ @Override public Class getValueClass() { - return type().type; + return Object.class; } /** - * Returns the parameter value as an object. The object type may be {@link Double}, - * {@link Integer}, {@link Boolean}, {@link String} or {@link URI}. - * - * @return the parameter value as an object, or {@code null} if no value has been set. + * Read-only parameter value. */ - @Override - public Object getValue() { - switch (type()) { - case MEASURE: return doubleValue(); - case INTEGER: return intValue(); - case BOOLEAN: return booleanValue(); - case STRING: return stringValue(); - case FILENAME: return valueFile(); - default: throw new AssertionError(); // Should never happen. + static final class Value extends Parameter implements ParameterValue { + /** + * Creates a new wrapper for the given {@code osgeo::proj::operation::OperationParameterValue}. + * + * @param ptr pointer to the wrapped PROJ object. + */ + Value(final long ptr) { + super(ptr); } - } - /** - * Returns the unit of measurement of values returned by {@link #doubleValue()}, or {@code null} if none. - * - * @return unit of measurement of {@link #doubleValue()}. - */ - @Override - public Unit getUnit() { - return (Unit) impl.getObjectProperty(Property.PARAMETER_UNIT); - } + /** + * Returns a description of this parameter. + * + * @return {@code this}. + */ + @Override + public ParameterDescriptor getDescriptor() { + return this; + } - /** - * Returns the parameter value in the given unit of measurement. - * - * @param unit the desired unit of measurement. - * @return the parameter value converted to the given unit. - * @throws IllegalArgumentException if the specified unit is invalid for this parameter. - * @throws InvalidParameterTypeException if the value is not a numeric type. - */ - @Override - public double doubleValue(final Unit unit) { - double value = doubleValue(); - if (unit != null) { - final Unit source = getUnit(); - if (source != null) try { - value = source.getConverterToAny(unit).convert(value); - } catch (IncommensurableException e) { - throw new IllegalArgumentException("Can not convert \"" + - getName().getCode() + "\" values to unit " + unit, e); + /** + * Returns the type of this parameter. + * + * @return the type of this parameter. + * @throws UnsupportedOperationException if the type is unknown. + * It may happen if new type has been added in a new PROJ version, + * in which case we may need to upgrade PROJ-JNI accordingly. + */ + private ParameterType type() { + return ParameterType.get(impl.getIntegerProperty(Property.PARAMETER_TYPE)); + } + + /** + * Returns the class of parameter values. + * + * @return the type of parameter values. + */ + @Override + public Class getValueClass() { + return type().type; + } + + /** + * Returns the parameter value as an object. The object type may be {@link Double}, + * {@link Integer}, {@link Boolean}, {@link String} or {@link URI}. + * + * @return the parameter value as an object, or {@code null} if no value has been set. + */ + @Override + public Object getValue() { + switch (type()) { + case MEASURE: return doubleValue(); + case INTEGER: return intValue(); + case BOOLEAN: return booleanValue(); + case STRING: return stringValue(); + case FILENAME: return valueFile(); + default: throw new AssertionError(); // Should never happen. } } - return value; - } - /** - * Returns the parameter value as a floating point number. - * The unit of measurement is specified by {@link #getUnit()}. - * - * @return the numeric parameter value. - * @throws InvalidParameterTypeException if the value is not a numeric type. - */ - @Override - public double doubleValue() { - return impl.getNumericProperty(Property.PARAMETER_VALUE); - } + /** + * Returns the unit of measurement of values returned by {@link #doubleValue()}, or {@code null} if none. + * + * @return unit of measurement of {@link #doubleValue()}. + */ + @Override + public Unit getUnit() { + return (Unit) impl.getObjectProperty(Property.PARAMETER_UNIT); + } - /** - * Returns the parameter value as an integer value. - * - * @return the integer parameter value. - * @throws InvalidParameterTypeException if the value is not an integer type. - */ - @Override - public int intValue() { - return impl.getIntegerProperty(Property.PARAMETER_INT); - } + /** + * Returns the parameter value in the given unit of measurement. + * + * @param unit the desired unit of measurement. + * @return the parameter value converted to the given unit. + * @throws IllegalArgumentException if the specified unit is invalid for this parameter. + * @throws InvalidParameterTypeException if the value is not a numeric type. + */ + @Override + public double doubleValue(final Unit unit) { + double value = doubleValue(); + if (unit != null) { + final Unit source = getUnit(); + if (source != null) try { + value = source.getConverterToAny(unit).convert(value); + } catch (IncommensurableException e) { + throw new IllegalArgumentException("Can not convert \"" + + getName().getCode() + "\" values to unit " + unit, e); + } + } + return value; + } - /** - * Returns the parameter value as a boolean value. - * - * @return the boolean parameter value. - * @throws InvalidParameterTypeException if the value is not a boolean type. - */ - @Override - public boolean booleanValue() { - return impl.getBooleanProperty(Property.PARAMETER_BOOL); - } + /** + * Returns the parameter value as a floating point number. + * The unit of measurement is specified by {@link #getUnit()}. + * + * @return the numeric parameter value. + * @throws InvalidParameterTypeException if the value is not a numeric type. + */ + @Override + public double doubleValue() { + return impl.getNumericProperty(Property.PARAMETER_VALUE); + } - /** - * Returns the string value of this parameter. - * - * @return the string value represented by this parameter. - * @throws InvalidParameterTypeException if the value is not a string. - */ - @Override - public String stringValue() { - return impl.getStringProperty(Property.PARAMETER_STRING); - } + /** + * Returns the parameter value as an integer value. + * + * @return the integer parameter value. + * @throws InvalidParameterTypeException if the value is not an integer type. + */ + @Override + public int intValue() { + return impl.getIntegerProperty(Property.PARAMETER_INT); + } - /** - * Returns a reference to a file or a part of a file containing one or more parameter values. - * - * @return the reference to a file containing parameter values. - * @throws InvalidParameterTypeException if the value is not a reference to a file or a URI. - */ - @Override - public URI valueFile() { - final String file = impl.getStringProperty(Property.PARAMETER_STRING); - return (file != null) ? new File(file).toURI() : null; - } + /** + * Returns the parameter value as a boolean value. + * + * @return the boolean parameter value. + * @throws InvalidParameterTypeException if the value is not a boolean type. + */ + @Override + public boolean booleanValue() { + return impl.getBooleanProperty(Property.PARAMETER_BOOL); + } - /** - * Returns an ordered sequence of numeric values in the specified unit of measure. - * - * @param unit the unit of measure for the value to be returned. - * @return the sequence of values represented by this parameter after conversion to given unit. - * @throws IllegalArgumentException if the specified unit is invalid for this parameter. - * @throws InvalidParameterTypeException if the value is not an array of {@code double}s. - */ - @Override - public double[] doubleValueList(final Unit unit) { - return new double[] {doubleValue(unit)}; - } + /** + * Returns the string value of this parameter. + * + * @return the string value represented by this parameter. + * @throws InvalidParameterTypeException if the value is not a string. + */ + @Override + public String stringValue() { + return impl.getStringProperty(Property.PARAMETER_STRING); + } - /** - * Returns an ordered sequence of numeric values of this parameter. - * - * @return the sequence of values represented by this parameter. - * @throws InvalidParameterTypeException if the value is not an array of {@code double}s. - */ - @Override - public double[] doubleValueList() { - return new double[] {doubleValue()}; - } + /** + * Returns a reference to a file or a part of a file containing one or more parameter values. + * + * @return the reference to a file containing parameter values. + * @throws InvalidParameterTypeException if the value is not a reference to a file or a URI. + */ + @Override + public URI valueFile() { + final String file = impl.getStringProperty(Property.PARAMETER_STRING); + return (file != null) ? new File(file).toURI() : null; + } - /** - * Returns an ordered sequence of integer values of this parameter. - * - * @return the sequence of values represented by this parameter. - * @throws InvalidParameterTypeException if the value is not an array of {@code int}s. - */ - @Override - public int[] intValueList() { - return new int[] {intValue()}; - } + /** + * Returns an ordered sequence of numeric values in the specified unit of measure. + * + * @param unit the unit of measure for the value to be returned. + * @return the sequence of values represented by this parameter after conversion to given unit. + * @throws IllegalArgumentException if the specified unit is invalid for this parameter. + * @throws InvalidParameterTypeException if the value is not an array of {@code double}s. + */ + @Override + public double[] doubleValueList(final Unit unit) { + return new double[] {doubleValue(unit)}; + } - @Override public void setValue(double[] value, Unit unit) {throw new UnsupportedOperationException("Read-only parameter.");} - @Override public void setValue(double value, Unit unit) {throw new UnsupportedOperationException("Read-only parameter.");} - @Override public void setValue(double value) {throw new UnsupportedOperationException("Read-only parameter.");} - @Override public void setValue(int value) {throw new UnsupportedOperationException("Read-only parameter.");} - @Override public void setValue(boolean value) {throw new UnsupportedOperationException("Read-only parameter.");} - @Override public void setValue(Object value) {throw new UnsupportedOperationException("Read-only parameter.");} + /** + * Returns an ordered sequence of numeric values of this parameter. + * + * @return the sequence of values represented by this parameter. + * @throws InvalidParameterTypeException if the value is not an array of {@code double}s. + */ + @Override + public double[] doubleValueList() { + return new double[] {doubleValue()}; + } + + /** + * Returns an ordered sequence of integer values of this parameter. + * + * @return the sequence of values represented by this parameter. + * @throws InvalidParameterTypeException if the value is not an array of {@code int}s. + */ + @Override + public int[] intValueList() { + return new int[] {intValue()}; + } + + @Override public void setValue(double[] value, Unit unit) {throw new UnsupportedOperationException("Read-only parameter.");} + @Override public void setValue(double value, Unit unit) {throw new UnsupportedOperationException("Read-only parameter.");} + @Override public void setValue(double value) {throw new UnsupportedOperationException("Read-only parameter.");} + @Override public void setValue(int value) {throw new UnsupportedOperationException("Read-only parameter.");} + @Override public void setValue(boolean value) {throw new UnsupportedOperationException("Read-only parameter.");} + @Override public void setValue(Object value) {throw new UnsupportedOperationException("Read-only parameter.");} + + /** + * Returns a copy of this parameter value that user can modify. + * + * @return a modifiable copy of this parameter value. + */ + @Override + @SuppressWarnings("CloneDoesntCallSuperClone") + public ParameterValue clone() { + final ParameterValue value = createValue(); + value.setValue(getValue()); + return value; + } + } /** * Creates a modifiable parameter value with initially no value. @@ -251,19 +290,6 @@ public ParameterValue createValue() { throw new UnsupportedOperationException(); // TODO } - /** - * Returns a copy of this parameter value that user can modify. - * - * @return a modifiable copy of this parameter value. - */ - @Override - @SuppressWarnings("CloneDoesntCallSuperClone") - public ParameterValue clone() { - final ParameterValue value = createValue(); - value.setValue(getValue()); - return value; - } - /** * Returns a string representation of this parameter for debugging purposes. * This method format a pseudo-WKT string, with the parameter name between quotes. diff --git a/src/main/java/org/kortforsyningen/proj/ParameterType.java b/src/main/java/org/kortforsyningen/proj/ParameterType.java index e4339aa..8ab1760 100644 --- a/src/main/java/org/kortforsyningen/proj/ParameterType.java +++ b/src/main/java/org/kortforsyningen/proj/ParameterType.java @@ -33,27 +33,27 @@ */ enum ParameterType { /** - * Value with a unit given by {@link Parameter#doubleValue()}. + * Value with a unit given by {@link Parameter.Value#doubleValue()}. */ MEASURE(Double.class), /** - * Character string given by {@link Parameter#stringValue()}. + * Character string given by {@link Parameter.Value#stringValue()}. */ STRING(String.class), /** - * Integer given by {@link Parameter#intValue()}. + * Integer given by {@link Parameter.Value#intValue()}. */ INTEGER(Integer.class), /** - * Boolean given by {@link Parameter#booleanValue()}. + * Boolean given by {@link Parameter.Value#booleanValue()}. */ BOOLEAN(Boolean.class), /** - * Filename given by {@link Parameter#valueFile()}. + * Filename given by {@link Parameter.Value#valueFile()}. */ FILENAME(URI.class); diff --git a/src/main/java/org/kortforsyningen/proj/Property.java b/src/main/java/org/kortforsyningen/proj/Property.java index b25e1e2..cd9e7b6 100644 --- a/src/main/java/org/kortforsyningen/proj/Property.java +++ b/src/main/java/org/kortforsyningen/proj/Property.java @@ -119,7 +119,8 @@ private Property() { * Identify properties which can be returned by {@link SharedPointer#getBooleanProperty(short)} method. */ @Native - static final short IS_SPHERE = 600, - IVF_DEFINITIVE = 601, - PARAMETER_BOOL = 602; + static final short HAS_NAME = 600, + IS_SPHERE = 601, + IVF_DEFINITIVE = 602, + PARAMETER_BOOL = 603; } diff --git a/src/main/java/org/kortforsyningen/proj/SharedObjects.java b/src/main/java/org/kortforsyningen/proj/SharedObjects.java index 7054192..999f354 100644 --- a/src/main/java/org/kortforsyningen/proj/SharedObjects.java +++ b/src/main/java/org/kortforsyningen/proj/SharedObjects.java @@ -288,7 +288,7 @@ private void removeUnderLock(final Entry toRemove) { * @return whether {@link #count} matches the expected value. */ private boolean isValid() { - if (count > upperCapacityThreshold(table.length)) { + if (count >= table.length) { throw new AssertionError(count); } int n = 0; diff --git a/src/main/java/org/kortforsyningen/proj/SimpleExtent.java b/src/main/java/org/kortforsyningen/proj/SimpleExtent.java index 2922bdd..bae95bf 100644 --- a/src/main/java/org/kortforsyningen/proj/SimpleExtent.java +++ b/src/main/java/org/kortforsyningen/proj/SimpleExtent.java @@ -84,8 +84,8 @@ final class SimpleExtent implements GeographicBoundingBox, Extent, Serializable * @param eastBoundLongitude the maximal x value. * @param southBoundLatitude the minimal y value. * @param northBoundLatitude the maximal y value. - * @throws IllegalArgumentException if (west bound > east bound) - * or (south bound > north bound). + * @throws IllegalArgumentException if |west bound| or |east bound| > 180° + * or if (south bound > north bound). * Note that {@linkplain Double#NaN NaN} values are allowed. */ SimpleExtent(final double westBoundLongitude, @@ -95,7 +95,7 @@ final class SimpleExtent implements GeographicBoundingBox, Extent, Serializable { final String dim; final double min, max; - if (westBoundLongitude > eastBoundLongitude) { + if (Math.abs(westBoundLongitude) > 180 || Math.abs(eastBoundLongitude) > 180) { min = westBoundLongitude; max = eastBoundLongitude; dim = "longitude"; diff --git a/src/main/java/org/kortforsyningen/proj/Type.java b/src/main/java/org/kortforsyningen/proj/Type.java index 64994c0..887f57c 100644 --- a/src/main/java/org/kortforsyningen/proj/Type.java +++ b/src/main/java/org/kortforsyningen/proj/Type.java @@ -74,7 +74,8 @@ private Type() { CONVERSION = 28, TRANSFORMATION = 29, PARAMETER = 30, - PARAMETRIC_CS = 31, // From ISO 19111:2019 - PARAMETRIC_CRS = 32, - PARAMETRIC_DATUM = 33; + PARAMETER_VALUE = 31, + PARAMETRIC_CS = 32, // From ISO 19111:2019 + PARAMETRIC_CRS = 33, + PARAMETRIC_DATUM = 34; } diff --git a/src/main/java/org/kortforsyningen/proj/UnitOfMeasure.java b/src/main/java/org/kortforsyningen/proj/UnitOfMeasure.java index 3573543..7aae5dd 100644 --- a/src/main/java/org/kortforsyningen/proj/UnitOfMeasure.java +++ b/src/main/java/org/kortforsyningen/proj/UnitOfMeasure.java @@ -116,6 +116,25 @@ private UnitOfMeasure(final int type, final String name, final double toSI) { */ static native UnitOfMeasure create(short code); + /** + * Returns a unit of measurement of the same kind than this unit bit with the given {@link #toSI} factor + * (ignoring a small tolerance threshold). This method returns a predefined unit if possible or create a + * new one otherwise. + * + * @param scale the desired {@link #toSI} scale. + * @return a unit of measurement for the given scale. + */ + private Unit forScale(final double scale) { + final UnitType t = UnitType.FOR_QUANTITY_TYPE.get(type); + if (t != null) { + final Unit unit = t.getPredefinedUnit(scale); + if (unit != null) { + return unit.asType(type); + } + } + return new UnitOfMeasure<>(type, scale); + } + /** * Returns the symbol of this unit, or {@code null} if this unit has no specific symbol associated with. */ @@ -273,7 +292,7 @@ public Unit shift(final double offset) { @Override public Unit multiply(final double multiplier) { if (multiplier == 1) return this; - return new UnitOfMeasure<>(type, toSI * multiplier); + return forScale(toSI * multiplier); } /** @@ -298,7 +317,7 @@ public Unit inverse() { @Override public Unit divide(final double divisor) { if (divisor == 1) return this; - return new UnitOfMeasure<>(type, toSI / divisor); + return forScale(toSI / divisor); } /** @@ -362,6 +381,6 @@ public int hashCode() { */ @Override public String toString() { - return getName(); + return (name != null) ? name : "Unnamed"; } } diff --git a/src/main/java/org/kortforsyningen/proj/UnitType.java b/src/main/java/org/kortforsyningen/proj/UnitType.java index 98c7d46..cc759a7 100644 --- a/src/main/java/org/kortforsyningen/proj/UnitType.java +++ b/src/main/java/org/kortforsyningen/proj/UnitType.java @@ -21,6 +21,7 @@ */ package org.kortforsyningen.proj; +import java.util.Map; import java.util.Arrays; import javax.measure.Unit; import javax.measure.Quantity; @@ -122,6 +123,17 @@ enum UnitType { } } + /** + * Provides {@link UnitType} instances for a given quantity type. + * This is similar to {@link #forOrdinal(int)} method, but using + * a {@link Class} argument instead than an enumeration ordinal. + */ + static final Map, UnitType> FOR_QUANTITY_TYPE = Map.of( + Time.class, TIME, + Angle.class, ANGULAR, + Length.class, LINEAR, + Dimensionless.class, SCALE); + /** * Returns the unit type from the given ordinal value. * This method is invoked by {@link UnitOfMeasure} constructor, which is a @@ -177,7 +189,8 @@ final Unit getPredefinedUnit(final double scale) { } } final Unit unit = getSystemUnit(); - if (!(unit instanceof UnitOfMeasure)) { + if (unit != null && !(unit instanceof UnitOfMeasure)) { + // Do NOT invoke on UnitOfMeasure instance; it would create a never-ending loop. return unit.multiply(scale); } /* diff --git a/src/test/java/org/kortforsyningen/proj/GIGS2001Test.java b/src/test/java/org/kortforsyningen/proj/GIGS2001Test.java new file mode 100644 index 0000000..c4dff71 --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/GIGS2001Test.java @@ -0,0 +1,59 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.junit.Test; +import org.junit.Ignore; +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; + + + +/** + * Tests creation of units of measurements from EPSG codes. + * This is part of Geospatial Integrity of Geoscience Software (GIGS) tests implemented in GeoAPI. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.JVM) // Intentionally want some randomness +public final strictfp class GIGS2001Test extends org.opengis.test.referencing.gigs.GIGS2001 { + /** + * Creates a new test using the default authority factory. + */ + public GIGS2001Test() { + super(TestFactorySource.EPSG); + } + + /** + * Skips this test because we do not support non-linear unit conversions. + */ + @Test + @Override + @Ignore("Non-linear unit conversions not supported.") + public void testSexagesimalDegree() { + } +} diff --git a/src/test/java/org/kortforsyningen/proj/GIGS2002Test.java b/src/test/java/org/kortforsyningen/proj/GIGS2002Test.java new file mode 100644 index 0000000..801e700 --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/GIGS2002Test.java @@ -0,0 +1,48 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; + + +/** + * Tests creation of ellipsoids from EPSG codes. + * This is part of Geospatial Integrity of Geoscience Software (GIGS) tests implemented in GeoAPI. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.JVM) // Intentionally want some randomness +public final strictfp class GIGS2002Test extends org.opengis.test.referencing.gigs.GIGS2002 { + /** + * Creates a new test using the default authority factory. + */ + public GIGS2002Test() { + super(TestFactorySource.EPSG); + isStandardAliasSupported = false; + } +} diff --git a/src/test/java/org/kortforsyningen/proj/GIGS2003Test.java b/src/test/java/org/kortforsyningen/proj/GIGS2003Test.java new file mode 100644 index 0000000..83df77c --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/GIGS2003Test.java @@ -0,0 +1,48 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; + + +/** + * Tests creation of prime meridians from EPSG codes. + * This is part of Geospatial Integrity of Geoscience Software (GIGS) tests implemented in GeoAPI. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.JVM) // Intentionally want some randomness +public final strictfp class GIGS2003Test extends org.opengis.test.referencing.gigs.GIGS2003 { + /** + * Creates a new test using the default authority factory. + */ + public GIGS2003Test() { + super(TestFactorySource.EPSG); + isStandardAliasSupported = false; + } +} diff --git a/src/test/java/org/kortforsyningen/proj/GIGS2004Test.java b/src/test/java/org/kortforsyningen/proj/GIGS2004Test.java new file mode 100644 index 0000000..20fd605 --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/GIGS2004Test.java @@ -0,0 +1,60 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; +import org.opengis.referencing.IdentifiedObject; + + +/** + * Tests creation of geodetic (geographic or geocentric) CRS from EPSG codes. + * This is part of Geospatial Integrity of Geoscience Software (GIGS) tests implemented in GeoAPI. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.JVM) // Intentionally want some randomness +public final strictfp class GIGS2004Test extends org.opengis.test.referencing.gigs.GIGS2004 { + /** + * Creates a new test using the default authority factory. + */ + public GIGS2004Test() { + super(TestFactorySource.EPSG, TestFactorySource.EPSG); + } + + /** + * Returns the name to compare against expected names. We temporarily override this method + * for taking in account changes in EPSG database compared to GIGS tests. + * + * @param object the object for which to get the name. + * @return the name to compare against expected values. + */ + @Override + protected String getVerifiableName(final IdentifiedObject object) { + return TestFactorySource.renameToPreviousVersion(super.getVerifiableName(object)); + } +} diff --git a/src/test/java/org/kortforsyningen/proj/GIGS2005Test.java b/src/test/java/org/kortforsyningen/proj/GIGS2005Test.java new file mode 100644 index 0000000..7d02af5 --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/GIGS2005Test.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; + + +/** + * Tests creation of map projections from EPSG codes. + * This is part of Geospatial Integrity of Geoscience Software (GIGS) tests implemented in GeoAPI. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.JVM) // Intentionally want some randomness +public final strictfp class GIGS2005Test extends org.opengis.test.referencing.gigs.GIGS2005 { + /** + * Creates a new test using the default authority factory. + */ + public GIGS2005Test() { + super(TestFactorySource.EPSG); + } +} diff --git a/src/test/java/org/kortforsyningen/proj/GIGS2006Test.java b/src/test/java/org/kortforsyningen/proj/GIGS2006Test.java new file mode 100644 index 0000000..1f89ac1 --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/GIGS2006Test.java @@ -0,0 +1,71 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.junit.Test; +import org.junit.Ignore; +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; +import org.opengis.referencing.IdentifiedObject; + + +/** + * Tests creation of projected CRS from EPSG codes. + * This is part of Geospatial Integrity of Geoscience Software (GIGS) tests implemented in GeoAPI. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.JVM) // Intentionally want some randomness +public final strictfp class GIGS2006Test extends org.opengis.test.referencing.gigs.GIGS2006 { + /** + * Creates a new test using the default authority factory. + */ + public GIGS2006Test() { + super(TestFactorySource.EPSG); + } + + /** + * Returns the name to compare against expected names. We temporarily override this method + * for taking in account changes in EPSG database compared to GIGS tests. + * + * @param object the object for which to get the name. + * @return the name to compare against expected values. + */ + @Override + protected String getVerifiableName(final IdentifiedObject object) { + return TestFactorySource.renameToPreviousVersion(super.getVerifiableName(object)); + } + + /** + * Skips this test because of wrong axis order in the test. + */ + @Test + @Override + @Ignore("Wrong axis order in GeoAPI implementation of GIGS test.") + public void testTananarive_Paris() { + } +} diff --git a/src/test/java/org/kortforsyningen/proj/GIGS2007Test.java b/src/test/java/org/kortforsyningen/proj/GIGS2007Test.java new file mode 100644 index 0000000..a7f192e --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/GIGS2007Test.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; + + +/** + * Tests creation horizontal coordinate transformations from EPSG codes. + * This is part of Geospatial Integrity of Geoscience Software (GIGS) tests implemented in GeoAPI. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.JVM) // Intentionally want some randomness +public final strictfp class GIGS2007Test extends org.opengis.test.referencing.gigs.GIGS2007 { + /** + * Creates a new test using the default authority factory. + */ + public GIGS2007Test() { + super(TestFactorySource.EPSG); + } +} diff --git a/src/test/java/org/kortforsyningen/proj/GIGS2008Test.java b/src/test/java/org/kortforsyningen/proj/GIGS2008Test.java new file mode 100644 index 0000000..4189e15 --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/GIGS2008Test.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; + + +/** + * Tests creation of vertical CRS from EPSG codes. + * This is part of Geospatial Integrity of Geoscience Software (GIGS) tests implemented in GeoAPI. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.JVM) // Intentionally want some randomness +public final strictfp class GIGS2008Test extends org.opengis.test.referencing.gigs.GIGS2008 { + /** + * Creates a new test using the default authority factory. + */ + public GIGS2008Test() { + super(TestFactorySource.EPSG, TestFactorySource.EPSG); + } +} diff --git a/src/test/java/org/kortforsyningen/proj/GIGS2009Test.java b/src/test/java/org/kortforsyningen/proj/GIGS2009Test.java new file mode 100644 index 0000000..673bd9b --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/GIGS2009Test.java @@ -0,0 +1,46 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; + + +/** + * Tests creation of vertical coordinate transformations from EPSG codes. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.JVM) // Intentionally want some randomness +public final strictfp class GIGS2009Test extends org.opengis.test.referencing.gigs.GIGS2009 { + /** + * Creates a new test using the default authority factory. + */ + public GIGS2009Test() { + super(TestFactorySource.EPSG); + } +} diff --git a/src/test/java/org/kortforsyningen/proj/GIGS3002Test.java b/src/test/java/org/kortforsyningen/proj/GIGS3002Test.java new file mode 100644 index 0000000..7587fc0 --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/GIGS3002Test.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; + + +/** + * Runs the Geospatial Integrity of Geoscience Software tests on + * ellipsoid objects creation. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.JVM) // Intentionally want some randomness +public final strictfp class GIGS3002Test extends org.opengis.test.referencing.gigs.GIGS3002 { + /** + * Creates a new test suite using the singleton factory instance. + */ + public GIGS3002Test() { + super(TestFactorySource.OBJECTS); + } +} diff --git a/src/test/java/org/kortforsyningen/proj/GIGS3003Test.java b/src/test/java/org/kortforsyningen/proj/GIGS3003Test.java new file mode 100644 index 0000000..d424745 --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/GIGS3003Test.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; + + +/** + * Runs the Geospatial Integrity of Geoscience Software tests on + * prime meridian objects creation. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.JVM) // Intentionally want some randomness +public final strictfp class GIGS3003Test extends org.opengis.test.referencing.gigs.GIGS3003 { + /** + * Creates a new test suite using the singleton factory instance. + */ + public GIGS3003Test() { + super(TestFactorySource.OBJECTS); + } +} diff --git a/src/test/java/org/kortforsyningen/proj/GIGS3004Test.java b/src/test/java/org/kortforsyningen/proj/GIGS3004Test.java new file mode 100644 index 0000000..23d69dd --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/GIGS3004Test.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.junit.FixMethodOrder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; + + +/** + * Runs the Geospatial Integrity of Geoscience Software tests on datum objects creation. + * {@code GIGS3004} tests also geographic and geocentric CRS creations with the tested geodetic datum. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.JVM) // Intentionally want some randomness +public final strictfp class GIGS3004Test extends org.opengis.test.referencing.gigs.GIGS3004 { + /** + * Creates a new test suite using the singleton factory instance. + */ + public GIGS3004Test() { + super(TestFactorySource.OBJECTS, TestFactorySource.OBJECTS, TestFactorySource.OBJECTS); + } +} diff --git a/src/test/java/org/kortforsyningen/proj/OperationFactoryTest.java b/src/test/java/org/kortforsyningen/proj/OperationFactoryTest.java index 935820f..7378556 100644 --- a/src/test/java/org/kortforsyningen/proj/OperationFactoryTest.java +++ b/src/test/java/org/kortforsyningen/proj/OperationFactoryTest.java @@ -55,7 +55,7 @@ public final strictfp class OperationFactoryTest { * Creates a new test case. */ public OperationFactoryTest() { - crsFactory = new AuthorityFactory.API("EPSG"); + crsFactory = TestFactorySource.EPSG; } /** diff --git a/src/test/java/org/kortforsyningen/proj/OperationTest.java b/src/test/java/org/kortforsyningen/proj/OperationTest.java index b65cc8d..81d4f7d 100644 --- a/src/test/java/org/kortforsyningen/proj/OperationTest.java +++ b/src/test/java/org/kortforsyningen/proj/OperationTest.java @@ -51,8 +51,8 @@ public final strictfp class OperationTest extends TransformTestCase { * Creates a new test case. */ public OperationTest() { - factory = new OperationFactory(null); - crsFactory = new AuthorityFactory.API("EPSG"); + factory = TestFactorySource.OPERATIONS; + crsFactory = TestFactorySource.EPSG; } /** diff --git a/src/test/java/org/kortforsyningen/proj/ParameterTest.java b/src/test/java/org/kortforsyningen/proj/ParameterTest.java index a11e717..cac2e3c 100644 --- a/src/test/java/org/kortforsyningen/proj/ParameterTest.java +++ b/src/test/java/org/kortforsyningen/proj/ParameterTest.java @@ -76,7 +76,7 @@ private static void assertLatitude(final ParameterDescriptor descriptor) { */ @Test public void testMercator() throws FactoryException { - AuthorityFactory.API factory = new AuthorityFactory.API("EPSG"); + AuthorityFactory.API factory = TestFactorySource.EPSG; verifyWorldMercator((Conversion) factory.createCoordinateOperation("19883")); } diff --git a/src/test/java/org/kortforsyningen/proj/ReferencingFormatTest.java b/src/test/java/org/kortforsyningen/proj/ReferencingFormatTest.java index ffc2736..a8bda79 100644 --- a/src/test/java/org/kortforsyningen/proj/ReferencingFormatTest.java +++ b/src/test/java/org/kortforsyningen/proj/ReferencingFormatTest.java @@ -83,7 +83,7 @@ public void verifyOrdinalValues() throws IOException { */ @Test public void testToWKT() throws FactoryException { - final AuthorityFactory.API factory = new AuthorityFactory.API("EPSG"); + final AuthorityFactory.API factory = TestFactorySource.EPSG; final CoordinateReferenceSystem crs = factory.createCoordinateReferenceSystem("4326"); final String wkt = crs.toWKT(); assertTrue(wkt, wkt.startsWith( @@ -104,7 +104,7 @@ public void testToWKT() throws FactoryException { */ @Test public void testFormatWKT() throws FactoryException { - final AuthorityFactory.API factory = new AuthorityFactory.API("EPSG"); + final AuthorityFactory.API factory = TestFactorySource.EPSG; final CoordinateReferenceSystem crs = factory.createCoordinateReferenceSystem("4326"); final ReferencingFormat formatter = new ReferencingFormat(); formatter.setConvention(ReferencingFormat.Convention.WKT1_ESRI); @@ -122,7 +122,7 @@ public void testFormatWKT() throws FactoryException { */ @Test public void testFormatJSON() throws FactoryException { - final AuthorityFactory.API factory = new AuthorityFactory.API("EPSG"); + final AuthorityFactory.API factory = TestFactorySource.EPSG; final CoordinateReferenceSystem crs = factory.createCoordinateReferenceSystem("4326"); final ReferencingFormat formatter = new ReferencingFormat(); formatter.setConvention(ReferencingFormat.Convention.JSON); @@ -137,7 +137,7 @@ public void testFormatJSON() throws FactoryException { */ @Test public void testFormatPROJ() throws FactoryException { - final AuthorityFactory.API factory = new AuthorityFactory.API("EPSG"); + final AuthorityFactory.API factory = TestFactorySource.EPSG; final CoordinateReferenceSystem crs = factory.createCoordinateReferenceSystem("3395"); final ReferencingFormat formatter = new ReferencingFormat(); formatter.setConvention(ReferencingFormat.Convention.PROJ_5); diff --git a/src/test/java/org/kortforsyningen/proj/TestFactorySource.java b/src/test/java/org/kortforsyningen/proj/TestFactorySource.java new file mode 100644 index 0000000..d8c3c62 --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/TestFactorySource.java @@ -0,0 +1,68 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + + +/** + * Source of factories used for the tests. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +final class TestFactorySource { + /** + * The EPSG authority factory to use for testing creation from EPSG codes. + */ + static final AuthorityFactory.API EPSG = new AuthorityFactory.API("EPSG"); + + /** + * The factory to use for testing component creations. + */ + static final ObjectFactory OBJECTS = ObjectFactory.INSTANCE; + + /** + * The factory to use for testing operation creations. + */ + static final OperationFactory OPERATIONS = new OperationFactory(null); + + /** + * Do not allow instantiation of this class. + */ + private TestFactorySource() { + } + + /** + * If the name of an object was different in a previous version of EPSG database, + * returns the previous name expected by GIGS tests. Those renaming are temporary, + * until we update GIGS tests for the new names. + * + * @param name the name selected by PROJ. + * @return the name to compare against expected values. + */ + static String renameToPreviousVersion(String name) { + if ("Camacupa 1948".equals(name)) { + name = "Camacupa"; + } + return name; + } +} diff --git a/src/test/java/org/kortforsyningen/proj/UnitsTest.java b/src/test/java/org/kortforsyningen/proj/UnitsTest.java index bf62689..d2455fa 100644 --- a/src/test/java/org/kortforsyningen/proj/UnitsTest.java +++ b/src/test/java/org/kortforsyningen/proj/UnitsTest.java @@ -97,7 +97,7 @@ public void testScaledUnits() { */ @Test public void testCreateUnitOfMeasure() throws FactoryException { - final AuthorityFactory.API factory = new AuthorityFactory.API("EPSG"); + final AuthorityFactory.API factory = TestFactorySource.EPSG; assertSame(Units.METRE, factory.createUnit("9001")); assertSame(Units.RADIAN, factory.createUnit("9101")); assertSame(Units.MICRORADIAN, factory.createUnit("9109")); From d0c59d28b03d05a2cef549cb61e09acd37453f55 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Tue, 24 Dec 2019 15:45:39 +0100 Subject: [PATCH 4/5] Implement IdentifiedObject.getAliases(). Not tested because while PROJ provides an `IdentifiedObject.aliases()` method, it seems that the vector is always empty (at least with the GIGS tests). https://github.com/Kortforsyningen/PROJ-JNI/issues/27 --- src/main/cpp/bindings.cpp | 52 +++++ .../cpp/org_kortforsyningen_proj_Property.h | 18 +- .../org_kortforsyningen_proj_SharedPointer.h | 2 +- .../java/org/kortforsyningen/proj/Alias.java | 105 ++++++++++ .../proj/IdentifiableObject.java | 29 ++- .../org/kortforsyningen/proj/Property.java | 14 +- .../kortforsyningen/proj/SharedPointer.java | 2 +- .../org/kortforsyningen/proj/SimpleName.java | 182 ++++++++++++++++++ 8 files changed, 389 insertions(+), 15 deletions(-) create mode 100644 src/main/java/org/kortforsyningen/proj/Alias.java create mode 100644 src/main/java/org/kortforsyningen/proj/SimpleName.java diff --git a/src/main/cpp/bindings.cpp b/src/main/cpp/bindings.cpp index eb1d0ac..4c073d6 100644 --- a/src/main/cpp/bindings.cpp +++ b/src/main/cpp/bindings.cpp @@ -157,7 +157,10 @@ using osgeo::proj::operation::SingleOperation; using osgeo::proj::operation::Transformation; using osgeo::proj::util::BaseObject; using osgeo::proj::util::BaseObjectPtr; +using osgeo::proj::util::GenericNameNNPtr; +using osgeo::proj::util::GenericNamePtr; using osgeo::proj::util::IComparable; +using osgeo::proj::util::NameSpacePtr; using osgeo::proj::util::optional; using osgeo::proj::util::PropertyMap; // @@ -888,6 +891,19 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_Context_createFromUserIn // +/** + * Converts the given osgeo::proj::util::GenericName into a Java string. + * + * @param env The JNI environment. + * @param name The name to convert to Java string. + * @return the Java string. + */ +inline jstring name_to_string(JNIEnv *env, GenericNameNNPtr name) { + const std::string &text = name->toString(); + return env->NewStringUTF(text.c_str()); +} + + /** * Returns a property value as an object. * @@ -1032,6 +1048,19 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_SharedPointer_searchVect } +/** + * Returns the alias at given index. This is a shortcut for a relatively frequent operation. + * + * @param env The JNI environment. + * @param object The Java object wrapping the PROJ object for which to get an alias. + * @param index Index of the alias to return. + * @return Value of the specified alias. + */ +inline GenericNameNNPtr get_alias(JNIEnv *env, jobject object, jint index) { + return get_identified_object(env, object)->aliases().at(index); +} + + /** * Returns a property value as an element in a std::vector. * @@ -1053,6 +1082,26 @@ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_SharedPointer_getVectorE type = org_kortforsyningen_proj_Type_IDENTIFIER; break; } + case org_kortforsyningen_proj_Property_ALIAS: { + return name_to_string(env, get_alias(env, object, index)); + } + case org_kortforsyningen_proj_Property_ALIAS_NS: { + NameSpacePtr ns = get_alias(env, object, index)->scope(); + if (ns) { + GenericNamePtr name = ns->name(); + if (name) { + return name_to_string(env, NN_CHECK_ASSERT(name)); + } + } + return nullptr; + } + case org_kortforsyningen_proj_Property_ALIAS_NS_IS_GLOBAL: { + NameSpacePtr ns = get_alias(env, object, index)->scope(); + return env->NewStringUTF((!ns || ns->isGlobal()) ? "true" : "false"); + } + case org_kortforsyningen_proj_Property_FULLY_QUALIFIED: { + return name_to_string(env, get_alias(env, object, index)->toFullyQualifiedName()); + } case org_kortforsyningen_proj_Property_AXIS: { value = get_shared_object(env, object)->axisList().at(index).as_nullable(); type = org_kortforsyningen_proj_Type_AXIS; @@ -1112,6 +1161,9 @@ JNIEXPORT jint JNICALL Java_org_kortforsyningen_proj_SharedPointer_getVectorSize case org_kortforsyningen_proj_Property_IDENTIFIER: { return get_identified_object(env, object)->identifiers().size(); } + case org_kortforsyningen_proj_Property_ALIAS: { + return get_identified_object(env, object)->aliases().size(); + } case org_kortforsyningen_proj_Property_AXIS: { return get_and_unwrap_ptr(env, object)->axisList().size(); } diff --git a/src/main/cpp/org_kortforsyningen_proj_Property.h b/src/main/cpp/org_kortforsyningen_proj_Property.h index 0e2b679..048ab20 100644 --- a/src/main/cpp/org_kortforsyningen_proj_Property.h +++ b/src/main/cpp/org_kortforsyningen_proj_Property.h @@ -33,16 +33,24 @@ extern "C" { #define org_kortforsyningen_proj_Property_PARAMETER_UNIT 11L #undef org_kortforsyningen_proj_Property_AXIS #define org_kortforsyningen_proj_Property_AXIS 100L +#undef org_kortforsyningen_proj_Property_ALIAS +#define org_kortforsyningen_proj_Property_ALIAS 101L +#undef org_kortforsyningen_proj_Property_ALIAS_NS +#define org_kortforsyningen_proj_Property_ALIAS_NS 102L +#undef org_kortforsyningen_proj_Property_ALIAS_NS_IS_GLOBAL +#define org_kortforsyningen_proj_Property_ALIAS_NS_IS_GLOBAL 103L +#undef org_kortforsyningen_proj_Property_FULLY_QUALIFIED +#define org_kortforsyningen_proj_Property_FULLY_QUALIFIED 104L #undef org_kortforsyningen_proj_Property_IDENTIFIER -#define org_kortforsyningen_proj_Property_IDENTIFIER 101L +#define org_kortforsyningen_proj_Property_IDENTIFIER 105L #undef org_kortforsyningen_proj_Property_METHOD_PARAMETER -#define org_kortforsyningen_proj_Property_METHOD_PARAMETER 102L +#define org_kortforsyningen_proj_Property_METHOD_PARAMETER 106L #undef org_kortforsyningen_proj_Property_OPERATION_PARAMETER -#define org_kortforsyningen_proj_Property_OPERATION_PARAMETER 103L +#define org_kortforsyningen_proj_Property_OPERATION_PARAMETER 107L #undef org_kortforsyningen_proj_Property_CRS_COMPONENT -#define org_kortforsyningen_proj_Property_CRS_COMPONENT 104L +#define org_kortforsyningen_proj_Property_CRS_COMPONENT 108L #undef org_kortforsyningen_proj_Property_SOURCE_TARGET_CRS -#define org_kortforsyningen_proj_Property_SOURCE_TARGET_CRS 105L +#define org_kortforsyningen_proj_Property_SOURCE_TARGET_CRS 109L #undef org_kortforsyningen_proj_Property_NAME_STRING #define org_kortforsyningen_proj_Property_NAME_STRING 200L #undef org_kortforsyningen_proj_Property_IDENTIFIER_STRING diff --git a/src/main/cpp/org_kortforsyningen_proj_SharedPointer.h b/src/main/cpp/org_kortforsyningen_proj_SharedPointer.h index 7528227..2e9e1d9 100644 --- a/src/main/cpp/org_kortforsyningen_proj_SharedPointer.h +++ b/src/main/cpp/org_kortforsyningen_proj_SharedPointer.h @@ -66,7 +66,7 @@ JNIEXPORT jint JNICALL Java_org_kortforsyningen_proj_SharedPointer_getVectorSize /* * Class: org_kortforsyningen_proj_SharedPointer * Method: getVectorElement - * Signature: (SI)Lorg/kortforsyningen/proj/IdentifiableObject; + * Signature: (SI)Ljava/lang/Object; */ JNIEXPORT jobject JNICALL Java_org_kortforsyningen_proj_SharedPointer_getVectorElement (JNIEnv *, jobject, jshort, jint); diff --git a/src/main/java/org/kortforsyningen/proj/Alias.java b/src/main/java/org/kortforsyningen/proj/Alias.java new file mode 100644 index 0000000..c097c93 --- /dev/null +++ b/src/main/java/org/kortforsyningen/proj/Alias.java @@ -0,0 +1,105 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.opengis.util.GenericName; + + +/** + * A {@link GenericName} which is an item of a list provided by a larger object. + * We do not wrap {@code osgeo::proj::util::GenericName} directly because in most + * cases, only the {@link #toString()} method is of interest. If nevertheless the + * user asks for another property, then we will fetch that information from parent. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.0 + * @since 1.0 + */ +final class Alias extends SimpleName { + /** + * The object which owns this name. + */ + private final IdentifiableObject owner; + + /** + * Index of the this item in the aliases vector. + */ + private final int index; + + /** + * Creates a new name which is an item of the specified object. + * + * @param name the name. + * @param owner the object which owns this name. + * @param index index of the this item in the aliases vector. + */ + Alias(final String name, final IdentifiableObject owner, final int index) { + super(name); + this.owner = owner; + this.index = index; + } + + /** + * Returns a property value as an string at the given index of a {@code std::vector}. + * + * @param property one of {@link Property#ALIAS_NS}, etc. values. + * @return value of the specified property, or {@code null} if undefined. + * @throws RuntimeException if the specified property does not exist for {@link #owner}. + * @throws IndexOutOfBoundsException if {@link #index} is out of bounds. + */ + private String getElement(final short property) { + return (String) owner.impl.getVectorElement(property, index); + } + + /** + * If the fully-qualified name differs from this name, returns it. + * Otherwise returns {@code this}. + * + * @return the fully-qualified name (never {@code null}). + */ + @Override + public GenericName toFullyQualifiedName() { + final String qn = getElement(Property.FULLY_QUALIFIED); + return name.equals(qn) ? this : new SimpleName(qn); + } + + /** + * Indicates whether this namespace is a "top level" namespace. + * + * @return {@code true} if this namespace is the global namespace. + */ + @Override + public boolean isGlobal() { + return Boolean.parseBoolean(getElement(Property.ALIAS_NS_IS_GLOBAL)); + } + + /** + * Represents the identifier of this namespace. + * + * @return the identifier of this namespace. + */ + @Override + public GenericName name() { + final String ns = getElement(Property.ALIAS_NS); + return (ns != null) ? new SimpleName(ns) : null; + } +} diff --git a/src/main/java/org/kortforsyningen/proj/IdentifiableObject.java b/src/main/java/org/kortforsyningen/proj/IdentifiableObject.java index 5cf66b5..8cd9703 100644 --- a/src/main/java/org/kortforsyningen/proj/IdentifiableObject.java +++ b/src/main/java/org/kortforsyningen/proj/IdentifiableObject.java @@ -24,7 +24,6 @@ import java.time.Instant; import java.util.Set; import java.util.Collection; -import java.util.Collections; import java.util.AbstractSet; import java.util.AbstractList; import java.util.Formattable; @@ -143,7 +142,7 @@ public Identifier getName() { * @return alternative names and abbreviations, or an empty collection if there is none. */ public Collection getAlias() { - return Collections.emptySet(); // TODO + return new Aliases(); } /** @@ -210,6 +209,30 @@ final Date getDate(final short property) { return (value != null) ? Date.from(Instant.parse(value)) : null; } + /** + * Collection of aliases stored by PROJ in a vector. + * This is a specialization of {@link PropertyList} — see that class for comments. + */ + private final class Aliases extends AbstractList { + /** + * Returns the length of the C++ vector. + * + * @return number of elements in the wrapped vector. + */ + @Override + public int size() { + return impl.getVectorSize(Property.ALIAS); + } + + /** + * Returns the element at the given index. + */ + @Override + public GenericName get(final int index) { + return new Alias((String) impl.getVectorElement(Property.ALIAS, index), IdentifiableObject.this, index); + } + } + /** * Collection of objects stored by PROJ in a vector. * @@ -267,7 +290,7 @@ public E get(final int index) { * * @param type of values returned by this collection. */ - private class PropertySet extends AbstractSet { + private final class PropertySet extends AbstractSet { /** * Type of values returned by this collection. */ diff --git a/src/main/java/org/kortforsyningen/proj/Property.java b/src/main/java/org/kortforsyningen/proj/Property.java index cd9e7b6..4503584 100644 --- a/src/main/java/org/kortforsyningen/proj/Property.java +++ b/src/main/java/org/kortforsyningen/proj/Property.java @@ -60,11 +60,15 @@ private Property() { */ @Native static final short AXIS = 100, - IDENTIFIER = 101, - METHOD_PARAMETER = 102, - OPERATION_PARAMETER = 103, - CRS_COMPONENT = 104, - SOURCE_TARGET_CRS = 105; // Index 0 for source, 1 for target. + ALIAS = 101, + ALIAS_NS = 102, + ALIAS_NS_IS_GLOBAL = 103, + FULLY_QUALIFIED = 104, + IDENTIFIER = 105, + METHOD_PARAMETER = 106, + OPERATION_PARAMETER = 107, + CRS_COMPONENT = 108, + SOURCE_TARGET_CRS = 109; // Index 0 for source, 1 for target. /** * Identify properties which can be returned by {@link SharedPointer#getStringProperty(short)} method. diff --git a/src/main/java/org/kortforsyningen/proj/SharedPointer.java b/src/main/java/org/kortforsyningen/proj/SharedPointer.java index 51fbd8b..12da96b 100644 --- a/src/main/java/org/kortforsyningen/proj/SharedPointer.java +++ b/src/main/java/org/kortforsyningen/proj/SharedPointer.java @@ -122,7 +122,7 @@ class SharedPointer extends NativeResource { * @throws RuntimeException if the specified property does not exist for this object. * @throws IndexOutOfBoundsException if the given index is out of bounds. */ - final native IdentifiableObject getVectorElement(short property, int index); + final native Object getVectorElement(short property, int index); /** * Returns a property value as an object for the given name. diff --git a/src/main/java/org/kortforsyningen/proj/SimpleName.java b/src/main/java/org/kortforsyningen/proj/SimpleName.java new file mode 100644 index 0000000..9301b6d --- /dev/null +++ b/src/main/java/org/kortforsyningen/proj/SimpleName.java @@ -0,0 +1,182 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import java.util.List; +import java.util.Collections; +import org.opengis.util.GenericName; +import org.opengis.util.InternationalString; +import org.opengis.util.LocalName; +import org.opengis.util.NameSpace; +import org.opengis.util.ScopedName; + + +/** + * Simple implementation of {@link LocalName} for storing CRS aliases. + * This class provides the most trivial implementation of every {@link LocalName} methods, + * making this class merely a container for a {@link String}. Other libraries may provide + * more sophisticated implementations behaving like a path in a file directory structure. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.0 + * @since 1.0 + */ +class SimpleName implements LocalName, NameSpace { + /** + * The name. + */ + final String name; + + /** + * Creates a new name. + * + * @param name the name. + */ + SimpleName(final String name) { + this.name = name; + } + + /** + * Returns always 1 for a local name. + * + * @return always 1 for a local name. + */ + @Override + public final int depth() { + return 1; + } + + /** + * Returns a singleton containing only {@code this}, since this name is itself a local name. + * + * @return a {@linkplain Collections#singletonList singleton} containing only {@code this}. + */ + @Override + public final List getParsedNames() { + return Collections.singletonList(this); + } + + /** + * Returns {@code this} since this object is already a local name. + */ + @Override + public final LocalName head() { + return this; + } + + /** + * Returns {@code this} since this object is already a local name. + */ + @Override + public final LocalName tip() { + return this; + } + + /** + * Returns {@code this} since the {@linkplain #scope() scope} of this name + * is already {@linkplain NameSpace#isGlobal() global}. + * + * @return the fully-qualified name (never {@code null}). + */ + @Override + public GenericName toFullyQualifiedName() { + return this; + } + + /** + * Returns the scope (name space) in which this name is local. + * Current implementation assumes that all names are local in the global scope. + * + * @return the scope of this name. + */ + @Override + public final NameSpace scope() { + return this; + } + + /** + * Indicates whether this namespace is a "top level" namespace. Global, or top-level + * namespaces are not contained within another namespace. The global namespace has no + * parent. + * + * @return {@code true} if this namespace is the global namespace. + */ + @Override + public boolean isGlobal() { + return true; + } + + /** + * Represents the identifier of this namespace. + * + * @return the identifier of this namespace. + */ + @Override + public GenericName name() { + return null; + } + + /** + * Unsupported operation. If supported, this method would have expanded this name with the specified scope. + * One may represent this operation as a concatenation of the specified {@code scope} with {@code this}. + * + * @param scope the name to use as prefix. + * @return a concatenation of the given scope with this name. + */ + @Override + public final ScopedName push(GenericName scope) { + throw new UnsupportedOperationException("Not supported yet."); + } + + /** + * Compares this name with an other name for order. + * + * @param other the other object to be compared to this name. + * @return a negative integer, zero, or a positive integer as this name is lexicographically + * less than, equal to, or greater than the specified name. + */ + @Override + public final int compareTo(final GenericName other) { + return name.compareTo(other.toString()); + } + + /** + * Returns a locale-independent string representation of this local name. + * + * @return the local-independent string representation of this name. + */ + @Override + public final String toString() { + return name; + } + + /** + * Returns a local-dependent string representation of this generic name. + * Current implementation supports only one locale, the default one. + * + * @return a localizable string representation of this name. + */ + @Override + public final InternationalString toInternationalString() { + return new SimpleCitation(name); + } +} From 555f2ccab14d49919d8d2298ab1364788175a6e0 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Sun, 28 Jun 2020 15:54:23 +0200 Subject: [PATCH 5/5] Add tests of WKT parsing. The WKT string are copied from OGC specification and can be viewed there: http://www.geoapi.org/conformance/java/org/opengis/test/wkt/CRSParserTest.html#testGeographic3D() --- .../kortforsyningen/proj/WKTParserTest.java | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 src/test/java/org/kortforsyningen/proj/WKTParserTest.java diff --git a/src/test/java/org/kortforsyningen/proj/WKTParserTest.java b/src/test/java/org/kortforsyningen/proj/WKTParserTest.java new file mode 100644 index 0000000..3c8a652 --- /dev/null +++ b/src/test/java/org/kortforsyningen/proj/WKTParserTest.java @@ -0,0 +1,146 @@ +/* + * Copyright © 2019 Agency for Data Supply and Efficiency + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.kortforsyningen.proj; + +import org.junit.FixMethodOrder; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; +import org.opengis.test.wkt.CRSParserTest; + + + +/** + * Tests Well-Known Text parser using the tests defined in GeoAPI. + * + * @author Martin Desruisseaux (Geomatys) + * @version 2.0 + * @since 2.0 + */ +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.JVM) // Intentionally want some randomness +public final strictfp class WKTParserTest extends CRSParserTest { + /** + * Creates a new test case using the default {@code CRSFactory} implementation. + */ + public WKTParserTest() { + super(ObjectFactory.INSTANCE); + /* + * ISO 19111:2007 said that axis names shall be "geodetic latitude" and "geodetic longitude", + * but PROJ keep "latitude" and "longitude" names as they appear in the WKT string. + */ + validators.crs.enforceStandardNames = false; + } + + /** + * Skip test having a PROJ error. Error message is: + * {@literal "Missing EDATUM / ENGINEERINGDATUM node"}. + */ + @Ignore + @Override + public void testTemporal() { + } + + /** + * Skip test having a PROJ error. Error message is: + * {@literal "unexpected TIMEUNIT"}. + */ + @Ignore + @Override + public void testCompoundWithTime() { + } + + /** + * Skip test having a PROJ error. Error message is: + * {@literal "Missing EDATUM / ENGINEERINGDATUM node"}. + */ + @Ignore + @Override + public void testDerivedEngineeringFromGeodetic() { + } + + /** + * Skip test having a PROJ error. Error message is: + * {@literal "Missing EDATUM / ENGINEERINGDATUM node"}. + */ + @Ignore + @Override + public void testDerivedEngineeringFromProjected() { + } + + /** + * Skip test having a PROJ error. Error message is: + * {@literal "Parsing error : syntax error, unexpected PRIMEM, expecting ID"}. + */ + @Ignore + @Override + public void testProjectedWithImplicitParameterUnits() { + } + + /** + * Skip test failing validation. Error message is: + * {@literal "(…) is of type Geographic while the expected type was DerivedCRS or a subtype"}. + */ + @Ignore + @Override + public void testDerivedGeodetic() { + } + + /** + * Skip test failing validation. Error message is: + * {@literal "CoordinateSystemAxis: abbreviation is mandatory"}. + */ + @Ignore + @Override + public void testEngineeringRotated() { + } + + /** + * Skip test having a GeoAPI test failure. Error message is: + * {@literal "CoordinateSystem.getAxis(*).getUnit() expected: but was:"}. + */ + @Ignore + @Override + public void testProjectedWithFootUnits() { + } + + /** + * Skip test having a PROJ-JNI limitation. Error message is: + * {@literal "The PROJ-JNI binding provides only minimal support for Unit of Measurement operations. + * For more advanced operations, a JSR-363 implementation should be added to the classpath."}. + */ + @Ignore + @Override + public void testParametric() { + } + + /** + * Skip test having a PROJ-JNI limitation. Error message is: + * {@literal "The PROJ-JNI binding provides only minimal support for Unit of Measurement operations. + * For more advanced operations, a JSR-363 implementation should be added to the classpath."}. + */ + @Ignore + @Override + public void testCompoundWithParametric() { + } +}