Search in sources :

Example 11 with IdentifiedObject

use of org.opengis.referencing.IdentifiedObject in project sis by apache.

the class Formatter method appendComplement.

/**
 * Appends the optional complementary attributes common to many {@link IdentifiedObject} subtypes.
 * Those attributes are {@code ANCHOR}, {@code SCOPE}, {@code AREA}, {@code BBOX}, {@code VERTICALEXTENT},
 * {@code TIMEEXTENT}, {@code ID} (previously known as {@code AUTHORITY}) and {@code REMARKS},
 * and have a special treatment: they are written by {@link #append(FormattableObject)}
 * after the {@code formatTo(Formatter)} method returned.
 *
 * <p>The {@code ID[<name>,<code>,…]} element is normally written only for the root element
 * (unless the convention is {@code INTERNAL}), but there is various exceptions to this rule.
 * If formatted, the {@code ID} element will be by default on the same line than the enclosing
 * element (e.g. {@code SPHEROID["Clarke 1866", …, ID["EPSG", 7008]]}). Other example:</p>
 *
 * {@preformat text
 *   PROJCS["NAD27 / Idaho Central",
 *     GEOGCS[...etc...],
 *     ...etc...
 *     ID["EPSG", 26769]]
 * }
 *
 * For non-internal conventions, all elements other than {@code ID[…]} are formatted
 * only for {@link CoordinateOperation} and root {@link ReferenceSystem} instances,
 * with an exception for remarks of {@code ReferenceSystem} embedded inside {@code CoordinateOperation}.
 * Those restrictions are our interpretation of the following ISO 19162 requirement:
 *
 * <blockquote>(…snip…) {@code <scope extent identifier remark>} is a collection of four optional attributes
 * which may be applied to a coordinate reference system, a coordinate operation or a boundCRS. (…snip…)
 * Identifier (…snip…) may also be utilised for components of these objects although this is not recommended
 * except for coordinate operation methods (including map projections) and parameters. (…snip…)
 * A {@code <remark>} can be included within the descriptions of source and target CRS embedded within
 * a coordinate transformation as well as within the coordinate transformation itself.</blockquote>
 */
