/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2004-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * This package contains documentation from OpenGIS specifications. * OpenGIS consortium's work is fully acknowledged here. */ package org.geotools.metadata.iso.extent; import java.util.Collection; import org.opengis.metadata.extent.Extent; import org.opengis.metadata.extent.BoundingPolygon; import org.opengis.metadata.extent.GeographicExtent; import org.opengis.metadata.extent.GeographicBoundingBox; import org.opengis.metadata.extent.TemporalExtent; import org.opengis.metadata.extent.VerticalExtent; import org.opengis.util.InternationalString; import org.geotools.metadata.iso.MetadataEntity; /** * Information about spatial, vertical, and temporal extent. * This interface has four optional attributes * ({@linkplain #getGeographicElements geographic elements}, * {@linkplain #getTemporalElements temporal elements}, and * {@linkplain #getVerticalElements vertical elements}) and an element called * {@linkplain #getDescription description}. * At least one of the four shall be used. * * * @source $URL$ * @version $Id$ * @author Martin Desruisseaux (IRD) * @author Touraïvane * * @since 2.1 */ public class ExtentImpl extends MetadataEntity implements Extent { /** * Serial number for interoperability with different versions. */ private static final long serialVersionUID = 7812213837337326257L; /** * A geographic extent ranging from 180°W to 180°E and 90°S to 90°N. * * @since 2.2 */ public static final Extent WORLD; static { final ExtentImpl world = new ExtentImpl(); world.getGeographicElements().add(GeographicBoundingBoxImpl.WORLD); world.freeze(); WORLD = world; } /** * Returns the spatial and temporal extent for the referring object. */ private InternationalString description; /** * Provides geographic component of the extent of the referring object */ private Collection<GeographicExtent> geographicElements; /** * Provides temporal component of the extent of the referring object */ private Collection<TemporalExtent> temporalElements; /** * Provides vertical component of the extent of the referring object */ private Collection<VerticalExtent> verticalElements; /** * Constructs an initially empty extent. */ public ExtentImpl() { } /** * Constructs a metadata entity initialized with the values from the specified metadata. * * @since 2.4 */ public ExtentImpl(final Extent source) { super(source); } /** * Returns the spatial and temporal extent for the referring object. */ public InternationalString getDescription() { return description; } /** * Set the spatial and temporal extent for the referring object. */ public synchronized void setDescription(final InternationalString newValue) { checkWritePermission(); description = newValue; } /** * Provides geographic component of the extent of the referring object */ public synchronized Collection<GeographicExtent> getGeographicElements() { return (geographicElements = nonNullCollection(geographicElements, GeographicExtent.class)); } /** * Set geographic component of the extent of the referring object */ public synchronized void setGeographicElements( final Collection<? extends GeographicExtent> newValues) { geographicElements = copyCollection(newValues, geographicElements, GeographicExtent.class); } /** * Provides temporal component of the extent of the referring object */ public synchronized Collection<TemporalExtent> getTemporalElements() { return (temporalElements = nonNullCollection(temporalElements, TemporalExtent.class)); } /** * Set temporal component of the extent of the referring object */ public synchronized void setTemporalElements( final Collection<? extends TemporalExtent> newValues) { temporalElements = copyCollection(newValues, temporalElements, TemporalExtent.class); } /** * Provides vertical component of the extent of the referring object */ public synchronized Collection<VerticalExtent> getVerticalElements() { return (verticalElements = nonNullCollection(verticalElements, VerticalExtent.class)); } /** * Set vertical component of the extent of the referring object */ public synchronized void setVerticalElements( final Collection<? extends VerticalExtent> newValues) { verticalElements = copyCollection(newValues, verticalElements, VerticalExtent.class); } /** * Convenience method returning a single geographic bounding box from the specified extent. * If no bounding box was found, then this method returns {@code null}. If more than one box * is found, then boxes are {@linkplain GeographicBoundingBoxImpl#add added} together. * * @since 2.2 */ public static GeographicBoundingBox getGeographicBoundingBox(final Extent extent) { GeographicBoundingBox candidate = null; if (extent != null) { GeographicBoundingBoxImpl modifiable = null; for (final GeographicExtent element : extent.getGeographicElements()) { final GeographicBoundingBox bounds; if (element instanceof GeographicBoundingBox) { bounds = (GeographicBoundingBox) element; } else if (element instanceof BoundingPolygon) { // TODO: iterates through all polygons and invoke Polygon.getEnvelope(); continue; } else { continue; } /* * A single geographic bounding box has been extracted. Now add it to previous * ones (if any). All exclusion boxes before the first inclusion box are ignored. */ if (candidate == null) { /* * Reminder: 'inclusion' is a mandatory attribute, so it should never be * null for a valid metadata object. If the metadata object is invalid, * it is better to get an exception than having a code doing silently * some probably inappropriate work. */ final Boolean inclusion = bounds.getInclusion(); ensureNonNull("inclusion", inclusion); if (inclusion.booleanValue()) { candidate = bounds; } } else { if (modifiable == null) { modifiable = new GeographicBoundingBoxImpl(candidate); candidate = modifiable; } modifiable.add(bounds); } } if (modifiable != null) { modifiable.freeze(); } } return candidate; } }