1   /* Copyright 2013-2025 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.rugged.raster;
18  
19  import org.hipparchus.geometry.euclidean.threed.Vector3D;
20  import org.orekit.rugged.utils.NormalizedGeodeticPoint;
21  
22  /** Interface representing a raster tile.
23   * <p>
24   * The elevations are considered to be at the <em>center</em> of each cells.
25   * The minimum latitude and longitude hence correspond to the <em>center</em>
26   * of the most South-West cell, and the maximum latitude and longitude
27   * correspond to the <em>center</em> of the most North-East cell.
28   * </p>
29   * @author Luc Maisonobe
30   * @author Guylaine Prat
31   */
32  public interface Tile extends UpdatableTile {
33  
34      /** Enumerate for point location with respect to the interpolation grid of a tile.
35       * <p>
36       * Elevations in a tile are interpolated using the four neighboring points
37       * in a grid: (i, j), (i+1, j), (i, j+1), (i+1), (j+1). This implies that a point
38       * can be interpolated only if the elevation for these four points is available
39       * in the tile. A consequence is that a point in the northernmost row (resp.
40       * easternmost column) miss neighboring points at row j+1 (resp. neighboring points
41       * at column i+1) and therefore cannot be interpolated.
42       * </p>
43       * <p>
44       * This enumerate represent the position of a point taking this off-by-one property
45       * into account, the value {@link #HAS_INTERPOLATION_NEIGHBORS} correspond to points that
46       * do have the necessary four neighbors, whereas the other values correspond to points
47       * that are either completely outside of the tile or within the tile but in either the
48       * northernmost row or easternmost column.
49       * </p>
50       */
51      enum Location {
52  
53          /** Location for points out of tile interpolation grid, in the South-West corner direction. */
54          SOUTH_WEST,
55  
56          /** Location for points out of tile interpolation grid, in the West edge direction. */
57          WEST,
58  
59          /** Location for points out of tile interpolation grid, in the North-West corner direction.
60           * <p>
61           * The point may still be in the tile, but in the northernmost row thus missing required
62           * interpolation points.
63           * </p>
64           */
65          NORTH_WEST,
66  
67          /** Location for points out of tile interpolation grid, in the North edge direction.
68           * <p>
69           * The point may still be in the tile, but in the northernmost row thus missing required
70           * interpolation points.
71           * </p>
72           */
73          NORTH,
74  
75          /** Location for points out of tile interpolation grid, in the North-East corner direction.
76           * <p>
77           * The point may still be in the tile, but either in the northernmost row or in the
78           * easternmost column thus missing required interpolation points.
79           * </p>
80           */
81          NORTH_EAST,
82  
83          /** Location for points out of tile interpolation grid, in the East edge direction.
84           * <p>
85           * The point may still be in the tile, but in the easternmost column thus missing required
86           * interpolation points.
87           * </p>
88           */
89          EAST,
90  
91          /** Location for points out of tile interpolation grid, in the South-East corner direction.
92           * <p>
93           * The point may still be in the tile, but in the easternmost column thus missing required
94           * interpolation points.
95           * </p>
96           */
97          SOUTH_EAST,
98  
99          /** Location for points out of tile interpolation grid, in the South edge direction. */
100         SOUTH,
101 
102         /** Location for points that do have interpolation neighbors.
103          * <p>
104          * The value corresponds to points that can be interpolated using their four
105          * neighboring points in the grid at indices (i, j), (i+1, j), (i, j+1), (i+1),
106          * (j+1). This implies that these points are neither in the northernmost latitude
107          * row nor in the easternmost longitude column.
108          * </p>
109          */
110         HAS_INTERPOLATION_NEIGHBORS
111 
112     }
113 
114     /** Hook called at the end of tile update completion.
115      */
116     void tileUpdateCompleted();
117 
118     /** Get minimum latitude of grid interpolation points.
119      * @return minimum latitude of grid interpolation points (rad)
120      * (latitude of the center of the cells of South row)
121      */
122     double getMinimumLatitude();
123 
124     /** Get the latitude at some index.
125      * @param latitudeIndex latitude index
126      * @return latitude at the specified index (rad)
127      * (latitude of the center of the cells of specified row)
128      */
129     double getLatitudeAtIndex(int latitudeIndex);
130 
131     /** Get maximum latitude.
132      * <p>
133      * Beware that as a point at maximum latitude is the northernmost
134      * one of the grid, it doesn't have a northwards neighbor and
135      * therefore calling {@link #getLocation(double, double) getLocation}
136      * on such a latitude will return either {@link Location#NORTH_WEST},
137      * {@link Location#NORTH} or {@link Location#NORTH_EAST}, but can
138      * <em>never</em> return {@link Location#HAS_INTERPOLATION_NEIGHBORS}!
139      * </p>
140      * @return maximum latitude (rad)
141      * (latitude of the center of the cells of North row)
142      */
143     double getMaximumLatitude();
144 
145     /** Get minimum longitude.
146      * @return minimum longitude (rad)
147      * (longitude of the center of the cells of West column)
148      */
149     double getMinimumLongitude();
150 
151     /** Get the longitude at some index.
152      * @param longitudeIndex longitude index
153      * @return longitude at the specified index (rad)
154      * (longitude of the center of the cells of specified column)
155      */
156     double getLongitudeAtIndex(int longitudeIndex);
157 
158     /** Get maximum longitude.
159      * <p>
160      * Beware that as a point at maximum longitude is the easternmost
161      * one of the grid, it doesn't have an eastwards neighbor and
162      * therefore calling {@link #getLocation(double, double) getLocation}
163      * on such a longitude will return either {@link Location#SOUTH_EAST},
164      * {@link Location#EAST} or {@link Location#NORTH_EAST}, but can
165      * <em>never</em> return {@link Location#HAS_INTERPOLATION_NEIGHBORS}!
166      * </p>
167      * @return maximum longitude (rad)
168      * (longitude of the center of the cells of East column)
169      */
170     double getMaximumLongitude();
171 
172     /** Get step in latitude (size of one raster element).
173      * @return step in latitude (rad)
174      */
175     double getLatitudeStep();
176 
177     /** Get step in longitude (size of one raster element).
178      * @return step in longitude (rad)
179      */
180     double getLongitudeStep();
181 
182     /** Get number of latitude rows.
183      * @return number of latitude rows
184      */
185     int getLatitudeRows();
186 
187     /** Get number of longitude columns.
188      * @return number of longitude columns
189      */
190     int getLongitudeColumns();
191 
192     /** Get the floor latitude index of a point.
193      * <p>
194      * The specified latitude is always between index and index+1.
195      * </p>
196      * @param latitude geodetic latitude
197      * @return floor latitude index (it may lie outside of the tile!)
198      */
199     int getFloorLatitudeIndex(double latitude);
200 
201     /** Get the floor longitude index of a point.
202      * <p>
203      * The specified longitude is always between index and index+1.
204      * </p>
205      * @param longitude geodetic longitude
206      * @return floor longitude index (it may lie outside of the tile!)
207      */
208     int getFloorLongitudeIndex(double longitude);
209 
210     /** Get the minimum elevation in the tile.
211      * @return minimum elevation in the tile (m)
212      */
213     double getMinElevation();
214 
215     /** Get the latitude index of min elevation.
216      * @return latitude index of min elevation*/
217     int getMinElevationLatitudeIndex();
218 
219     /** Get the longitude index of min elevation.
220      * @return longitude index of min elevation*/
221     int getMinElevationLongitudeIndex();
222 
223    /** Get the maximum elevation in the tile.
224      * @return maximum elevation in the tile (m)
225      */
226     double getMaxElevation();
227 
228     /** Get the latitude index of max elevation.
229      * @return latitude index of max elevation*/
230     int getMaxElevationLatitudeIndex();
231 
232     /** Get the longitude index of max elevation.
233      * @return longitude index of max elevation*/
234     int getMaxElevationLongitudeIndex();
235 
236     /** Get the elevation of an exact grid point.
237      * @param latitudeIndex grid point index along latitude
238      * @param longitudeIndex grid point index along longitude
239      * @return elevation at grid point (m)
240      */
241     double getElevationAtIndices(int latitudeIndex, int longitudeIndex);
242 
243     /** Interpolate elevation.
244      * <p>
245      * In order to cope with numerical accuracy issues when computing
246      * points at tile boundary, a slight tolerance (typically 1/8 cell)
247      * around the tile is allowed. Elevation can therefore be interpolated
248      * (really extrapolated in this case) even for points slightly overshooting
249      * tile boundaries, using the closest tile cell. Attempting to interpolate
250      * too far from the tile will trigger an exception.
251      * </p>
252      * @param latitude ground point latitude
253      * @param longitude ground point longitude
254      * @return interpolated elevation (m)
255      */
256     double interpolateElevation(double latitude, double longitude);
257 
258     /** Find the intersection of a line-of-sight and a Digital Elevation Model cell.
259      * <p>
260      * Beware that for continuity reasons, the point argument in {@code cellIntersection} is normalized
261      * with respect to other points used by the caller. This implies that the longitude may be
262      * outside of the [-π ; +π] interval (or the [0 ; 2π] interval, depending on the DEM). In particular,
263      * when a Line Of Sight crosses the antimeridian at  ±π longitude, the library may call the
264      * {@code cellIntersection} method with a point having a longitude of -π-ε to ensure this continuity.
265      * As tiles are stored with longitude clipped to a some DEM specific interval (either  [-π ; +π] or [0 ; 2π]),
266      * implementations MUST take care to clip the input point back to the tile interval using
267      * {@link org.hipparchus.util.MathUtils#normalizeAngle(double, double) MathUtils.normalizeAngle(p.getLongitude(),
268      * someLongitudeWithinTheTile)}. The output point normalization should also be made consistent with
269      * the current tile.
270      * </p>
271      * @param p point on the line (beware its longitude is <em>not</em> normalized with respect to tile)
272      * @param los line-of-sight, in the topocentric frame (East, North, Zenith) of the point,
273      * scaled to match radians in the horizontal plane and meters along the vertical axis
274      * @param latitudeIndex latitude index of the Digital Elevation Model cell
275      * @param longitudeIndex longitude index of the Digital Elevation Model cell
276      * @return point corresponding to line-of-sight crossing the Digital Elevation Model surface
277      * if it lies within the cell, null otherwise
278      */
279     NormalizedGeodeticPoint cellIntersection(NormalizedGeodeticPoint p, Vector3D los,
280                                              int latitudeIndex, int longitudeIndex);
281 
282     /** Check if a tile covers a ground point.
283      * @param latitude ground point latitude
284      * @param longitude ground point longitude
285      * @return location of the ground point with respect to tile
286      */
287     Location getLocation(double latitude, double longitude);
288 
289 }