@SuppressWarnings("null")
private void appendComplement(final IdentifiedObject object, final FormattableObject parent, final FormattableObject gp) {
    isComplement = true;
    // Whether to format ID[…] elements.
    final boolean showIDs;
    // Whether we shall limit to a single ID[…] element.
    final boolean filterID;
    // Whether to format any element other than ID[…] and Remarks[…].
    final boolean showOthers;
    // Whether to format Remarks[…].
    final boolean showRemarks;
    if (convention == Convention.INTERNAL) {
        showIDs = true;
        filterID = false;
        showOthers = true;
        showRemarks = true;
    } else {
        /*
             * Except for the special cases of OperationMethod and Parameters, ISO 19162 recommends to format the
             * ID only for the root element.  But Apache SIS adds an other exception to this rule by handling the
             * components of CompoundCRS as if they were root elements. The reason is that users often create their
             * own CompoundCRS from standard components, for example by adding a time axis to some standard CRS like
             * "WGS84". The resulting CompoundCRS usually have no identifier. Then the users often need to extract a
             * particular component of a CompoundCRS, most often the horizontal part, and will need its identifier
             * for example in a Web Map Service (WMS). Those ID are lost if we do not format them here.
             */
        if (parent == null || parent instanceof CompoundCRS) {
            showIDs = true;
        } else if (gp instanceof CoordinateOperation && !(parent instanceof IdentifiedObject)) {
            // "SourceCRS[…]" and "TargetCRS[…]" sub-elements in CoordinateOperation.
            showIDs = true;
        } else if (convention == Convention.WKT2_SIMPLIFIED) {
            showIDs = false;
        } else {
            showIDs = (object instanceof OperationMethod) || (object instanceof GeneralParameterDescriptor);
        }
        if (convention.majorVersion() == 1) {
            filterID = true;
            showOthers = false;
            showRemarks = false;
        } else {
            filterID = (parent != null);
            if (object instanceof CoordinateOperation) {
                showOthers = !(parent instanceof ConcatenatedOperation);
                showRemarks = showOthers;
            } else if (object instanceof ReferenceSystem) {
                showOthers = (parent == null);
                showRemarks = (parent == null) || (gp instanceof CoordinateOperation);
            } else {
                // Mandated by ISO 19162.
                showOthers = false;
                showRemarks = false;
            }
        }
    }
    if (showOthers) {
        appendForSubtypes(object);
    }
    if (showIDs) {
        Collection<ReferenceIdentifier> identifiers = object.getIdentifiers();
        if (identifiers != null) {
            // Paranoiac check
            if (filterID) {
                for (final ReferenceIdentifier id : identifiers) {
                    if (Citations.identifierMatches(authority, id.getAuthority())) {
                        identifiers = Collections.singleton(id);
                        break;
                    }
                }
            }
            for (ReferenceIdentifier id : identifiers) {
                if (!(id instanceof FormattableObject)) {
                    id = ImmutableIdentifier.castOrCopy(id);
                }
                append((FormattableObject) id);
                if (filterID)
                    break;
            }
        }
    }
    if (showRemarks) {
        appendOnNewLine(WKTKeywords.Remark, object.getRemarks(), ElementKind.REMARKS);
    }
    isComplement = false;
}
Also used : ReferenceIdentifier(org.opengis.referencing.ReferenceIdentifier) CompoundCRS(org.opengis.referencing.crs.CompoundCRS) GeneralParameterDescriptor(org.opengis.parameter.GeneralParameterDescriptor) CoordinateOperation(org.opengis.referencing.operation.CoordinateOperation) ConcatenatedOperation(org.opengis.referencing.operation.ConcatenatedOperation) IdentifiedObject(org.opengis.referencing.IdentifiedObject) ReferenceSystem(org.opengis.referencing.ReferenceSystem) OperationMethod(org.opengis.referencing.operation.OperationMethod)

Example 12 with IdentifiedObject

use of org.opengis.referencing.IdentifiedObject in project sis by apache.

the class EPSGDataAccess method createObject.

/**
 * Returns an arbitrary object from a code. The default implementation delegates to more specific methods,
 * for example {@link #createCoordinateReferenceSystem(String)}, {@link #createDatum(String)}, <i>etc.</i>
 * until a successful one is found.
 *
 * <p><strong>Note that this method may be ambiguous</strong> since the same EPSG code can be used for different
 * kind of objects. This method throws an exception if it detects an ambiguity on a <em>best-effort</em> basis.
 * It is recommended to invoke the most specific {@code createFoo(String)} method when the desired type is known,
 * both for performance reason and for avoiding ambiguity.</p>
 *
 * @param  code  value allocated by EPSG.
 * @return the object for the given code.
 * @throws NoSuchAuthorityCodeException if the specified {@code code} was not found.
 * @throws FactoryException if the object creation failed for some other reason.
 *
 * @see #createCoordinateReferenceSystem(String)
 * @see #createDatum(String)
 * @see #createCoordinateSystem(String)
 */
