blob: e02e655b7522d71e95ea6270fb74fde51407c0b8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sis.referencing.crs;
import java.util.Comparator;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.CompoundCRS;
import org.opengis.referencing.crs.DerivedCRS;
import org.opengis.referencing.crs.EngineeringCRS;
import org.opengis.referencing.crs.GeodeticCRS;
import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.referencing.crs.TemporalCRS;
import org.opengis.referencing.crs.VerticalCRS;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.cs.SphericalCS;
import org.apache.sis.referencing.cs.AxesConvention;
/**
* Implementation of {@link AbstractCRS} methods that require knowledge about subclasses.
* Those methods are defined in a separated static class for avoiding class loading of all
* coordinate reference system implementations before necessary.
*
* <p>This class currently provides implementation for the following methods:</p>
* <ul>
* <li>{@link AbstractCRS#castOrCopy(CoordinateReferenceSystem)}</li>
* <li>{@link DefaultCompoundCRS#forConvention(AxesConvention)}</li>
* </ul>
*
* @author Martin Desruisseaux (Geomatys)
*/
final class SubTypes implements Comparator<Object> {
/**
* CRS types to sort first in a compound CRS. Any type not in this list will be sorted last.
* Used for implementation of {@link #BY_TYPE} comparator.
*/
private static final Class<?>[] TYPE_ORDER = {
ProjectedCRS.class,
GeodeticCRS.class,
VerticalCRS.class,
TemporalCRS.class
};
/**
* A comparator for sorting CRS objects by their types.
* The comparison sorts projected CRS first, followed by geodetic, vertical then temporal CRS.
*/
static final Comparator<Object> BY_TYPE = new SubTypes();
/**
* Do not allow instantiation of this class (except the singleton).
*/
private SubTypes() {
}
/**
* Returns the index of the interface implemented by the given object.
*/
private static int indexOf(final Object object) {
int i = 0;
while (i < TYPE_ORDER.length) {
if (TYPE_ORDER[i].isInstance(object)) {
break;
}
i++;
}
return i;
}
/**
* Implementation of {@link #BY_TYPE} comparator.
*/
@Override
public int compare(final Object o1, final Object o2) {
return indexOf(o1) - indexOf(o2);
}
/**
* Returns a SIS implementation for the given coordinate reference system.
*
* @see AbstractCRS#castOrCopy(CoordinateReferenceSystem)
*/
@SuppressWarnings("deprecation")
static AbstractCRS castOrCopy(final CoordinateReferenceSystem object) {
if (object instanceof ProjectedCRS) {
return DefaultProjectedCRS.castOrCopy((ProjectedCRS) object);
}
if (object instanceof DerivedCRS) { // Shall be tested after ProjectedCRS.
return DefaultDerivedCRS.castOrCopy((DerivedCRS) object);
}
if (object instanceof GeodeticCRS) {
if (object instanceof DefaultGeodeticCRS) {
/*
* Result of XML unmarshalling — keep as-is. We avoid creating a new object because it
* would break object identities specified in GML document by the xlink:href attribute.
* However, we may revisit this policy in the future. See SC_CRS.setElement(AbstractCRS).
*/
return (DefaultGeodeticCRS) object;
}
final var crs = (GeodeticCRS) object;
final CoordinateSystem cs = crs.getCoordinateSystem();
if (cs instanceof EllipsoidalCS) {
return new DefaultGeographicCRS(crs);
}
if (cs instanceof CartesianCS || cs instanceof SphericalCS) {
return new DefaultGeocentricCRS(crs);
}
}
if (object instanceof VerticalCRS) {
return DefaultVerticalCRS.castOrCopy((VerticalCRS) object);
}
if (object instanceof TemporalCRS) {
return DefaultTemporalCRS.castOrCopy((TemporalCRS) object);
}
if (object instanceof EngineeringCRS) {
return DefaultEngineeringCRS.castOrCopy((EngineeringCRS) object);
}
if (object instanceof CompoundCRS) {
return DefaultCompoundCRS.castOrCopy((CompoundCRS) object);
}
/*
* Intentionally check for AbstractCRS after the interfaces because user may have defined his own
* subclass implementing the interface. If we were checking for AbstractCRS before the interfaces,
* the returned instance could have been a user subclass without the JAXB annotations required
* for XML marshalling.
*/
if (object == null || object instanceof AbstractCRS) {
return (AbstractCRS) object;
}
return new AbstractCRS(object);
}
}