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.util.FastMath;
20  import org.hipparchus.util.MathUtils;
21  
22  /**
23   * To simulate DEM SRTM3 V4.0 tiles (without the real data !)
24   * The tiles are seamless = no overlapping 
25   * 
26   * @author Guylaine Prat
27   */
28  public class DummySRTMsimpleElevationUpdater implements TileUpdater {
29      
30      /** SRTM tile size (deg) */
31      private double tileSizeDeg = 5.;
32  
33      /** SRTM tile step (rad) */
34      private double stepRad;
35  
36      /** SRTM tile number of rows and columns */
37      private int n;
38      
39      /** Factor to change resolution above 60 degrees and below 60 degrees */
40      private int resolutionChange;
41  
42      private double elevation1;
43      private double elevation2;
44      
45      /**
46       * Constructor with dummy elevations to fill in the tile ...
47       * @param rowCol SRTM tile number of rows and column
48       * @param elevation1 chosen elevation1 (m)
49       * @param elevation2 chosen elevation2 (m)
50       * @param resolutionChange factor to change resolution at +/- 60 degrees
51       */
52      public DummySRTMsimpleElevationUpdater(final int rowCol, final double elevation1, final double elevation2, final int resolutionChange) {
53          
54          this.n = rowCol;
55          this.stepRad = FastMath.toRadians(this.tileSizeDeg / this.n);
56          this.resolutionChange = resolutionChange;
57          
58          this.elevation1 = elevation1;
59          this.elevation2 = elevation2;
60      }
61  
62      /**
63       * Update the tile
64       * @param latitude latitude (rad)
65       * @param longitude longitude (rad)
66       * @param tile to be updated
67       */
68      public void updateTile(final double latitude, final double longitude, UpdatableTile tile) {
69  
70          int numberOfStep;
71          
72          // Change the tile step for latitude above 60 degrees and below 60 degrees
73          if (FastMath.toDegrees(latitude) > 60. || FastMath.toDegrees(latitude) < -60.) {
74              // step * resolutionChange for latitude > 60 or < -60
75              this.stepRad = FastMath.toRadians(this.tileSizeDeg*this.resolutionChange / this.n);
76              numberOfStep = this.n/this.resolutionChange;
77  
78          } else { // step = tile size / n
79              this.stepRad = FastMath.toRadians(this.tileSizeDeg / this.n);
80              numberOfStep = this.n;
81          }
82          
83          // Get the tile indices that contents the current latitude and longitude
84          int[] tileIndex = findIndexInTile(latitude, longitude);
85          double latIndex = tileIndex[0];
86          double lonIndex = tileIndex[1];
87  
88          // Init the tile geometry with the Rugged convention: 
89          //   the minimum latitude and longitude correspond to the center of the most South-West cell, 
90          //   and the maximum latitude and longitude correspond to the center of the most North-East cell.
91          // For SRTM : origin latitude is at North of the tile (and latitude step is < 0)
92          double minLatitude = FastMath.toRadians(60. - latIndex*5.) + 0.5*stepRad;
93          double minLongitude = FastMath.toRadians(-180. + (lonIndex - 1)*5.) + 0.5*stepRad;
94  
95          tile.setGeometry(minLatitude, minLongitude, stepRad, stepRad, numberOfStep, numberOfStep);
96  
97          for (int i = 0; i < numberOfStep; ++i) {
98              int p = (int) FastMath.floor((FastMath.abs(minLatitude) + i * stepRad) / stepRad);
99              for (int j = 0; j < numberOfStep; ++j) {
100                 int q = (int) FastMath.floor((FastMath.abs(minLongitude) + j * stepRad) / stepRad);
101                 double factor = FastMath.sin(minLatitude + i*stepRad - (minLongitude + j*stepRad))*
102                                 FastMath.cos(minLatitude + i*stepRad + (minLongitude + j*stepRad));
103                 tile.setElevation(i, j, (((p ^ q) & 0x1) == 0) ? factor*lonIndex*elevation1 + q  : factor*latIndex*elevation2 + q*p);
104             }
105         }
106     }
107     
108     /**
109      * Find tile indices that contain the given (latitude, longitude)
110      * @param latitude latitude (rad)
111      * @param longitude longitude (rad)
112      * @return array : [0] = latitude tile index and [1] = longitude tile index
113      */
114     private int[] findIndexInTile(final double latitude, final double longitude) {
115         
116       double latDeg = FastMath.toDegrees(latitude);
117       
118       // Assure that the longitude belongs to [-180, + 180]
119       double lonDeg = FastMath.toDegrees(MathUtils.normalizeAngle(longitude, 0.0));
120 
121       // Compute longitude tile name with longitude value: 
122       // For SRTM with 5 degrees tiles: tile longitude index 1 starts at 180 deg W; tile longitude index 72 starts at 175 deg E
123       int tileLongIndex = (int) (1 + (lonDeg + 180.)/5.); 
124 
125       // Compute latitude tile name with latitude value: 
126       // For SRTM with 5 degrees tiles: tile latitude index 1 starts at 60 deg N; tile latitude index 23 starts at 50 deg S
127       int tileLatIndex = (int) (1 + (60. - latDeg)/5.); 
128 
129       return new int[] {tileLatIndex, tileLongIndex};
130     }
131     
132     public double getTileStepDeg() {
133         return FastMath.toDegrees(this.stepRad);
134     }
135     
136     public double getTileSizeDeg() {
137         return this.tileSizeDeg;
138     }
139 }