@Override
public synchronized IdentifiedObject createObject(final String code) throws NoSuchAuthorityCodeException, FactoryException {
    ArgumentChecks.ensureNonNull("code", code);
    final boolean isPrimaryKey = isPrimaryKey(code);
    final StringBuilder query = new StringBuilder("SELECT ");
    final int queryStart = query.length();
    int found = -1;
    try {
        final int pk = isPrimaryKey ? toPrimaryKeys(null, null, null, code)[0] : 0;
        for (int i = 0; i < TableInfo.EPSG.length; i++) {
            final TableInfo table = TableInfo.EPSG[i];
            final String column = isPrimaryKey ? table.codeColumn : table.nameColumn;
            if (column == null) {
                continue;
            }
            query.setLength(queryStart);
            query.append(table.codeColumn);
            if (!isPrimaryKey) {
                // Only for filterFalsePositive(…).
                query.append(", ").append(column);
            }
            query.append(" FROM ").append(table.table).append(" WHERE ").append(column).append(isPrimaryKey ? " = ?" : " LIKE ?");
            try (PreparedStatement stmt = connection.prepareStatement(translator.apply(query.toString()))) {
                /*
                     * Check if at least one record is found for the code or the name.
                     * Ensure that there is not two values for the same code or name.
                     */
                if (isPrimaryKey) {
                    stmt.setInt(1, pk);
                } else {
                    stmt.setString(1, toLikePattern(code));
                }
                Integer present = null;
                try (ResultSet result = stmt.executeQuery()) {
                    while (result.next()) {
                        if (isPrimaryKey || SQLUtilities.filterFalsePositive(code, result.getString(2))) {
                            present = ensureSingleton(getOptionalInteger(result, 1), present, code);
                        }
                    }
                }
                if (present != null) {
                    if (found >= 0) {
                        throw new FactoryDataException(error().getString(Errors.Keys.DuplicatedIdentifier_1, code));
                    }
                    found = i;
                }
            }
        }
    } catch (SQLException exception) {
        throw databaseFailure(IdentifiedObject.class, code, exception);
    }
    /*
         * If a record has been found in one table, then delegates to the appropriate method.
         */
    if (found >= 0) {
        switch(found) {
            case 0:
                return createCoordinateReferenceSystem(code);
            case 1:
                return createCoordinateSystem(code);
            case 2:
                return createCoordinateSystemAxis(code);
            case 3:
                return createDatum(code);
            case 4:
                return createEllipsoid(code);
            case 5:
                return createPrimeMeridian(code);
            case 6:
                return createCoordinateOperation(code);
            case 7:
                return createOperationMethod(code);
            case 8:
                return createParameterDescriptor(code);
            // Can not cast Unit to IdentifiedObject
            case 9:
                break;
            // Should not happen
            default:
                throw new AssertionError(found);
        }
    }
    throw noSuchAuthorityCode(IdentifiedObject.class, code);
}
Also used : FactoryDataException(org.apache.sis.referencing.factory.FactoryDataException) SQLException(java.sql.SQLException) ResultSet(java.sql.ResultSet) PreparedStatement(java.sql.PreparedStatement) InternationalString(org.opengis.util.InternationalString) SimpleInternationalString(org.apache.sis.util.iso.SimpleInternationalString) AbstractIdentifiedObject(org.apache.sis.referencing.AbstractIdentifiedObject) IdentifiedObject(org.opengis.referencing.IdentifiedObject)

Example 13 with IdentifiedObject

use of org.opengis.referencing.IdentifiedObject in project sis by apache.

the class CoordinateOperationRegistry method toAuthorityDefinition.

/**
 * If the authority defines an object equal, ignoring metadata, to the given object, returns that authority object.
 * Otherwise returns the given object unchanged. We do not invoke this method for user-supplied CRS, but only for
 * CRS or other objects created by {@code CoordinateOperationRegistry} as intermediate step.
 */
final <T extends IdentifiedObject> T toAuthorityDefinition(final Class<T> type, final T object) throws FactoryException {
    if (codeFinder != null) {
        codeFinder.setIgnoringAxes(false);
        final IdentifiedObject candidate = codeFinder.findSingleton(object);
        codeFinder.setIgnoringAxes(true);
        if (Utilities.equalsIgnoreMetadata(object, candidate)) {
            return type.cast(candidate);
        }
    }
    return object;
}
Also used : IdentifiedObject(org.opengis.referencing.IdentifiedObject) AbstractIdentifiedObject(org.apache.sis.referencing.AbstractIdentifiedObject)

