1 /* Copyright 2002-2026 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.models.earth.tessellation;
18
19 import java.io.Serial;
20 import java.io.Serializable;
21
22 import org.hipparchus.geometry.euclidean.threed.Vector3D;
23 import org.hipparchus.util.FastMath;
24 import org.orekit.bodies.GeodeticPoint;
25
26 /** Simple data structure for a quadrilateral tile shape on a body surface.
27 * <p>
28 * This class is devoted to simple usage only. It assumes the edges
29 * are strictly between 0 and π radians and that the angles between
30 * edges are also strictly between 0 and π radians.
31 * </p>
32 * @see AlongTrackAiming
33 * @see ConstantAzimuthAiming
34 * @author Luc Maisonobe
35 */
36 public class Tile implements Serializable {
37
38 /** Serializable UID. */
39 @Serial
40 private static final long serialVersionUID = 20150313L;
41
42 /** First vertex. */
43 private final GeodeticPoint v0;
44
45 /** Second vertex. */
46 private final GeodeticPoint v1;
47
48 /** Third vertex. */
49 private final GeodeticPoint v2;
50
51 /** Fourth vertex. */
52 private final GeodeticPoint v3;
53
54 /** Create a tile.
55 * <p>
56 * It is caller responsibility o ensure the vertices define a
57 * simple non-degenerated tile (i.e. edges are strictly between
58 * 0 than π radians and angles between edges are also strictly
59 * between 0 and π radians). No checks are performed here.
60 * </p>
61 * @param v0 first vertex
62 * @param v1 second vertex
63 * @param v2 third vertex
64 * @param v3 fourth vertex
65 */
66 public Tile(final GeodeticPoint v0, final GeodeticPoint v1,
67 final GeodeticPoint v2, final GeodeticPoint v3) {
68 this.v0 = v0;
69 this.v1 = v1;
70 this.v2 = v2;
71 this.v3 = v3;
72 }
73
74 /** Get the four vertices.
75 * @return four vertices
76 */
77 public GeodeticPoint[] getVertices() {
78 return new GeodeticPoint[] {
79 v0, v1, v2, v3
80 };
81 }
82
83 /** Get an interpolated point inside the tile.
84 * <p>
85 * The interpolated point is based on bilinear interpolations
86 * along the body surface assumed to be <em>spherical</em>,
87 * and along the vertical axis.
88 * </p>
89 * <p>
90 * The interpolation parameters are chosen such that
91 * (u = 0, v = 0) maps to vertex v0, (u = 1, v = 0) maps
92 * to vertex v1, (u = 1, v = 1) maps to vertex v2 and
93 * (u = 0, v = 1) maps to vertex v3.
94 * </p>
95 * @param u first interpolation parameter (should be between
96 * 0 and 1 to remain inside the tile)
97 * @param v second interpolation parameter (should be between
98 * 0 and 1 to remain inside the tile)
99 * @return interpolated point
100 */
101 public GeodeticPoint getInterpolatedPoint(final double u, final double v) {
102
103 // bilinear interpolation along a spherical shape
104 final Vector3D pu0 = interpolate(v0.getZenith(), v1.getZenith(), u);
105 final Vector3D pu1 = interpolate(v3.getZenith(), v2.getZenith(), u);
106 final Vector3D puv = interpolate(pu0, pu1, v);
107
108 // bilinear interpolation of altitude
109 final double hu0 = v1.getAltitude() * u + v0.getAltitude() * (1 - u);
110 final double hu1 = v2.getAltitude() * u + v3.getAltitude() * (1 - u);
111 final double huv = hu1 * v + hu0 * (1 - v);
112
113 // create interpolated point
114 return new GeodeticPoint(puv.getDelta(), puv.getAlpha(), huv);
115
116 }
117
118 /** Interpolate a vector along a unit sphere.
119 * @param p0 first base unit vector
120 * @param p1 second base unit vector
121 * @param r interpolation parameter (0 for p0, 1 for p1)
122 * @return interpolated unit vector
123 */
124 private Vector3D interpolate(final Vector3D p0, final Vector3D p1, final double r) {
125
126 // find all interpolation angles
127 final double theta = Vector3D.angle(p0, p1);
128 final double alpha = r * theta;
129 final double thetaMAlpha = (1 - r) * theta;
130
131 final double sinTheta = FastMath.sin(theta);
132 final double sinAlpha = FastMath.sin(alpha);
133 final double sinThetaMAlpha = FastMath.sin(thetaMAlpha);
134
135 // interpolate
136 return new Vector3D(sinThetaMAlpha / sinTheta, p0, sinAlpha / sinTheta, p1);
137
138 }
139
140 /** Get the center point.
141 * <p>
142 * The center points corresponds to {@link
143 * #getInterpolatedPoint(double, double) getInterpolatedPoint(0.5, 0.5)}
144 * </p>
145 * @return center point
146 */
147 public GeodeticPoint getCenter() {
148 return getInterpolatedPoint(0.5, 0.5);
149 }
150
151 }