use of org.opengis.referencing.crs.VerticalCRS in project sis by apache.
the class EllipsoidalHeightCombiner method createCompoundCRS.
/**
* Creates a compound CRS, but we special processing for (two-dimensional Geographic + ellipsoidal heights) tupples.
* If any such tupple is found, a three-dimensional geographic CRS is created instead than the compound CRS.
*
* @param properties name and other properties to give to the new object.
* @param components ordered array of {@code CoordinateReferenceSystem} objects.
* @return the coordinate reference system for the given properties.
* @throws FactoryException if the object creation failed.
*/
public final CoordinateReferenceSystem createCompoundCRS(final Map<String, ?> properties, CoordinateReferenceSystem... components) throws FactoryException {
for (int i = 0; i < components.length; i++) {
final CoordinateReferenceSystem vertical = components[i];
if (vertical instanceof VerticalCRS) {
final VerticalDatum datum = ((VerticalCRS) vertical).getDatum();
if (datum != null && datum.getVerticalDatumType() == VerticalDatumTypes.ELLIPSOIDAL) {
int axisPosition = 0;
CoordinateSystem cs = null;
CoordinateReferenceSystem crs = null;
if (i == 0 || (cs = getCsIfHorizontal2D(crs = components[i - 1])) == null) {
/*
* GeographicCRS are normally before VerticalCRS. But Apache SIS is tolerant to the
* opposite order (note however that such ordering is illegal according ISO 19162).
*/
if (i + 1 >= components.length || (cs = getCsIfHorizontal2D(crs = components[i + 1])) == null) {
continue;
}
axisPosition = 1;
}
/*
* At this point we have the horizontal and vertical components. The horizontal component
* begins at 'axisPosition', which is almost always zero. Create the three-dimensional CRS.
* If the result is the CRS to be returned directly by this method (components.length == 2),
* use the properties given in argument. Otherwise we need to use other properties; current
* implementation recycles the properties of the existing two-dimensional CRS.
*/
final CoordinateSystemAxis[] axes = new CoordinateSystemAxis[3];
axes[axisPosition++] = cs.getAxis(0);
axes[axisPosition++] = cs.getAxis(1);
axes[axisPosition %= 3] = vertical.getCoordinateSystem().getAxis(0);
final ReferencingServices referencing = ReferencingServices.getInstance();
final Map<String, ?> csProps = referencing.getProperties(cs, false);
final Map<String, ?> crsProps = (components.length == 2) ? properties : referencing.getProperties(crs, false);
if (crs instanceof GeodeticCRS) {
initialize(CS | CRS);
cs = csFactory.createEllipsoidalCS(csProps, axes[0], axes[1], axes[2]);
crs = crsFactory.createGeographicCRS(crsProps, ((GeodeticCRS) crs).getDatum(), (EllipsoidalCS) cs);
} else {
initialize(CS | CRS | OPERATION);
final ProjectedCRS proj = (ProjectedCRS) crs;
GeographicCRS base = proj.getBaseCRS();
if (base.getCoordinateSystem().getDimension() == 2) {
base = (GeographicCRS) createCompoundCRS(referencing.getProperties(base, false), base, vertical);
}
/*
* In Apache SIS implementation, the Conversion contains the source and target CRS together with
* a MathTransform2D. We need to recreate the same conversion, but without CRS and MathTransform
* for letting SIS create or associate new ones, which will be three-dimensional now.
*/
Conversion fromBase = proj.getConversionFromBase();
fromBase = opFactory.createDefiningConversion(referencing.getProperties(fromBase, true), fromBase.getMethod(), fromBase.getParameterValues());
cs = csFactory.createCartesianCS(csProps, axes[0], axes[1], axes[2]);
crs = crsFactory.createProjectedCRS(crsProps, base, fromBase, (CartesianCS) cs);
}
/*
* Remove the VerticalCRS and store the three-dimensional GeographicCRS in place of the previous
* two-dimensional GeographicCRS. Then let the loop continues in case there is other CRS to merge
* (should never happen, but we are paranoiac).
*/
components = ArraysExt.remove(components, i, 1);
// GeographicCRS before VerticalCRS (usual case).
if (axisPosition != 0)
i--;
components[i] = crs;
}
}
}
switch(components.length) {
case 0:
return null;
case 1:
return components[0];
default:
initialize(CRS);
return crsFactory.createCompoundCRS(properties, components);
}
}
use of org.opengis.referencing.crs.VerticalCRS in project sis by apache.
the class ServicesForMetadata method setBounds.
/**
* Sets a vertical extent with the value inferred from the given envelope.
* Only the vertical ordinates are extracted; all other ordinates are ignored.
*
* @param envelope the source envelope.
* @param target the target vertical extent where to store envelope information.
* @throws TransformException if no vertical component can be extracted from the given envelope.
*/
@Override
public void setBounds(final Envelope envelope, final DefaultVerticalExtent target) throws TransformException {
final CoordinateReferenceSystem crs = envelope.getCoordinateReferenceSystem();
final VerticalCRS verticalCRS = CRS.getVerticalComponent(crs, true);
if (verticalCRS == null && envelope.getDimension() != 1) {
throw new TransformException(dimensionNotFound(Resources.Keys.MissingVerticalDimension_1, crs));
}
setVerticalExtent(envelope, target, crs, verticalCRS);
}
use of org.opengis.referencing.crs.VerticalCRS in project sis by apache.
the class CommonCRSTest method testVertical.
/**
* Verifies the vertical datum enumeration.
*/
@Test
public void testVertical() {
for (final CommonCRS.Vertical e : CommonCRS.Vertical.values()) {
final VerticalDatumType datumType;
final String axisName, datumName;
switch(e) {
case NAVD88:
axisName = AxisNames.GRAVITY_RELATED_HEIGHT;
datumName = "North American Vertical Datum 1988";
datumType = VerticalDatumType.GEOIDAL;
break;
case BAROMETRIC:
axisName = "Barometric altitude";
datumName = "Constant pressure surface";
datumType = VerticalDatumType.BAROMETRIC;
break;
case MEAN_SEA_LEVEL:
axisName = AxisNames.GRAVITY_RELATED_HEIGHT;
datumName = "Mean Sea Level";
datumType = VerticalDatumType.GEOIDAL;
break;
case DEPTH:
axisName = AxisNames.DEPTH;
datumName = "Mean Sea Level";
datumType = VerticalDatumType.GEOIDAL;
break;
case ELLIPSOIDAL:
axisName = AxisNames.ELLIPSOIDAL_HEIGHT;
datumName = "Ellipsoid";
datumType = VerticalDatumTypes.ELLIPSOIDAL;
break;
case OTHER_SURFACE:
axisName = "Height";
datumName = "Other surface";
datumType = VerticalDatumType.OTHER_SURFACE;
break;
default:
throw new AssertionError(e);
}
final String name = e.name();
final VerticalDatum datum = e.datum();
final VerticalCRS crs = e.crs();
if (e.isEPSG) {
/*
* BAROMETRIC, ELLIPSOIDAL and OTHER_SURFACE uses an axis named "Height", which is not
* a valid axis name according ISO 19111. We skip the validation test for those enums.
*/
Validators.validate(crs);
}
// Datum before CRS creation.
assertSame(name, datum, e.datum());
// Datum after CRS creation.
assertSame(name, crs.getDatum(), e.datum());
assertEquals(name, datumName, datum.getName().getCode());
assertEquals(name, datumType, datum.getVerticalDatumType());
assertEquals(name, axisName, crs.getCoordinateSystem().getAxis(0).getName().getCode());
}
}
use of org.opengis.referencing.crs.VerticalCRS in project sis by apache.
the class StandardDefinitionsTest method testCreateVerticalCRS.
/**
* Tests the creation of vertical CRS.
*
* @since 0.7
*/
@Test
@DependsOnMethod("testCreateAxis")
public void testCreateVerticalCRS() {
VerticalDatum datum;
VerticalCRS crs;
datum = StandardDefinitions.createVerticalDatum(CommonCRS.Vertical.NAVD88.datum);
crs = StandardDefinitions.createVerticalCRS(CommonCRS.Vertical.NAVD88.crs, datum);
assertEquals("name", "NAVD88 height", crs.getName().getCode());
assertEquals("identifier", "5703", IdentifiedObjects.getIdentifier(crs, Citations.EPSG).getCode());
assertEquals("identifier", "88", IdentifiedObjects.getIdentifier(crs, Citations.WMS).getCode());
assertEquals("direction", AxisDirection.UP, crs.getCoordinateSystem().getAxis(0).getDirection());
datum = StandardDefinitions.createVerticalDatum(CommonCRS.Vertical.MEAN_SEA_LEVEL.datum);
crs = StandardDefinitions.createVerticalCRS(CommonCRS.Vertical.MEAN_SEA_LEVEL.crs, datum);
assertEquals("name", "MSL height", crs.getName().getCode());
assertEquals("identifier", "5714", IdentifiedObjects.getIdentifier(crs, Citations.EPSG).getCode());
assertNull("identifier", IdentifiedObjects.getIdentifier(crs, Citations.OGC));
assertEquals("direction", AxisDirection.UP, crs.getCoordinateSystem().getAxis(0).getDirection());
datum = StandardDefinitions.createVerticalDatum(CommonCRS.Vertical.DEPTH.datum);
crs = StandardDefinitions.createVerticalCRS(CommonCRS.Vertical.DEPTH.crs, datum);
assertEquals("name", "MSL depth", crs.getName().getCode());
assertEquals("identifier", "5715", IdentifiedObjects.getIdentifier(crs, Citations.EPSG).getCode());
assertNull("identifier", IdentifiedObjects.getIdentifier(crs, Citations.OGC));
assertEquals("direction", AxisDirection.DOWN, crs.getCoordinateSystem().getAxis(0).getDirection());
}
use of org.opengis.referencing.crs.VerticalCRS in project sis by apache.
the class EllipsoidalHeightCombinerTest method testGeographicCRS.
/**
* Tests {@link EllipsoidalHeightCombiner#createCompoundCRS EllipsoidalHeightCombiner.createCompoundCRS(…)}
* with a geographic CRS.
*
* @throws FactoryException if a CRS can not be created.
*/
@Test
public void testGeographicCRS() throws FactoryException {
final EllipsoidalHeightCombiner services = create();
final Map<String, String> properties = Collections.singletonMap(CoordinateReferenceSystem.NAME_KEY, "WGS 84 (4D)");
final GeographicCRS horizontal = HardCodedCRS.WGS84;
final GeographicCRS volumetric = HardCodedCRS.WGS84_3D;
final VerticalCRS vertical = HardCodedCRS.ELLIPSOIDAL_HEIGHT;
final TemporalCRS temporal = HardCodedCRS.TIME;
final VerticalCRS geoidal = HardCodedCRS.GRAVITY_RELATED_HEIGHT;
/*
* createCompoundCRS(…) should not combine GeographicCRS with non-ellipsoidal height.
*/
CoordinateReferenceSystem compound = services.createCompoundCRS(properties, horizontal, geoidal, temporal);
assertArrayEqualsIgnoreMetadata(new SingleCRS[] { horizontal, geoidal, temporal }, CRS.getSingleComponents(compound).toArray());
/*
* createCompoundCRS(…) should combine GeographicCRS with ellipsoidal height.
*/
compound = services.createCompoundCRS(properties, horizontal, vertical);
assertArrayEqualsIgnoreMetadata(new SingleCRS[] { volumetric }, CRS.getSingleComponents(compound).toArray());
/*
* createCompoundCRS(…) should combine GeographicCRS with ellipsoidal height and keep time.
*/
compound = services.createCompoundCRS(properties, horizontal, vertical, temporal);
assertArrayEqualsIgnoreMetadata(new SingleCRS[] { volumetric, temporal }, CRS.getSingleComponents(compound).toArray());
/*
* Non-standard feature: accept (VerticalCRS + GeodeticCRS) order.
* The test below use the reverse order for all axes compared to the previous test.
*/
compound = services.createCompoundCRS(properties, temporal, vertical, HardCodedCRS.WGS84_φλ);
final Object[] components = CRS.getSingleComponents(compound).toArray();
assertEquals(2, components.length);
assertEqualsIgnoreMetadata(temporal, components[0]);
assertInstanceOf("Shall be a three-dimensional geographic CRS.", GeographicCRS.class, components[1]);
assertAxisDirectionsEqual("Shall be a three-dimensional geographic CRS.", ((CoordinateReferenceSystem) components[1]).getCoordinateSystem(), AxisDirection.UP, AxisDirection.NORTH, AxisDirection.EAST);
}
Aggregations