Example 14 with IdentifiedObject

use of org.opengis.referencing.IdentifiedObject in project sis by apache.

the class CoordinateOperationRegistry method recreate.

/**
 * Creates a new coordinate operation with the same method than the given operation, but different CRS.
 * The CRS may differ either in the number of dimensions (i.e. let the vertical coordinate pass through),
 * or in axis order (i.e. axis order in user CRS were not compliant with authority definition).
 *
 * @param  operation  the operation specified by the authority.
 * @param  sourceCRS  the source CRS specified by the user.
 * @param  targetCRS  the target CRS specified by the user
 * @param  transform  the math transform to use in replacement to the one in {@code operation}.
 * @param  method     the operation method, or {@code null} for attempting an automatic detection.
 * @return a new operation from the given source CRS to target CRS using the given transform.
 * @throws IllegalArgumentException if the operation method can not have the desired number of dimensions.
 * @throws FactoryException if an error occurred while creating the new operation.
 */
private CoordinateOperation recreate(final CoordinateOperation operation, CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, final MathTransform transform, OperationMethod method) throws IllegalArgumentException, FactoryException {
    /*
         * If the user-provided CRS are approximatively equal to the coordinate operation CRS, keep the later.
         * The reason is that coordinate operation CRS are built from the definitions provided by the authority,
         * while the user-provided CRS can be anything (e.g. parsed from a quite approximative WKT).
         */
    CoordinateReferenceSystem crs;
    if (Utilities.equalsApproximatively(sourceCRS, crs = operation.getSourceCRS()))
        sourceCRS = crs;
    if (Utilities.equalsApproximatively(targetCRS, crs = operation.getTargetCRS()))
        targetCRS = crs;
    final Map<String, Object> properties = new HashMap<>(derivedFrom(operation));
    /*
         * Determine whether the operation to create is a Conversion or a Transformation
         * (could also be a Conversion subtype like Projection, but this is less important).
         * We want the GeoAPI interface, not the implementation class.
         * The most reliable way is to ask to the 'AbstractOperation.getInterface()' method,
         * but this is SIS-specific. The fallback uses reflection.
         */
    final Class<? extends IdentifiedObject> type;
    if (operation instanceof AbstractIdentifiedObject) {
        type = ((AbstractIdentifiedObject) operation).getInterface();
    } else {
        type = Classes.getLeafInterfaces(operation.getClass(), CoordinateOperation.class)[0];
    }
    properties.put(ReferencingServices.OPERATION_TYPE_KEY, type);
    /*
         * Reuse the same operation method, but we may need to change its number of dimension.
         * The capability to resize an OperationMethod is specific to Apache SIS, so we must
         * be prepared to see the 'redimension' call fails. In such case, we will try to get
         * the SIS implementation of the operation method and try again.
         */
    if (SubTypes.isSingleOperation(operation)) {
        final SingleOperation single = (SingleOperation) operation;
        properties.put(ReferencingServices.PARAMETERS_KEY, single.getParameterValues());
        if (method == null) {
            final int sourceDimensions = transform.getSourceDimensions();
            final int targetDimensions = transform.getTargetDimensions();
            method = single.getMethod();
            try {
                method = DefaultOperationMethod.redimension(method, sourceDimensions, targetDimensions);
            } catch (IllegalArgumentException ex) {
                try {
                    method = factorySIS.getOperationMethod(method.getName().getCode());
                    method = DefaultOperationMethod.redimension(method, sourceDimensions, targetDimensions);
                } catch (NoSuchIdentifierException | IllegalArgumentException se) {
                    ex.addSuppressed(se);
                    throw ex;
                }
            }
        }
    }
    return factorySIS.createSingleOperation(properties, sourceCRS, targetCRS, AbstractCoordinateOperation.getInterpolationCRS(operation), method, transform);
}
Also used : AbstractIdentifiedObject(org.apache.sis.referencing.AbstractIdentifiedObject) HashMap(java.util.HashMap) IdentifiedObject(org.opengis.referencing.IdentifiedObject) AbstractIdentifiedObject(org.apache.sis.referencing.AbstractIdentifiedObject) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem)

