1   /* Copyright 2002-2024 Thales Alenia Space
2    * Licensed to CS Communication & Systèmes (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.models.earth.troposphere.iturp834;
18  
19  /** Holder for one cell of grid data surrounding one point.
20   * @author Luc Maisonobe
21   * @since 13.0
22   */
23  class GridCell {
24  
25      /** Latitude difference with respect to South cell edge. */
26      private final double deltaSouth;
27  
28      /** Longitude difference with respect to West cell edge. */
29      private final double deltaWest;
30  
31      /** Cell size in latitude. */
32      private final double sizeLat;
33  
34      /** Cell size in longitude. */
35      private final double sizeLon;
36  
37      /** North-West value. */
38      private final double nw;
39  
40      /** South-West value. */
41      private final double sw;
42  
43      /** South-East value. */
44      private final double se;
45  
46      /** North-East value. */
47      private final double ne;
48  
49      /**
50       * Build a grid cell from corner data.
51       *
52       * @param deltaSouth point latitude minus South cell edge latitude
53       * @param deltaWest  point longitude minus West cell edge longitude
54       * @param sizeLat    cell size in latitude
55       * @param sizeLon    cell size in longitude
56       * @param nw         North-West value
57       * @param sw         South-West value
58       * @param se         South-East value
59       * @param ne         North-East value
60       */
61      GridCell(final double deltaSouth, final double deltaWest, final double sizeLat, final double sizeLon,
62               final double nw, final double sw, final double se, final double ne) {
63          this.deltaSouth = deltaSouth;
64          this.deltaWest  = deltaWest;
65          this.sizeLat    = sizeLat;
66          this.sizeLon    = sizeLon;
67          this.nw         = nw;
68          this.sw         = sw;
69          this.se         = se;
70          this.ne         = ne;
71      }
72  
73      /** Build a grid cell by applying a function to two existing cells.
74       * <p>
75       * The cells are expected to be consistent (i.e. same locations,
76       * same sizes), but no verification is done here. It works in
77       * the context of ITR-R P.834 because the grids have similar
78       * samplings, it would not work fro general and inconsistent grids.
79       * </p>
80       * @param function function to apply to all cells corners
81       * @param cell1 first cell
82       * @param cell2 second cell
83       */
84      GridCell(final BiFunction function,
85               final GridCell cell1, final GridCell cell2) {
86          this.deltaSouth = cell1.deltaSouth;
87          this.deltaWest  = cell1.deltaWest;
88          this.sizeLat    = cell1.sizeLat;
89          this.sizeLon    = cell1.sizeLon;
90          this.nw         = function.apply(cell1.nw, cell2.nw);
91          this.sw         = function.apply(cell1.sw, cell2.sw);
92          this.se         = function.apply(cell1.se, cell2.se);
93          this.ne         = function.apply(cell1.ne, cell2.ne);
94      }
95  
96      /** Build a grid cell by applying a function to three existing cells.
97       * <p>
98       * The cells are expected to be consistent (i.e. same locations,
99       * same sizes), but no verification is done here. It works in
100      * the context of ITR-R P.834 because the grids have similar
101      * samplings, it would not work fro general and inconsistent grids.
102      * </p>
103      * @param function function to apply to all cells corners
104      * @param cell1 first cell
105      * @param cell2 second cell
106      * @param cell3 third cell
107      */
108     GridCell(final TriFunction function,
109              final GridCell cell1, final GridCell cell2, final GridCell cell3) {
110         this.deltaSouth = cell1.deltaSouth;
111         this.deltaWest  = cell1.deltaWest;
112         this.sizeLat    = cell1.sizeLat;
113         this.sizeLon    = cell1.sizeLon;
114         this.nw         = function.apply(cell1.nw, cell2.nw, cell3.nw);
115         this.sw         = function.apply(cell1.sw, cell2.sw, cell3.sw);
116         this.se         = function.apply(cell1.se, cell2.se, cell3.se);
117         this.ne         = function.apply(cell1.ne, cell2.ne, cell3.ne);
118     }
119 
120     /** Build a grid cell by applying a function to four existing cells.
121      * <p>
122      * The cells are expected to be consistent (i.e. same locations,
123      * same sizes), but no verification is done here. It works in
124      * the context of ITR-R P.834 because the grids have similar
125      * samplings, it would not work fro general and inconsistent grids.
126      * </p>
127      * @param function function to apply to all cells corners
128      * @param cell1 first cell
129      * @param cell2 second cell
130      * @param cell3 third cell
131      * @param cell4 fourth cell
132      */
133     GridCell(final QuarticFunction function,
134              final GridCell cell1, final GridCell cell2,
135              final GridCell cell3, final GridCell cell4) {
136         this.deltaSouth = cell1.deltaSouth;
137         this.deltaWest  = cell1.deltaWest;
138         this.sizeLat    = cell1.sizeLat;
139         this.sizeLon    = cell1.sizeLon;
140         this.nw         = function.apply(cell1.nw, cell2.nw, cell3.nw, cell4.nw);
141         this.sw         = function.apply(cell1.sw, cell2.sw, cell3.sw, cell4.sw);
142         this.se         = function.apply(cell1.se, cell2.se, cell3.se, cell4.se);
143         this.ne         = function.apply(cell1.ne, cell2.ne, cell3.ne, cell4.ne);
144     }
145 
146     /** Build a grid cell by applying a function to five existing cells.
147      * <p>
148      * The cells are expected to be consistent (i.e. same locations,
149      * same sizes), but no verification is done here. It works in
150      * the context of ITR-R P.834 because the grids have similar
151      * samplings, it would not work fro general and inconsistent grids.
152      * </p>
153      * @param function function to apply to all cells corners
154      * @param cell1 first cell
155      * @param cell2 second cell
156      * @param cell3 third cell
157      * @param cell4 fourth cell
158      * @param cell5 fifth cell
159      */
160     GridCell(final QuinticFunction function,
161              final GridCell cell1, final GridCell cell2, final GridCell cell3,
162              final GridCell cell4, final GridCell cell5) {
163         this.deltaSouth = cell1.deltaSouth;
164         this.deltaWest  = cell1.deltaWest;
165         this.sizeLat    = cell1.sizeLat;
166         this.sizeLon    = cell1.sizeLon;
167         this.nw         = function.apply(cell1.nw, cell2.nw, cell3.nw, cell4.nw, cell5.nw);
168         this.sw         = function.apply(cell1.sw, cell2.sw, cell3.sw, cell4.sw, cell5.sw);
169         this.se         = function.apply(cell1.se, cell2.se, cell3.se, cell4.se, cell5.se);
170         this.ne         = function.apply(cell1.ne, cell2.ne, cell3.ne, cell4.ne, cell5.ne);
171     }
172 
173     /** Evaluate cell value at point location using bi-linear interpolation.
174      * @return cell value at point location
175      */
176     public double evaluate() {
177         final double deltaNorth = sizeLat - deltaSouth;
178         final double deltaEast  = sizeLon - deltaWest;
179         return (deltaSouth * (deltaWest * ne + deltaEast * nw) +
180                 deltaNorth * (deltaWest * se + deltaEast * sw)) /
181                (sizeLat * sizeLon);
182     }
183 
184     /** Interface for function that can be applied to the corners of two cells. */
185     @FunctionalInterface
186     public interface BiFunction {
187         /** Apply function to similar corners coming from two cells.
188          * @param corner1 value at corner of first cell
189          * @param corner2 value at corner of second cell
190          * @return function evaluated at similar corners of two cells
191          */
192         double apply(double corner1, double corner2);
193     }
194 
195     /** Interface for function that can be applied to the corners of three cells. */
196     @FunctionalInterface
197     public interface TriFunction {
198         /** Apply function to similar corners coming from three cells.
199          * @param corner1 value at corner of first cell
200          * @param corner2 value at corner of second cell
201          * @param corner3 value at corner of third cell
202          * @return function evaluated at similar corners of three cells
203          */
204         double apply(double corner1, double corner2, double corner3);
205     }
206 
207     /** Interface for function that can be applied to the corners of four cells. */
208     @FunctionalInterface
209     public interface QuarticFunction {
210         /** Apply function to similar corners coming from four cells.
211          * @param corner1 value at corner of first cell
212          * @param corner2 value at corner of second cell
213          * @param corner3 value at corner of third cell
214          * @param corner4 value at corner of fourth cell
215          * @return function evaluated at similar corners of four cells
216          */
217         double apply(double corner1, double corner2, double corner3, double corner4);
218     }
219 
220     /** Interface for function that can be applied to the corners of five cells. */
221     @FunctionalInterface
222     public interface QuinticFunction {
223         /** Apply function to similar corners coming from five cells.
224          * @param corner1 value at corner of first cell
225          * @param corner2 value at corner of second cell
226          * @param corner3 value at corner of third cell
227          * @param corner4 value at corner of fourth cell
228          * @param corner5 value at corner of fifth cell
229          * @return function evaluated at similar corners of five cells
230          */
231         double apply(double corner1, double corner2, double corner3, double corner4, double corner5);
232     }
233 
234 }