Search in sources :

Example 1 with VerticalExtent

use of org.opengis.metadata.extent.VerticalExtent 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;
}
Also used : MeasurementRange(org.apache.sis.measure.MeasurementRange) VerticalDatumType(org.opengis.referencing.datum.VerticalDatumType) VerticalExtent(org.opengis.metadata.extent.VerticalExtent) VerticalCRS(org.opengis.referencing.crs.VerticalCRS) CoordinateSystemAxis(org.opengis.referencing.cs.CoordinateSystemAxis) VerticalDatum(org.opengis.referencing.datum.VerticalDatum) Unit(javax.measure.Unit)

Example 2 with VerticalExtent

use of org.opengis.metadata.extent.VerticalExtent in project sis by apache.

the class ExtentsTest method testVerticalIntersection.

/**
 * Tests {@link Extents#intersection(VerticalExtent, VerticalExtent)}.
 * This test does not perform any unit conversion, because it would require the use of different CRS.
 * For a test with unit conversion, see {@code ServicesForMetadataTest.testVerticalIntersection()} in
 * {@code sis-referencing} module.
 *
 * @throws TransformException should never happen since we do not test transformation in this class.
 */
@Test
public void testVerticalIntersection() throws TransformException {
    final VerticalExtent e1 = new DefaultVerticalExtent(10, 20, null);
    final VerticalExtent e2 = new DefaultVerticalExtent(15, 25, null);
    assertEquals("intersect", new DefaultVerticalExtent(15, 20, null), Extents.intersection(e1, e2));
    assertSame(e1, Extents.intersection(e1, null));
    assertSame(e2, Extents.intersection(null, e2));
    assertNull(Extents.intersection((VerticalExtent) null, (VerticalExtent) null));
}
Also used : VerticalExtent(org.opengis.metadata.extent.VerticalExtent) Test(org.junit.Test)

Example 3 with VerticalExtent

use of org.opengis.metadata.extent.VerticalExtent 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");
}
Also used : DataIdentification(org.opengis.metadata.identification.DataIdentification) VerticalExtent(org.opengis.metadata.extent.VerticalExtent) Extent(org.opengis.metadata.extent.Extent) SpatialRepresentation(org.opengis.metadata.spatial.SpatialRepresentation) VectorSpatialRepresentation(org.opengis.metadata.spatial.VectorSpatialRepresentation) ReferenceSystemMetadata(org.apache.sis.internal.jaxb.metadata.replace.ReferenceSystemMetadata) VerticalExtent(org.opengis.metadata.extent.VerticalExtent) CoordinateSystemAxis(org.opengis.referencing.cs.CoordinateSystemAxis) DefaultCoordinateSystemAxis(org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis) VerticalDatum(org.opengis.referencing.datum.VerticalDatum) DefaultVerticalDatum(org.apache.sis.referencing.datum.DefaultVerticalDatum) GeographicBoundingBox(org.opengis.metadata.extent.GeographicBoundingBox) VerticalCS(org.opengis.referencing.cs.VerticalCS) DefaultVerticalCS(org.apache.sis.referencing.cs.DefaultVerticalCS) DefaultVerticalCRS(org.apache.sis.referencing.crs.DefaultVerticalCRS) VerticalCRS(org.opengis.referencing.crs.VerticalCRS) Test(org.junit.Test)

Example 4 with VerticalExtent

use of org.opengis.metadata.extent.VerticalExtent in project sis by apache.

the class ServicesForMetadata method setBounds.

/**
 * Sets the geographic, vertical and temporal extents with the values inferred from the given envelope.
 * If the given {@code target} has more geographic or vertical extents than needed (0 or 1), then the
 * extraneous extents are removed.
 *
 * @param  envelope  the source envelope.
 * @param  target    the target spatiotemporal extent where to store envelope information.
 * @throws TransformException if no temporal component can be extracted from the given envelope.
 */