Example 15 with IdentifiedObject

use of org.opengis.referencing.IdentifiedObject in project sis by apache.

the class IdentifiedObjectFinder method findSingleton.

/**
 * Lookups only one object which is approximatively equal to the specified object.
 * This method invokes {@link #find(IdentifiedObject)}, then examine the returned {@code Set} as below:
 *
 * <ul>
 *   <li>If the set is empty, then this method returns {@code null}.</li>
 *   <li>If the set contains exactly one element, then this method returns that element.</li>
 *   <li>If the set contains more than one element, but only one element has the same axis order
 *       than {@code object} and all other elements have different axis order,
 *       then this method returns the single element having the same axis order.</li>
 *   <li>Otherwise this method considers that there is ambiguity and returns {@code null}.</li>
 * </ul>
 *
 * @param  object  the object looked up.
 * @return the identified object, or {@code null} if none or ambiguous.
 * @throws FactoryException if an error occurred while creating an object.
 */
public IdentifiedObject findSingleton(final IdentifiedObject object) throws FactoryException {
    /*
         * Do not invoke Set.size() because it may be a costly operation if the subclass
         * implements a mechanism that create IdentifiedObject instances only on demand.
         */
    IdentifiedObject result = null;
    boolean sameAxisOrder = false;
    boolean ambiguous = false;
    try {
        for (final IdentifiedObject candidate : find(object)) {
            final boolean so = !ignoreAxes || Utilities.deepEquals(candidate, object, COMPARISON_MODE);
            if (result != null) {
                ambiguous = true;
                if (sameAxisOrder && so) {
                    // Found two matches even when taking in account axis order.
                    return null;
                }
            }
            result = candidate;
            sameAxisOrder = so;
        }
    } catch (BackingStoreException e) {
        throw e.unwrapOrRethrow(FactoryException.class);
    }
    return (sameAxisOrder || !ambiguous) ? result : null;
}
Also used : FactoryException(org.opengis.util.FactoryException) BackingStoreException(org.apache.sis.util.collection.BackingStoreException) IdentifiedObject(org.opengis.referencing.IdentifiedObject) AbstractIdentifiedObject(org.apache.sis.referencing.AbstractIdentifiedObject)

Aggregations

IdentifiedObject (org.opengis.referencing.IdentifiedObject)30 AbstractIdentifiedObject (org.apache.sis.referencing.AbstractIdentifiedObject)15 InternationalString (org.opengis.util.InternationalString)10 FactoryException (org.opengis.util.FactoryException)8 IllegalArgumentException (com.sun.star.lang.IllegalArgumentException)5 IdentifiedObjectFinder (org.apache.sis.referencing.factory.IdentifiedObjectFinder)5 DataStoreException (org.apache.sis.storage.DataStoreException)5 Identifier (org.opengis.metadata.Identifier)5 ReferenceIdentifier (org.opengis.referencing.ReferenceIdentifier)5 CoordinateReferenceSystem (org.opengis.referencing.crs.CoordinateReferenceSystem)5 HashMap (java.util.HashMap)4 Cache (org.apache.sis.util.collection.Cache)3 Test (org.junit.Test)3 GenericName (org.opengis.util.GenericName)3 NameToIdentifier (org.apache.sis.internal.metadata.NameToIdentifier)2 FormattableObject (org.apache.sis.io.wkt.FormattableObject)2 NamedIdentifier (org.apache.sis.referencing.NamedIdentifier)2 DependsOnMethod (org.apache.sis.test.DependsOnMethod)2 SimpleInternationalString (org.apache.sis.util.iso.SimpleInternationalString)2 Extent (org.opengis.metadata.extent.Extent)2