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