001/* 002 * GeoAPI - Java interfaces for OGC/ISO standards 003 * Copyright © 2003-2024 Open Geospatial Consortium, Inc. 004 * http://www.geoapi.org 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.opengis.geometry; 019 020import java.awt.geom.Rectangle2D; // Used in @see javadoc tags 021 022import org.opengis.referencing.cs.RangeMeaning; // For javadoc 023import org.opengis.referencing.crs.CoordinateReferenceSystem; 024import org.opengis.annotation.UML; 025import org.opengis.annotation.Classifier; 026import org.opengis.annotation.Stereotype; 027 028import static org.opengis.annotation.Obligation.*; 029import static org.opengis.annotation.Specification.*; 030 031 032/** 033 * A minimum bounding box or rectangle. Regardless of dimension, an {@code Envelope} can 034 * be represented without ambiguity as two direct positions (coordinate points). To encode an 035 * {@code Envelope}, it is sufficient to encode these two points. This is consistent with 036 * all of the data types in this specification, their state is represented by their publicly 037 * accessible attributes. 038 * 039 * <h2>Crossing the anti-meridian of a geographic CRS</h2> 040 * The <cite>Web Coverage Service</cite> (WCS) 1.1 specification uses an extended interpretation 041 * of the bounding box definition. In a WCS 1.1 data structure, the {@linkplain #getUpperCorner() 042 * upper corner} defines the edges region in the directions of <em>increasing</em> coordinate 043 * values in the envelope CRS, while the {@linkplain #getLowerCorner() lower corner} defines the 044 * edges region in the direction of <em>decreasing</em> coordinate values. They are usually the 045 * algebraic maximum and minimum coordinates respectively, but not always. For example, an envelope 046 * crossing the anti-meridian could have an upper corner longitude less than the lower corner longitude. 047 * Whether an envelope supports the extended bounding box interpretation or not is 048 * implementation-dependent. If supported, the extended interpretation is applicable only to 049 * axes having a {@link RangeMeaning#WRAPAROUND WRAPAROUND} range meaning, which is usually 050 * the longitude axis. 051 * 052 * @departure easeOfUse 053 * The ISO specification defines this interface in the {@code coordinate} sub-package. 054 * GeoAPI moved this interface into the {@code org.opengis.geometry} root package for 055 * convenience, because it is extensively used. 056 * 057 * @author Martin Desruisseaux (IRD) 058 * @version 3.1 059 * @since 1.0 060 */ 061@Classifier(Stereotype.DATATYPE) 062@UML(identifier="GM_Envelope", specification=ISO_19107) 063public interface Envelope { 064 /** 065 * Returns the envelope coordinate reference system, or {@code null} if unknown. 066 * If non-null, it shall be the same as {@linkplain #getLowerCorner() lower corner} 067 * and {@linkplain #getUpperCorner() upper corner} CRS. 068 * 069 * @return the envelope CRS, or {@code null} if unknown. 070 * 071 * @departure easeOfUse 072 * ISO does not define this method - the CRS or the dimension can be obtained only through 073 * one of the corner {@code DirectPosition} objects. GeoAPI adds this method for convenience 074 * as a more direct way of obtaining the information and to free the user from the need to 075 * choose an arbitrary corner (very defensive code might feel the need to get the value from 076 * both corners to check they were the same). 077 */ 078 CoordinateReferenceSystem getCoordinateReferenceSystem(); 079 080 /** 081 * The length of coordinate sequence (the number of entries) in this envelope. Mandatory 082 * even when the {@linkplain #getCoordinateReferenceSystem() coordinate reference system} 083 * is unknown. 084 * 085 * @return the dimensionality of this envelope. 086 * 087 * @departure easeOfUse 088 * ISO does not define this method - the CRS or the dimension can be obtained only through 089 * one of the corner {@code DirectPosition} objects. GeoAPI adds this method for convenience 090 * as a more direct way of obtaining the information and to free the user from the need to 091 * choose an arbitrary corner (very defensive code might feel the need to get the value from 092 * both corners to check they were the same). 093 */ 094 int getDimension(); 095 096 /** 097 * The limits in the direction of decreasing coordinate values for each dimension. 098 * This is typically a coordinate position consisting of all the minimal coordinates 099 * for each dimension for all points within the {@code Envelope}. 100 * 101 * <h4>Crossing the anti-meridian of a geographic CRS</h4> 102 * The <cite>Web Coverage Service</cite> (WCS) 1.1 specification uses an extended interpretation 103 * of the bounding box definition. In a WCS 1.1 data structure, the lower corner defines the 104 * edges region in the directions of <em>decreasing</em> coordinate values in the envelope CRS. 105 * This is usually the algebraic {@linkplain #getMinimum(int) minimum} coordinates, but not 106 * always. For example, an envelope crossing the anti-meridian could have a lower corner 107 * longitude greater than the {@linkplain #getUpperCorner() upper corner} longitude. 108 * Whether this envelope supports the extended bounding box interpretation or not is 109 * implementation-dependent. If supported, the extended interpretation is applicable only to 110 * axes having a {@link RangeMeaning#WRAPAROUND WRAPAROUND} range meaning - usually the 111 * longitude axis. On typical map representations, the {@code getLowerCorner()} method 112 * name still "visually" appropriate since the <i>lower</i> corner still toward the 113 * bottom of the map even if the left corner became the right corner. 114 * 115 * @return the lower corner, typically (but not necessarily) containing minimal coordinate values. 116 */ 117 @UML(identifier="lowerCorner", obligation=MANDATORY, specification=ISO_19107) 118 DirectPosition getLowerCorner(); 119 120 /** 121 * The limits in the direction of increasing coordinate values for each dimension. 122 * This is typically a coordinate position consisting of all the maximal coordinates 123 * for each dimension for all points within the {@code Envelope}. 124 * 125 * <h4>Crossing the anti-meridian of a geographic CRS</h4> 126 * The <cite>Web Coverage Service</cite> (WCS) 1.1 specification uses an extended interpretation 127 * of the bounding box definition. In a WCS 1.1 data structure, the upper corner defines the 128 * edges region in the directions of <em>increasing</em> coordinate values in the envelope CRS. 129 * This is usually the algebraic {@linkplain #getMaximum(int) maximum} coordinates, but not 130 * always. For example, an envelope crossing the anti-meridian could have an upper corner 131 * longitude less than the {@linkplain #getLowerCorner() lower corner} longitude. 132 * Whether this envelope supports the extended bounding box interpretation or not is 133 * implementation-dependent. If supported, the extended interpretation is applicable only to 134 * axes having a {@link RangeMeaning#WRAPAROUND WRAPAROUND} range meaning - usually the 135 * longitude axis. On typical map representations, the {@code getUpperCorner()} method 136 * name still "visually" appropriate since the <i>upper</i> corner still toward the 137 * top of the map even if the right corner became the left corner. 138 * 139 * @return the upper corner, typically (but not necessarily) containing maximal coordinate values. 140 */ 141 @UML(identifier="upperCorner", obligation=MANDATORY, specification=ISO_19107) 142 DirectPosition getUpperCorner(); 143 144 /** 145 * Returns the minimal coordinate value for the specified dimension. In the typical case of 146 * non-empty envelopes <em>not</em> crossing the anti-meridian, this method is a shortcut 147 * for the following code without the cost of creating a temporary {@link DirectPosition} 148 * object: 149 * 150 * <blockquote><code> 151 * minimum = {@linkplain #getLowerCorner()}.{@linkplain DirectPosition#getCoordinate(int) getCoordinate}(dimension); 152 * </code></blockquote> 153 * 154 * <h4>Crossing the anti-meridian of a geographic CRS</h4> 155 * If the axis range meaning is {@link RangeMeaning#WRAPAROUND WRAPAROUND} and this envelope 156 * supports the {@linkplain #getLowerCorner() lower} and {@linkplain #getUpperCorner() upper} 157 * corners extended interpretation, then <var>lower</var> may possibly be greater than 158 * <var>upper</var>. In such case, implementations shall select some value such that 159 * <var>minimum</var> < <var>maximum</var> (ignoring NaN). It may be the 160 * {@linkplain org.opengis.referencing.cs.CoordinateSystemAxis#getMinimumValue() axis minimum value}, 161 * {@linkplain Double#NEGATIVE_INFINITY negative infinity}, {@linkplain Double#NaN NaN} or other 162 * value, at implementer choice. 163 * 164 * @param dimension the dimension for which to obtain the coordinate value. 165 * @return the minimal coordinate at the given dimension. 166 * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater 167 * than the {@linkplain #getDimension() envelope dimension}. 168 * 169 * @departure easeOfUse 170 * This method is not part of ISO specification. GeoAPI adds this method for convenience and efficiency, 171 * since some implementations might store the minimum and maximum coordinate values directly in the 172 * {@code Envelope} itself rather than in a contained {@code DirectPosition} corner. 173 * 174 * @see Rectangle2D#getMinX() 175 * @see Rectangle2D#getMinY() 176 */ 177 double getMinimum(int dimension) throws IndexOutOfBoundsException; 178 179 /** 180 * Returns the maximal coordinate value for the specified dimension. In the typical case of 181 * non-empty envelopes <em>not</em> crossing the anti-meridian, this method is a shortcut 182 * for the following code without the cost of creating a temporary {@link DirectPosition} 183 * object: 184 * 185 * <blockquote><code> 186 * maximum = {@linkplain #getUpperCorner()}.{@linkplain DirectPosition#getCoordinate(int) getCoordinate}(dimension); 187 * </code></blockquote> 188 * 189 * <h4>Crossing the anti-meridian of a geographic CRS</h4> 190 * If the axis range meaning is {@link RangeMeaning#WRAPAROUND WRAPAROUND} and this envelope 191 * supports the {@linkplain #getLowerCorner() lower} and {@linkplain #getUpperCorner() upper} 192 * corners extended interpretation, then <var>upper</var> may possibly be less than 193 * <var>lower</var>. In such case, implementations shall select some value such that 194 * <var>maximum</var> > <var>minimum</var> (ignoring NaN). It may be the 195 * {@linkplain org.opengis.referencing.cs.CoordinateSystemAxis#getMaximumValue() axis maximum value}, 196 * {@linkplain Double#POSITIVE_INFINITY positive infinity}, {@linkplain Double#NaN NaN} or other 197 * value, at implementer choice. 198 * 199 * @param dimension the dimension for which to obtain the coordinate value. 200 * @return the maximal coordinate at the given dimension. 201 * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater 202 * than the {@linkplain #getDimension() envelope dimension}. 203 * 204 * @departure easeOfUse 205 * This method is not part of ISO specification. GeoAPI adds this method for convenience and efficiency, 206 * since some implementations might store the minimum and maximum coordinate values directly in the 207 * {@code Envelope} itself rather than in a contained {@code DirectPosition} corner. 208 * 209 * @see Rectangle2D#getMaxX() 210 * @see Rectangle2D#getMaxY() 211 */ 212 double getMaximum(int dimension) throws IndexOutOfBoundsException; 213 214 /** 215 * Returns the median coordinate along the specified dimension. 216 * In most cases, the result is equal (minus rounding error) to: 217 * 218 * <blockquote><code> 219 * median = ({@linkplain #getMinimum(int) getMinimum}(dimension) + {@linkplain #getMaximum(int) getMaximum}(dimension)) / 2; 220 * </code></blockquote> 221 * 222 * <h4>Crossing the anti-meridian of a geographic CRS</h4> 223 * If this envelope supports the {@linkplain #getLowerCorner() lower} and 224 * {@linkplain #getUpperCorner() upper} corners extended interpretation, and if the axis 225 * range meaning is {@link RangeMeaning#WRAPAROUND WRAPAROUND}, then a special cases occurs 226 * when <var>upper</var> < <var>lower</var>. In such cases, the coordinate values from the 227 * lower and upper corner may be used instead of the minimum and maximum values, with the 228 * periodicity (360° for longitudes) added to the upper value before to perform the median calculation. 229 * Implementations are free to use variants of the above algorithm. For example some 230 * libraries may add different multiples of the periodicity in order to ensure that the 231 * median value is inside the axis range. 232 * 233 * @param dimension the dimension for which to obtain the coordinate value. 234 * @return the median coordinate at the given dimension. 235 * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater 236 * than the {@linkplain #getDimension() envelope dimension}. 237 * 238 * @departure easeOfUse 239 * This method is not part of ISO specification. GeoAPI adds this method for convenience and efficiency, 240 * since some implementations might store the minimum and maximum coordinate values directly in the 241 * {@code Envelope} itself rather than in a contained {@code DirectPosition} corner. 242 * 243 * @see Rectangle2D#getCenterX() 244 * @see Rectangle2D#getCenterY() 245 */ 246 double getMedian(int dimension) throws IndexOutOfBoundsException; 247 248 /** 249 * Returns the envelope span (typically width or height) along the specified dimension. 250 * In most cases, the result is equal (minus rounding error) to: 251 * 252 * <blockquote><code> 253 * span = {@linkplain #getMaximum(int) getMaximum}(dimension) - {@linkplain #getMinimum(int) getMinimum}(dimension); 254 * </code></blockquote> 255 * 256 * <h4>Crossing the anti-meridian of a geographic CRS</h4> 257 * If this envelope supports the {@linkplain #getLowerCorner() lower} and 258 * {@linkplain #getUpperCorner() upper} corners extended interpretation, and if the axis 259 * range meaning is {@link RangeMeaning#WRAPAROUND WRAPAROUND}, then a special cases occurs 260 * when <var>upper</var> < <var>lower</var>. In such cases, the coordinate values from the 261 * lower and upper corner may be used instead of the minimum and maximum values, with the 262 * periodicity (360° for longitudes) added to the upper value before to perform the span calculation. 263 * Implementations are free to use variants of the above algorithm. For example some 264 * libraries may add different multiples of the periodicity. 265 * 266 * @param dimension the dimension for which to obtain the span. 267 * @return the span (typically width or height) at the given dimension. 268 * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater 269 * than the {@linkplain #getDimension() envelope dimension}. 270 * 271 * @departure easeOfUse 272 * This method is not part of ISO specification. GeoAPI adds this method for convenience and efficiency, 273 * since some implementations might store the span values directly in the {@code Envelope} itself rather 274 * than calculating it from the corners. 275 * 276 * @see Rectangle2D#getWidth() 277 * @see Rectangle2D#getHeight() 278 */ 279 double getSpan(int dimension) throws IndexOutOfBoundsException; 280}