blob: 2b5b82d4652d945ec96188bf00c48c8cb67ac7fc [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.metadata.iso.content;
import javax.measure.Unit;
import javax.measure.quantity.Length;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.opengis.metadata.content.Band;
import org.opengis.metadata.content.BandDefinition;
import org.opengis.metadata.content.PolarizationOrientation;
import org.opengis.metadata.content.TransferFunctionType;
import org.apache.sis.measure.ValueRange;
import org.apache.sis.internal.jaxb.gco.GO_Real;
import org.apache.sis.internal.jaxb.gco.UnitAdapter;
import static org.apache.sis.internal.metadata.MetadataUtilities.ensurePositive;
// Branch-specific imports
import org.opengis.annotation.UML;
import static org.opengis.annotation.Obligation.OPTIONAL;
import static org.opengis.annotation.Specification.ISO_19115;
/**
* Range of wavelengths in the electromagnetic spectrum.
* The following property is conditional (i.e. mandatory under some circumstances)
* in a well-formed metadata according ISO 19115:
*
* <div class="preformat">{@code MD_Band}
* {@code   └─units……} Units of data in each dimension included in the resource.</div>
*
* <p><b>Limitations:</b></p>
* <ul>
* <li>Instances of this class are not synchronized for multi-threading.
* Synchronization, if needed, is caller's responsibility.</li>
* <li>Serialized objects of this class are not guaranteed to be compatible with future Apache SIS releases.
* Serialization support is appropriate for short term storage or RMI between applications running the
* same version of Apache SIS. For long term storage, use {@link org.apache.sis.xml.XML} instead.</li>
* </ul>
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @author Touraïvane (IRD)
* @author Cédric Briançon (Geomatys)
* @author Rémi Maréchal (Geomatys)
* @author Cullen Rombach (Image Matters)
* @version 1.0
* @since 0.3
* @module
*/
@XmlType(name = "MD_Band_Type", propOrder = {
"boundMax",
"boundMin",
"boundUnits",
"peakResponse",
"toneGradation",
"bandBoundaryDefinition",
"nominalSpatialResolution",
"transferFunctionType",
"transmittedPolarization",
"detectedPolarization"
})
@XmlRootElement(name = "MD_Band")
@XmlSeeAlso(org.apache.sis.internal.jaxb.gmi.MI_Band.class)
public class DefaultBand extends DefaultSampleDimension implements Band {
/**
* Serial number for inter-operability with different versions.
*/
private static final long serialVersionUID = -2474871120376144737L;
/**
* Shortest wavelength that the sensor is capable of collecting within a designated band.
*/
private Double boundMin;
/**
* Longest wavelength that the sensor is capable of collecting within a designated band.
*/
private Double boundMax;
/**
* Units in which sensor wavelengths are expressed.
*/
private Unit<Length> boundUnits;
/**
* Designation of criterion for defining maximum and minimum wavelengths for a spectral band.
*/
private BandDefinition bandBoundaryDefinition;
/**
* Wavelength at which the response is the highest.
*/
private Double peakResponse;
/**
* Number of discrete numerical values in the grid data.
*/
private Integer toneGradation;
/**
* Polarization of the radiation transmitted.
*/
private PolarizationOrientation transmittedPolarization;
/**
* Polarization of the radiation detected.
*/
private PolarizationOrientation detectedPolarization;
/**
* Constructs an initially empty band.
*/
public DefaultBand() {
}
/**
* Constructs a new instance initialized with the values from the specified metadata object.
* This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
* given object are not recursively copied.
*
* <div class="note"><b>Note on properties validation:</b>
* This constructor does not verify the property values of the given metadata (e.g. whether it contains
* unexpected negative values). This is because invalid metadata exist in practice, and verifying their
* validity in this copy constructor is often too late. Note that this is not the only hole, as invalid
* metadata instances can also be obtained by unmarshalling an invalid XML document.
* </div>
*
* @param object the metadata to copy values from, or {@code null} if none.
*
* @see #castOrCopy(Band)
*/
public DefaultBand(final Band object) {
super(object);
if (object != null) {
if (object instanceof DefaultBand) {
final DefaultBand c = (DefaultBand) object;
boundMin = c.getBoundMin();
boundMax = c.getBoundMax();
boundUnits = c.getBoundUnits();
}
peakResponse = object.getPeakResponse();
toneGradation = object.getToneGradation();
bandBoundaryDefinition = object.getBandBoundaryDefinition();
transmittedPolarization = object.getTransmittedPolarization();
detectedPolarization = object.getDetectedPolarization();
}
}
/**
* Returns a SIS metadata implementation with the values of the given arbitrary implementation.
* This method performs the first applicable action in the following choices:
*
* <ul>
* <li>If the given object is {@code null}, then this method returns {@code null}.</li>
* <li>Otherwise if the given object is already an instance of
* {@code DefaultBand}, then it is returned unchanged.</li>
* <li>Otherwise a new {@code DefaultBand} instance is created using the
* {@linkplain #DefaultBand(Band) copy constructor}
* and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
* metadata contained in the given object are not recursively copied.</li>
* </ul>
*
* @param object the object to get as a SIS implementation, or {@code null} if none.
* @return a SIS implementation containing the values of the given object (may be the
* given object itself), or {@code null} if the argument was null.
*/
public static DefaultBand castOrCopy(final Band object) {
if (object == null || object instanceof DefaultBand) {
return (DefaultBand) object;
}
return new DefaultBand(object);
}
/**
* Returns the shortest wavelength that the sensor is capable of collecting within a designated band.
* The units of measurement is given by {@link #getBoundUnits()}.
*
* @return Shortest wavelength that the sensor is capable of collecting within a designated band,
* or {@code null} if unspecified.
*
* @since 0.5
*/
@ValueRange(minimum = 0)
@XmlElement(name = "boundMin")
@XmlJavaTypeAdapter(GO_Real.Since2014.class)
@UML(identifier="boundMin", obligation=OPTIONAL, specification=ISO_19115)
public Double getBoundMin() {
return boundMin;
}
/**
* Sets the shortest wavelength that the sensor is capable of collecting within a designated band.
*
* @param newValue the new shortest wavelength, or {@code null}.
* @throws IllegalArgumentException if the given value is negative.
*
* @since 0.5
*/
public void setBoundMin(final Double newValue) {
checkWritePermission(boundMin);
if (ensurePositive(DefaultBand.class, "boundMin", false, newValue)) {
boundMin = newValue;
}
}
/**
* Returns the longest wavelength that the sensor is capable of collecting within a designated band.
* The units of measurement is given by {@link #getUnits()}.
*
* @return longest wavelength that the sensor is capable of collecting within a designated band,
* or {@code null} if unspecified.
*
* @since 0.5
*/
@ValueRange(minimum = 0)
@XmlElement(name = "boundMax")
@XmlJavaTypeAdapter(GO_Real.Since2014.class)
@UML(identifier="boundMax", obligation=OPTIONAL, specification=ISO_19115)
public Double getBoundMax() {
return boundMax;
}
/**
* Sets the longest wavelength that the sensor is capable of collecting within a designated band.
*
* @param newValue the new longest wavelength, or {@code null}.
* @throws IllegalArgumentException if the given value is negative.
*
* @since 0.5
*/
public void setBoundMax(final Double newValue) {
checkWritePermission(boundMax);
if (ensurePositive(DefaultBand.class, "boundMax", false, newValue)) {
boundMax = newValue;
}
}
/**
* Returns units in which sensor wavelengths are expressed.
*
* @return units in which sensor wavelengths are expressed.
*
* @since 0.5
*
* @see org.apache.sis.measure.Units#NANOMETRE
*/
@XmlElement(name = "boundUnits")
@XmlJavaTypeAdapter(UnitAdapter.Since2014.class)
@UML(identifier="boundUnits", obligation=OPTIONAL, specification=ISO_19115)
public Unit<Length> getBoundUnits() {
return boundUnits;
}
/**
* Sets a new units in which sensor wavelengths are expressed.
*
* @param newValue the new unit.
*
* @since 0.5
*/
public void setBoundUnits(final Unit<Length> newValue) {
checkWritePermission(boundUnits);
boundUnits = newValue;
}
/**
* Returns the designation of criterion for defining maximum and minimum wavelengths for a spectral band.
*
* @return criterion for defining maximum and minimum wavelengths, or {@code null}.
*/
@Override
@XmlElement(name = "bandBoundaryDefinition")
public BandDefinition getBandBoundaryDefinition() {
return bandBoundaryDefinition;
}
/**
* Sets designation of criterion for defining maximum and minimum wavelengths for a spectral band.
*
* @param newValue the new band definition.
*/
public void setBandBoundaryDefinition(final BandDefinition newValue) {
checkWritePermission(bandBoundaryDefinition);
bandBoundaryDefinition = newValue;
}
/**
* Returns the units of data as a unit of length.
*
* <div class="warning"><b>Upcoming API change — generalization</b><br>
* As of ISO 19115:2014, the units of wavelength is rather {@code boundUnits}.
* The restriction for units of length in this {@code units} property may be relaxed in GeoAPI 4.0.
* </div>
*
* @return The units of data.
*/
@Override
public Unit<Length> getUnits() {
final Unit<?> units = super.getUnits();
return (units != null) ? units.asType(Length.class) : null;
}
/**
* Sets the units of data as a unit of length.
*
* <div class="warning"><b>Upcoming precondition change — relaxation</b><br>
* The current implementation requires the unit to be an instance of {@code Unit<Length>},
* otherwise a {@link ClassCastException} is thrown. This is because the value returned by
* {@link #getUnits()} was restricted by ISO 19115:2003 to units of length.
* However this restriction may be relaxed in GeoAPI 4.0.
* </div>
*
* @param newValue The new units of data as an instance of {@code Unit<Length>}.
*/
@Override
public void setUnits(final Unit<?> newValue) {
super.setUnits(newValue.asType(Length.class));
}
/**
* Returns the wavelength at which the response is the highest.
* The units of measurement is given by {@link #getBoundUnits()}.
*
* @return wavelength at which the response is the highest, or {@code null} if unspecified.
*/
@Override
@ValueRange(minimum = 0)
@XmlElement(name = "peakResponse")
public Double getPeakResponse() {
return peakResponse;
}
/**
* Sets the wavelength at which the response is the highest.
*
* @param newValue the new peak response, or {@code null}.
* @throws IllegalArgumentException if the given value is negative.
*/
public void setPeakResponse(final Double newValue) {
checkWritePermission(peakResponse);
if (ensurePositive(DefaultBand.class, "peakResponse", false, newValue)) {
peakResponse = newValue;
}
}
/**
* Returns the number of discrete numerical values in the grid data.
*
* @return number of discrete numerical values in the grid data, or {@code null} if none.
*/
@Override
@ValueRange(minimum = 0)
@XmlElement(name = "toneGradation")
public Integer getToneGradation() {
return toneGradation;
}
/**
* Sets the number of discrete numerical values in the grid data.
*
* @param newValue the new tone gradation.
*/
public void setToneGradation(final Integer newValue) {
checkWritePermission(toneGradation);
if (ensurePositive(DefaultBand.class, "toneGradation", false, newValue)) {
toneGradation = newValue;
}
}
/**
* Returns the smallest distance between which separate points can be distinguished,
* as specified in instrument design.
*
* @return {@inheritDoc}
*/
@Override
@ValueRange(minimum = 0, isMinIncluded = false)
@XmlElement(name = "nominalSpatialResolution")
public Double getNominalSpatialResolution() {
return super.getNominalSpatialResolution();
}
/**
* {@inheritDoc}
*/
@Override
public void setNominalSpatialResolution(final Double newValue) {
super.setNominalSpatialResolution(newValue);
}
/**
* Returns type of transfer function to be used when scaling a physical value for a given element.
*
* @return {@inheritDoc}
*/
@Override
@XmlElement(name = "transferFunctionType")
public TransferFunctionType getTransferFunctionType() {
return super.getTransferFunctionType();
}
/**
* {@inheritDoc}
*/
@Override
public void setTransferFunctionType(final TransferFunctionType newValue) {
super.setTransferFunctionType(newValue);
}
/**
* Returns the polarization of the radiation transmitted.
*
* <div class="warning"><b>Upcoming API change</b><br>
* This method may be renamed {@code getTransmittedPolarization} and its return type replaced by
* {@code PolarisationOrientation} ("z" letter replaced by "s" letter) in GeoAPI 4.0
* for compliance with ISO 19115-2:2019.</div>
*
* @return polarization of the radiation transmitted, or {@code null}.
*/
@Override
@XmlElement(name = "transmittedPolarisation")
public PolarizationOrientation getTransmittedPolarization() {
return transmittedPolarization;
}
/**
* Sets the polarization of the radiation transmitted.
*
* <div class="warning"><b>Upcoming API change</b><br>
* This method may be renamed {@code setTransmittedPolarization} and its argument type replaced by
* {@code PolarisationOrientation} ("z" letter replaced by "s" letter) in GeoAPI 4.0
* for compliance with ISO 19115-2:2019.</div>
*
* @param newValue the new transmitted polarization.
*/
public void setTransmittedPolarization(final PolarizationOrientation newValue) {
checkWritePermission(transmittedPolarization);
transmittedPolarization = newValue;
}
/**
* Returns polarization of the radiation detected.
*
* <div class="warning"><b>Upcoming API change</b><br>
* This method may be renamed {@code getDetectedPolarization} and its return type replaced by
* {@code PolarisationOrientation} ("z" letter replaced by "s" letter) in GeoAPI 4.0
* for compliance with ISO 19115-2:2019.</div>
*
* @return polarization of the radiation detected, or {@code null}.
*/
@Override
@XmlElement(name = "detectedPolarisation")
public PolarizationOrientation getDetectedPolarization() {
return detectedPolarization;
}
/**
* Sets the polarization of the radiation detected.
*
* <div class="warning"><b>Upcoming API change</b><br>
* This method may be renamed {@code setDetectedPolarization} and its argument type replaced by
* {@code PolarisationOrientation} ("z" letter replaced by "s" letter) in GeoAPI 4.0
* for compliance with ISO 19115-2:2019.</div>
*
* @param newValue the new detected polarization.
*/
public void setDetectedPolarization(final PolarizationOrientation newValue) {
checkWritePermission(detectedPolarization);
detectedPolarization = newValue;
}
}