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 org.opengis.geometry.coordinate.Position; 021import org.opengis.referencing.crs.CoordinateReferenceSystem; 022import org.opengis.annotation.UML; 023import org.opengis.annotation.Classifier; 024import org.opengis.annotation.Stereotype; 025 026import static org.opengis.annotation.Obligation.*; 027import static org.opengis.annotation.Specification.*; 028 029 030/** 031 * Holds the coordinates for a position within some coordinate reference system. 032 * Since {@code DirectPosition}s, as data types, will often be included in larger objects 033 * (such as {@linkplain org.opengis.geometry.Geometry geometries}) that have references to 034 * {@linkplain CoordinateReferenceSystem coordinate reference system} (CRS), 035 * the {@link #getCoordinateReferenceSystem()} method may return {@code null} if this particular 036 * {@code DirectPosition} is included in a larger object with such a reference to a <abbr>CRS</abbr>. 037 * In this case, the coordinate reference system is implicitly assumed to take on the value 038 * of the containing object's <abbr>CRS</abbr>. 039 * 040 * <h2>Optional operation</h2> 041 * A direct position can optionally be modifiable. If this {@code DirectPosition} is unmodifiable, 042 * then all setter methods will throw {@link UnsupportedOperationException}. 043 * 044 * @departure easeOfUse 045 * The ISO specification defines this interface in the {@code coordinate} sub-package. 046 * GeoAPI moved this interface into the {@code org.opengis.geometry} root package for 047 * convenience, because it is extensively used. 048 * 049 * @author Martin Desruisseaux (IRD, Geomatys) 050 * @version 3.1 051 * @since 1.0 052 */ 053@Classifier(Stereotype.DATATYPE) 054@UML(identifier="DirectPosition", specification=ISO_19107) 055public interface DirectPosition extends Position { 056 /** 057 * Returns this direct position. 058 * 059 * @return {@code this} (usually). 060 * 061 * @deprecated This method is inherited from {@code GM_Position}, which has been removed in ISO 19107:2019. 062 */ 063 @Override 064 @Deprecated(since = "3.1") 065 default DirectPosition getDirectPosition() { 066 return this; 067 } 068 069 /** 070 * The coordinate reference system (CRS) in which the coordinate tuple is given. 071 * May be {@code null} if this particular {@code DirectPosition} is included in a larger object 072 * with such a reference to a {@linkplain CoordinateReferenceSystem coordinate reference system}. 073 * In this case, the coordinate reference system is implicitly assumed to take on the value 074 * of the containing object's <abbr>CRS</abbr>. 075 * 076 * <h4>Default implementation</h4> 077 * The default implementation returns {@code null}. Implementations should override 078 * this method if the <abbr>CRS</abbr> is known or can be taken from the containing object. 079 * 080 * @return the coordinate reference system (CRS), or {@code null}. 081 */ 082 @UML(identifier="coordinateReferenceSystem", obligation=MANDATORY, specification=ISO_19107) 083 default CoordinateReferenceSystem getCoordinateReferenceSystem() { 084 return null; 085 } 086 087 /** 088 * The length of coordinate sequence (the number of entries). This is determined by the 089 * {@linkplain #getCoordinateReferenceSystem() coordinate reference system}. 090 * 091 * @return the dimensionality of this position. 092 */ 093 @UML(identifier="dimension", obligation=MANDATORY, specification=ISO_19107) 094 int getDimension(); 095 096 /** 097 * A <b>copy</b> of the coordinates stored as an array of double values. 098 * Changes to the returned array will not affect this {@code DirectPosition}. 099 * The array length shall be equal to the {@linkplain #getDimension() dimension}. 100 * 101 * <h4>Default implementation</h4> 102 * The default implementation invokes {@link #getCoordinate(int)} for all indices 103 * from 0 inclusive to {@link #getDimension()} exclusive, and stores the values 104 * in a newly created array. 105 * 106 * @return a copy of the coordinates. Changes in the returned array will not be reflected back 107 * in this {@code DirectPosition} object. 108 * 109 * @since 3.1 110 */ 111 @UML(identifier="coordinate", obligation=MANDATORY, specification=ISO_19107) 112 default double[] getCoordinates() { 113 final double[] coordinates = new double[getDimension()]; 114 for (int i=0; i<coordinates.length; i++) { 115 coordinates[i] = getCoordinate(i); 116 } 117 return coordinates; 118 } 119 120 /** 121 * A <b>copy</b> of the coordinates presented as an array of double values. 122 * 123 * @return a copy of the coordinates. Changes in the returned array will not be reflected back 124 * in this {@code DirectPosition} object. 125 * 126 * @deprecated Renamed {@link #getCoordinates()}. 127 * To be removed because of the risk of confusion with {@link #getCoordinate(int)}. 128 */ 129 @Deprecated(since="3.1", forRemoval=true) 130 default double[] getCoordinate() { 131 return getCoordinates(); 132 } 133 134 /** 135 * Returns the coordinate at the specified dimension. 136 * 137 * @param dimension the dimension in the range 0 to {@linkplain #getDimension dimension}−1. 138 * @return the coordinate at the specified dimension. 139 * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater 140 * than the {@linkplain #getDimension() number of dimensions}. 141 * 142 * @since 3.1 143 */ 144 double getCoordinate(int dimension); 145 146 /** 147 * Returns the coordinate at the specified dimension. 148 * 149 * @param dimension the dimension in the range 0 to {@linkplain #getDimension dimension}−1. 150 * @return the coordinate at the specified dimension. 151 * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater 152 * than the {@linkplain #getDimension() number of dimensions}. 153 * 154 * @deprecated Renamed {@link #getCoordinate(int)}. 155 */ 156 @Deprecated(since = "3.1") 157 default double getOrdinate(int dimension) throws IndexOutOfBoundsException { 158 return getCoordinate(dimension); 159 } 160 161 /** 162 * Sets the coordinate value along the specified dimension. 163 * This is an optional operation. 164 * 165 * <h4>Default implementation</h4> 166 * The default implementation throws {@code UnsupportedOperationException}. 167 * Implementations need to override this method if this direct position is mutable. 168 * 169 * @param dimension the dimension for the coordinate of interest. 170 * @param value the coordinate value of interest. 171 * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater 172 * than the {@linkplain #getDimension() position dimension}. 173 * @throws UnsupportedOperationException if this direct position is immutable. 174 * 175 * @since 3.1 176 */ 177 default void setCoordinate(int dimension, double value) { 178 throw new UnsupportedOperationException(); 179 } 180 181 /** 182 * Sets the coordinate value along the specified dimension. 183 * 184 * @param dimension the dimension for the coordinate of interest. 185 * @param value the coordinate value of interest. 186 * @throws IndexOutOfBoundsException if the given index is negative or is equal or greater 187 * than the {@linkplain #getDimension() position dimension}. 188 * @throws UnsupportedOperationException if this direct position is immutable. 189 * 190 * @deprecated Renamed {@link #setCoordinate(int, double)}. 191 */ 192 @Deprecated(since = "3.1") 193 default void setOrdinate(int dimension, double value) 194 throws IndexOutOfBoundsException, UnsupportedOperationException 195 { 196 setCoordinate(dimension, value); 197 } 198 199 /** 200 * Compares this direct position with the specified object for equality. 201 * Two direct positions are considered equal if the following conditions are met: 202 * 203 * <ul> 204 * <li>{@code object} is non-null and is an instance of {@code DirectPosition}.</li> 205 * <li>Both direct positions have the same {@linkplain #getDimension() number of dimensions}.</li> 206 * <li>Both direct positions have the same or equal {@linkplain #getCoordinateReferenceSystem() 207 * coordinate reference system}.</li> 208 * <li>For all dimension <var>i</var>, the {@linkplain #getCoordinates coordinate value} of both 209 * direct positions at that dimension are equals in the sense of {@link Double#equals(Object)}.</li> 210 * </ul> 211 * 212 * In other words, this method shall be equivalent to the following code: 213 * 214 * {@snippet lang="java" : 215 * public boolean equals(Object obj) { 216 * return (obj instanceof DirectPosition other) 217 * && Arrays.equals(getCoordinates(), other.getCoordinates()) 218 * && Objects.equals(getCoordinateReferenceSystem(), other.getCoordinateReferenceSystem()); 219 * } 220 * } 221 * 222 * @param object the object to compare with this direct position for equality. 223 * @return {@code true} if the given object is equal to this direct position. 224 */ 225 @Override 226 boolean equals(Object object); 227 228 /** 229 * Returns a hash code value for this direct position. 230 * This method shall be equivalent to the following code: 231 * 232 * {@snippet lang="java" : 233 * public int hashCode() { 234 * return Arrays.hashCode(getCoordinates()) + Objects.hashCode(getCoordinateReferenceSystem()); 235 * } 236 * } 237 * 238 * @return a hash code value for this direct position. 239 */ 240 @Override 241 int hashCode(); 242}