use of org.opengis.referencing.crs.CompoundCRS in project sis by apache.
the class MultiAuthoritiesFactoryTest method testCreateFromCombinedURIs.
/**
* Implementation of {@link #testCreateFromCombinedURNs()} and {@link #testCreateFromCombinedHTTPs()}.
*/
private static void testCreateFromCombinedURIs(final MultiAuthoritiesFactory factory, final String heightOnWGS84) throws FactoryException {
CompoundCRS crs = factory.createCompoundCRS(heightOnWGS84);
assertArrayEquals("WGS 84 + MSL height", new SingleCRS[] { HardCodedCRS.WGS84_φλ, HardCodedCRS.GRAVITY_RELATED_HEIGHT }, crs.getComponents().toArray());
}
use of org.opengis.referencing.crs.CompoundCRS 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;
}
use of org.opengis.referencing.crs.CompoundCRS in project sis by apache.
the class CRS method getVerticalComponent.
/**
* Returns the first vertical coordinate reference system found in the given CRS, or {@code null} if there is none.
* If the given CRS is already an instance of {@code VerticalCRS}, then this method returns it as-is.
* Otherwise if the given CRS is compound, then this method searches for the first vertical component
* in the order of the {@linkplain #getSingleComponents(CoordinateReferenceSystem) single components list}.
*
* <div class="section">Height in a three-dimensional geographic CRS</div>
* In ISO 19111 model, ellipsoidal heights are indissociable from geographic CRS because such heights
* without their (<var>latitude</var>, <var>longitude</var>) locations make little sense. Consequently
* a standard-conformant library should return {@code null} when asked for the {@code VerticalCRS}
* component of a geographic CRS. This is what {@code getVerticalComponent(…)} does when the
* {@code allowCreateEllipsoidal} argument is {@code false}.
*
* <p>However in some exceptional cases, handling ellipsoidal heights like any other kind of heights
* may simplify the task. For example when computing <em>difference</em> between heights above the
* same datum, the impact of ignoring locations may be smaller (but not necessarily canceled).
* Orphan {@code VerticalCRS} may also be useful for information purpose like labeling a plot axis.
* If the caller feels confident that ellipsoidal heights are safe for his task, he can set the
* {@code allowCreateEllipsoidal} argument to {@code true}. In such case, this {@code getVerticalComponent(…)}
* method will create a temporary {@code VerticalCRS} from the first three-dimensional {@code GeographicCRS}
* <em>in last resort</em>, only if it can not find an existing {@code VerticalCRS} instance.
* <strong>Note that this is not a valid CRS according ISO 19111</strong> — use with care.</p>
*
* @param crs the coordinate reference system, or {@code null}.
* @param allowCreateEllipsoidal {@code true} for allowing the creation of orphan CRS for ellipsoidal heights.
* The recommended value is {@code false}.
* @return the first vertical CRS, or {@code null} if none.
*
* @see #compound(CoordinateReferenceSystem...)
*
* @category information
*/
public static VerticalCRS getVerticalComponent(final CoordinateReferenceSystem crs, final boolean allowCreateEllipsoidal) {
if (crs instanceof VerticalCRS) {
return (VerticalCRS) crs;
}
if (crs instanceof CompoundCRS) {
final CompoundCRS cp = (CompoundCRS) crs;
boolean a = false;
do {
// Executed at most twice.
for (final CoordinateReferenceSystem c : cp.getComponents()) {
final VerticalCRS candidate = getVerticalComponent(c, a);
if (candidate != null) {
return candidate;
}
}
} while ((a = !a) == allowCreateEllipsoidal);
}
if (allowCreateEllipsoidal && horizontalCode(crs) == 3) {
final CoordinateSystem cs = crs.getCoordinateSystem();
final int i = AxisDirections.indexOfColinear(cs, AxisDirection.UP);
if (i >= 0) {
final CoordinateSystemAxis axis = cs.getAxis(i);
VerticalCRS c = CommonCRS.Vertical.ELLIPSOIDAL.crs();
if (!c.getCoordinateSystem().getAxis(0).equals(axis)) {
final Map<String, ?> properties = IdentifiedObjects.getProperties(c);
c = new DefaultVerticalCRS(properties, c.getDatum(), new DefaultVerticalCS(properties, axis));
}
return c;
}
}
return null;
}
use of org.opengis.referencing.crs.CompoundCRS in project sis by apache.
the class SubTypes method castOrCopy.
/**
* Returns a SIS implementation for the given coordinate reference system.
*
* @see AbstractCRS#castOrCopy(CoordinateReferenceSystem)
*/
static AbstractCRS castOrCopy(final CoordinateReferenceSystem object) {
if (object instanceof DerivedCRS) {
return DefaultDerivedCRS.castOrCopy((DerivedCRS) object);
}
if (object instanceof ProjectedCRS) {
return DefaultProjectedCRS.castOrCopy((ProjectedCRS) object);
}
if (object instanceof GeodeticCRS) {
if (object instanceof GeographicCRS) {
return DefaultGeographicCRS.castOrCopy((GeographicCRS) object);
}
if (object instanceof GeocentricCRS) {
return DefaultGeocentricCRS.castOrCopy((GeocentricCRS) object);
}
/*
* The GeographicCRS and GeocentricCRS types are not part of ISO 19111.
* ISO uses a single type, GeodeticCRS, for both of them and infer the
* geographic or geocentric type from the coordinate system. We do this
* check here for instantiating the most appropriate SIS type, but only
* if we need to create a new object anyway (see below for rational).
*/
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 Map<String, ?> properties = IdentifiedObjects.getProperties(object);
final GeodeticDatum datum = ((GeodeticCRS) object).getDatum();
final CoordinateSystem cs = object.getCoordinateSystem();
if (cs instanceof EllipsoidalCS) {
return new DefaultGeographicCRS(properties, datum, (EllipsoidalCS) cs);
}
if (cs instanceof SphericalCS) {
return new DefaultGeocentricCRS(properties, datum, (SphericalCS) cs);
}
if (cs instanceof CartesianCS) {
return new DefaultGeocentricCRS(properties, datum, (CartesianCS) cs);
}
}
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 ImageCRS) {
return DefaultImageCRS.castOrCopy((ImageCRS) 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);
}
use of org.opengis.referencing.crs.CompoundCRS in project sis by apache.
the class DefaultPassThroughOperation method getModifiedCoordinates.
/**
* Returns the ordered sequence of indices in a source coordinate tuple of the coordinates
* affected by this pass-through operation.
*
* @return zero-based indices of the modified source coordinates.
*
* @see PassThroughTransform#getModifiedCoordinates()
*/
@Override
public int[] getModifiedCoordinates() {
final MathTransform transform = super.getMathTransform();
if (transform instanceof PassThroughTransform) {
return ((PassThroughTransform) transform).getModifiedCoordinates();
} else {
/*
* Should not happen with objects created by public methods since the constructor created the transform
* itself. However may happen with operations parsed from GML. As a fallback, search in the components
* of CompoundCRS. This is not a universal fallback, but work for the most straightforward cases.
*/
final CoordinateReferenceSystem sourceCRS = super.getSourceCRS();
if (sourceCRS instanceof CompoundCRS) {
int firstAffectedOrdinate = 0;
final CoordinateReferenceSystem search = operation.getSourceCRS();
for (final CoordinateReferenceSystem c : ((CompoundCRS) sourceCRS).getComponents()) {
final int dim = ReferencingUtilities.getDimension(c);
if (c == search) {
final int[] indices = new int[dim];
for (int i = 0; i < dim; i++) {
indices[i] = firstAffectedOrdinate + i;
}
return indices;
}
firstAffectedOrdinate += dim;
}
}
throw new UnsupportedImplementationException(transform.getClass());
}
}
Aggregations