@Override
public void setBounds(final Envelope envelope, final DefaultSpatialTemporalExtent target) throws TransformException {
    final CoordinateReferenceSystem crs = envelope.getCoordinateReferenceSystem();
    final SingleCRS horizontalCRS = CRS.getHorizontalComponent(crs);
    final VerticalCRS verticalCRS = CRS.getVerticalComponent(crs, true);
    final TemporalCRS temporalCRS = CRS.getTemporalComponent(crs);
    if (horizontalCRS == null && verticalCRS == null && temporalCRS == null) {
        throw new TransformException(dimensionNotFound(Resources.Keys.MissingSpatioTemporalDimension_1, crs));
    }
    /*
         * Try to set the geographic bounding box first, because this operation may fail with a
         * TransformException while the other operations (vertical and temporal) should not fail.
         * So doing the geographic part first help us to get a "all or nothing" behavior.
         */
    DefaultGeographicBoundingBox box = null;
    boolean useExistingBox = (horizontalCRS != null);
    final Collection<GeographicExtent> spatialExtents = target.getSpatialExtent();
    final Iterator<GeographicExtent> it = spatialExtents.iterator();
    while (it.hasNext()) {
        final GeographicExtent extent = it.next();
        if (extent instanceof GeographicBoundingBox) {
            if (useExistingBox && (extent instanceof DefaultGeographicBoundingBox)) {
                box = (DefaultGeographicBoundingBox) extent;
                useExistingBox = false;
            } else {
                it.remove();
            }
        }
    }
    if (horizontalCRS != null) {
        if (box == null) {
            box = new DefaultGeographicBoundingBox();
            spatialExtents.add(box);
        }
        GeographicCRS normalizedCRS = ReferencingUtilities.toNormalizedGeographicCRS(crs);
        if (normalizedCRS == null) {
            normalizedCRS = CommonCRS.defaultGeographic();
        }
        setGeographicExtent(envelope, box, crs, normalizedCRS);
    }
    /*
         * Other dimensions (vertical and temporal).
         */
    if (verticalCRS != null) {
        VerticalExtent e = target.getVerticalExtent();
        if (!(e instanceof DefaultVerticalExtent)) {
            e = new DefaultVerticalExtent();
            target.setVerticalExtent(e);
        }
        setVerticalExtent(envelope, (DefaultVerticalExtent) e, crs, verticalCRS);
    } else {
        target.setVerticalExtent(null);
    }
    if (temporalCRS != null) {
        setTemporalExtent(envelope, target, crs, temporalCRS);
    } else {
        target.setExtent(null);
    }
}
Also used : SingleCRS(org.opengis.referencing.crs.SingleCRS) DefaultVerticalExtent(org.apache.sis.metadata.iso.extent.DefaultVerticalExtent) TransformException(org.opengis.referencing.operation.TransformException) DefaultVerticalExtent(org.apache.sis.metadata.iso.extent.DefaultVerticalExtent) VerticalExtent(org.opengis.metadata.extent.VerticalExtent) GeographicBoundingBox(org.opengis.metadata.extent.GeographicBoundingBox) DefaultGeographicBoundingBox(org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox) GeographicExtent(org.opengis.metadata.extent.GeographicExtent) DefaultTemporalCRS(org.apache.sis.referencing.crs.DefaultTemporalCRS) TemporalCRS(org.opengis.referencing.crs.TemporalCRS) DefaultGeographicBoundingBox(org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox) VerticalCRS(org.opengis.referencing.crs.VerticalCRS) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem) GeographicCRS(org.opengis.referencing.crs.GeographicCRS)

Aggregations

VerticalExtent (org.opengis.metadata.extent.VerticalExtent)4 VerticalCRS (org.opengis.referencing.crs.VerticalCRS)3 Test (org.junit.Test)2 GeographicBoundingBox (org.opengis.metadata.extent.GeographicBoundingBox)2 CoordinateSystemAxis (org.opengis.referencing.cs.CoordinateSystemAxis)2 VerticalDatum (org.opengis.referencing.datum.VerticalDatum)2 Unit (javax.measure.Unit)1 ReferenceSystemMetadata (org.apache.sis.internal.jaxb.metadata.replace.ReferenceSystemMetadata)1 MeasurementRange (org.apache.sis.measure.MeasurementRange)1 DefaultGeographicBoundingBox (org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox)1 DefaultVerticalExtent (org.apache.sis.metadata.iso.extent.DefaultVerticalExtent)1 DefaultTemporalCRS (org.apache.sis.referencing.crs.DefaultTemporalCRS)1 DefaultVerticalCRS (org.apache.sis.referencing.crs.DefaultVerticalCRS)1 DefaultCoordinateSystemAxis (org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis)1 DefaultVerticalCS (org.apache.sis.referencing.cs.DefaultVerticalCS)1 DefaultVerticalDatum (org.apache.sis.referencing.datum.DefaultVerticalDatum)1 Extent (org.opengis.metadata.extent.Extent)1 GeographicExtent (org.opengis.metadata.extent.GeographicExtent)1 DataIdentification (org.opengis.metadata.identification.DataIdentification)1 SpatialRepresentation (org.opengis.metadata.spatial.SpatialRepresentation)1