use of org.opengis.referencing.datum.VerticalDatum in project sis by apache.
the class MetadataTest method testMetadataWithVerticalCRS.
/**
* Tests the (un)marshalling of a metadata with a vertical CRS.
*
* @throws JAXBException if the (un)marshalling process fails.
*/
@Test
public void testMetadataWithVerticalCRS() throws JAXBException {
final Metadata metadata = unmarshalFile(Metadata.class, VERTICAL_CRS_XML);
if (REGRESSION) {
((DefaultMetadata) metadata).setCharacterSet(CharacterSet.UTF_8);
}
assertEquals("fileIdentifier", "20090901", metadata.getFileIdentifier());
assertEquals("language", Locale.ENGLISH, metadata.getLanguage());
assertEquals("characterSet", CharacterSet.UTF_8, metadata.getCharacterSet());
assertEquals("dateStamp", xmlDate("2014-01-04 00:00:00"), metadata.getDateStamp());
/*
* <gmd:contact>
* <gmd:CI_ResponsibleParty>
* …
* </gmd:CI_ResponsibleParty>
* </gmd:contact>
*/
final ResponsibleParty contact = getSingleton(metadata.getContacts());
final OnlineResource onlineResource = contact.getContactInfo().getOnlineResource();
assertNotNull("onlineResource", onlineResource);
assertEquals("organisationName", "Apache SIS", contact.getOrganisationName().toString());
assertEquals("linkage", URI.create("http://sis.apache.org"), onlineResource.getLinkage());
assertEquals("function", OnLineFunction.INFORMATION, onlineResource.getFunction());
assertEquals("role", Role.PRINCIPAL_INVESTIGATOR, contact.getRole());
/*
* <gmd:spatialRepresentationInfo>
* <gmd:MD_VectorSpatialRepresentation>
* …
* </gmd:MD_VectorSpatialRepresentation>
* </gmd:spatialRepresentationInfo>
*/
final SpatialRepresentation spatial = getSingleton(metadata.getSpatialRepresentationInfo());
assertInstanceOf("spatialRepresentationInfo", VectorSpatialRepresentation.class, spatial);
assertEquals("geometricObjectType", GeometricObjectType.POINT, getSingleton(((VectorSpatialRepresentation) spatial).getGeometricObjects()).getGeometricObjectType());
/*
* <gmd:referenceSystemInfo>
* <gmd:MD_ReferenceSystem>
* …
* </gmd:MD_ReferenceSystem>
* </gmd:referenceSystemInfo>
*/
assertIdentifierEquals("referenceSystemInfo", null, "EPSG", null, "World Geodetic System 84", getSingleton(metadata.getReferenceSystemInfo()).getName());
/*
* <gmd:identificationInfo>
* <gmd:MD_DataIdentification>
* …
*/
final DataIdentification identification = (DataIdentification) getSingleton(metadata.getIdentificationInfo());
final Citation citation = identification.getCitation();
assertInstanceOf("citation", NilObject.class, citation);
assertEquals("nilReason", NilReason.MISSING, ((NilObject) citation).getNilReason());
assertEquals("abstract", "SIS test", identification.getAbstract().toString());
assertEquals("language", Locale.ENGLISH, getSingleton(identification.getLanguages()));
/*
* <gmd:geographicElement>
* <gmd:EX_GeographicBoundingBox>
* …
* </gmd:EX_GeographicBoundingBox>
* </gmd:geographicElement>
*/
final Extent extent = getSingleton(identification.getExtents());
final GeographicBoundingBox bbox = (GeographicBoundingBox) getSingleton(extent.getGeographicElements());
assertEquals("extentTypeCode", Boolean.TRUE, bbox.getInclusion());
assertEquals("westBoundLongitude", 4.55, bbox.getWestBoundLongitude(), STRICT);
assertEquals("eastBoundLongitude", 4.55, bbox.getEastBoundLongitude(), STRICT);
assertEquals("southBoundLatitude", 44.22, bbox.getSouthBoundLatitude(), STRICT);
assertEquals("northBoundLatitude", 44.22, bbox.getNorthBoundLatitude(), STRICT);
/*
* <gmd:verticalElement>
* <gmd:EX_VerticalExtent>
* …
* </gmd:EX_VerticalExtent>
* </gmd:verticalElement>
*/
final VerticalExtent ve = getSingleton(extent.getVerticalElements());
assertEquals("minimumValue", 0.1, ve.getMinimumValue(), STRICT);
assertEquals("maximumValue", 10000, ve.getMaximumValue(), STRICT);
final VerticalCRS crs = ve.getVerticalCRS();
verifyIdentifiers("test1", crs);
assertEquals("scope", "World", crs.getScope().toString());
final VerticalDatum datum = crs.getDatum();
verifyIdentifiers("test2", datum);
assertEquals("scope", "World", datum.getScope().toString());
// Inferred from the name.
assertEquals("vertDatumType", VerticalDatumType.DEPTH, datum.getVerticalDatumType());
final VerticalCS cs = crs.getCoordinateSystem();
verifyIdentifiers("test3", cs);
final CoordinateSystemAxis axis = cs.getAxis(0);
verifyIdentifiers("test4", axis);
assertEquals("axisAbbrev", "d", axis.getAbbreviation());
assertEquals("axisDirection", AxisDirection.DOWN, axis.getDirection());
/*
* …
* </gmd:MD_DataIdentification>
* </gmd:identificationInfo>
*
* Now marshal the object and compare with the original file.
*/
assertMarshalEqualsFile(VERTICAL_CRS_XML, metadata, VERSION_2007, "xmlns:*", "xsi:schemaLocation");
}
use of org.opengis.referencing.datum.VerticalDatum in project sis by apache.
the class Extents method getVerticalRange.
/**
* Returns the union of chosen vertical ranges found in the given extent, or {@code null} if none.
* This method gives preference to heights above the Mean Sea Level when possible.
* Depths have negative height values: if the
* {@linkplain org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis#getDirection() axis direction}
* is toward down, then this method reverses the sign of minimum and maximum values.
*
* <div class="section">Multi-occurrences</div>
* If the given {@code Extent} object contains more than one vertical extent, then this method
* performs a choice based on the vertical datum and the unit of measurement:
*
* <ul class="verbose">
* <li><p><b>Choice based on vertical datum</b><br>
* Only the extents associated (indirectly, through their CRS) to the same non-null {@link VerticalDatumType}
* will be taken in account. If all datum types are null, then this method conservatively uses only the first
* vertical extent. Otherwise the datum type used for filtering the vertical extents is:</p>
*
* <ul>
* <li>{@link VerticalDatumType#GEOIDAL} or {@link VerticalDatumType#DEPTH DEPTH} if at least one extent
* uses those datum types. For this method, {@code DEPTH} is considered as equivalent to {@code GEOIDAL}
* except for the axis direction.</li>
* <li>Otherwise, the first non-null datum type found in iteration order.</li>
* </ul>
*
* <div class="note"><b>Rational:</b> like {@linkplain #getGeographicBoundingBox(Extent) geographic bounding box},
* the vertical range is an approximative information; the range returned by this method does not carry any
* information about the vertical CRS and this method does not attempt to perform coordinate transformation.
* But this method is more useful if the returned ranges are close to a frequently used surface, like the
* Mean Sea Level. The same simplification is applied in the
* <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#31">{@code VerticalExtent} element of
* Well Known Text (WKT) format</a>, which specifies that <cite>“Vertical extent is an approximate description
* of location; heights are relative to an unspecified mean sea level.”</cite></div></li>
*
* <li><p><b>Choice based on units of measurement</b><br>
* If, after the choice based on the vertical datum described above, there is still more than one vertical
* extent to consider, then the next criterion checks for the units of measurement.</p>
* <ul>
* <li>If no range specify a unit of measurement, return the first range and ignore all others.</li>
* <li>Otherwise take the first range having a unit of measurement. Then:<ul>
* <li>All other ranges having an incompatible unit of measurement will be ignored.</li>
* <li>All other ranges having a compatible unit of measurement will be converted to
* the unit of the first retained range, and their union will be computed.</li>
* </ul></li>
* </ul>
*
* <div class="note"><b>Example:</b>
* Heights or depths are often measured using some pressure units, for example hectopascals (hPa).
* An {@code Extent} could contain two vertical elements: one with the height measurements in hPa,
* and the other element with heights transformed to metres using an empirical formula.
* In such case this method will select the first vertical element on the assumption that it is
* the "main" one that the metadata producer intended to show. Next, this method will search for
* other vertical elements using pressure unit. In our example there is none, but if such elements
* were found, this method would compute their union.</div></li>
* </ul>
*
* @param extent the extent to convert to a vertical measurement range, or {@code null}.
* @return a vertical measurement range created from the given extent, or {@code null} if none.
*
* @since 0.4
*/
public static MeasurementRange<Double> getVerticalRange(final Extent extent) {
MeasurementRange<Double> range = null;
VerticalDatumType selectedType = null;
if (extent != null) {
for (final VerticalExtent element : extent.getVerticalElements()) {
double min = element.getMinimumValue();
double max = element.getMaximumValue();
final VerticalCRS crs = element.getVerticalCRS();
VerticalDatumType type = null;
Unit<?> unit = null;
if (crs != null) {
final VerticalDatum datum = crs.getDatum();
if (datum != null) {
type = datum.getVerticalDatumType();
if (VerticalDatumType.DEPTH.equals(type)) {
type = VerticalDatumType.GEOIDAL;
}
}
final CoordinateSystemAxis axis = crs.getCoordinateSystem().getAxis(0);
unit = axis.getUnit();
if (AxisDirection.DOWN.equals(axis.getDirection())) {
final double tmp = min;
min = -max;
max = -tmp;
}
}
if (range != null) {
/*
* If the new range does not specify any datum type or unit, then we do not know how to
* convert the values before to perform the union operation. Conservatively do nothing.
*/
if (type == null || unit == null) {
continue;
}
/*
* If the new range is not measured relative to the same kind of surface than the previous range,
* then we do not know how to combine those ranges. Do nothing, unless the new range is a Mean Sea
* Level Height in which case we forget all previous ranges and use the new one instead.
*/
if (!type.equals(selectedType)) {
if (!type.equals(VerticalDatumType.GEOIDAL)) {
continue;
}
} else if (selectedType != null) {
/*
* If previous range did not specify any unit, then unconditionally replace it by
* the new range since it provides more information. If both ranges specify units,
* then we will compute the union if we can, or ignore the new range otherwise.
*/
final Unit<?> previous = range.unit();
if (previous != null) {
if (previous.isCompatible(unit)) {
range = (MeasurementRange<Double>) range.union(MeasurementRange.create(min, true, max, true, unit));
}
continue;
}
}
}
range = MeasurementRange.create(min, true, max, true, unit);
selectedType = type;
}
}
return range;
}
use of org.opengis.referencing.datum.VerticalDatum 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.datum.VerticalDatum 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.datum.VerticalDatum 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());
}
Aggregations