1 /* Copyright 2002-2019 CS Systèmes d'Information
2 * Licensed to CS Systèmes d'Information (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.bodies;
18
19 import java.io.Serializable;
20 import java.text.NumberFormat;
21
22 import org.hipparchus.geometry.euclidean.threed.Vector3D;
23 import org.hipparchus.util.CompositeFormat;
24 import org.hipparchus.util.FastMath;
25 import org.hipparchus.util.MathUtils;
26
27 /** Point location relative to a 2D body surface.
28 * <p>Instance of this class are guaranteed to be immutable.</p>
29 * @see BodyShape
30 * @see FieldGeodeticPoint
31 * @author Luc Maisonobe
32 */
33 public class GeodeticPoint implements Serializable {
34
35 /** Serializable UID. */
36 private static final long serialVersionUID = 7862466825590075399L;
37
38 /** Latitude of the point (rad). */
39 private final double latitude;
40
41 /** Longitude of the point (rad). */
42 private final double longitude;
43
44 /** Altitude of the point (m). */
45 private final double altitude;
46
47 /** Zenith direction. */
48 private transient Vector3D zenith;
49
50 /** Nadir direction. */
51 private transient Vector3D nadir;
52
53 /** North direction. */
54 private transient Vector3D north;
55
56 /** South direction. */
57 private transient Vector3D south;
58
59 /** East direction. */
60 private transient Vector3D east;
61
62 /** West direction. */
63 private transient Vector3D west;
64
65 /**
66 * Build a new instance. The angular coordinates will be normalized so that
67 * the latitude is between ±π/2 and the longitude is between ±π.
68 *
69 * @param latitude latitude of the point (rad)
70 * @param longitude longitude of the point (rad)
71 * @param altitude altitude of the point (m)
72 */
73 public GeodeticPoint(final double latitude, final double longitude,
74 final double altitude) {
75 double lat = MathUtils.normalizeAngle(latitude, FastMath.PI / 2);
76 double lon = MathUtils.normalizeAngle(longitude, 0);
77 if (lat > FastMath.PI / 2.0) {
78 // latitude is beyond the pole -> add 180 to longitude
79 lat = FastMath.PI - lat;
80 lon = MathUtils.normalizeAngle(longitude + FastMath.PI, 0);
81 }
82 this.latitude = lat;
83 this.longitude = lon;
84 this.altitude = altitude;
85 }
86
87 /** Get the latitude.
88 * @return latitude, an angular value in the range [-π/2, π/2]
89 */
90 public double getLatitude() {
91 return latitude;
92 }
93
94 /** Get the longitude.
95 * @return longitude, an angular value in the range [-π, π]
96 */
97 public double getLongitude() {
98 return longitude;
99 }
100
101 /** Get the altitude.
102 * @return altitude
103 */
104 public double getAltitude() {
105 return altitude;
106 }
107
108 /** Get the direction above the point, expressed in parent shape frame.
109 * <p>The zenith direction is defined as the normal to local horizontal plane.</p>
110 * @return unit vector in the zenith direction
111 * @see #getNadir()
112 */
113 public Vector3D getZenith() {
114 if (zenith == null) {
115 final double cosLat = FastMath.cos(latitude);
116 final double sinLat = FastMath.sin(latitude);
117 final double cosLon = FastMath.cos(longitude);
118 final double sinLon = FastMath.sin(longitude);
119 zenith = new Vector3D(cosLon * cosLat, sinLon * cosLat, sinLat);
120 }
121 return zenith;
122 }
123
124 /** Get the direction below the point, expressed in parent shape frame.
125 * <p>The nadir direction is the opposite of zenith direction.</p>
126 * @return unit vector in the nadir direction
127 * @see #getZenith()
128 */
129 public Vector3D getNadir() {
130 if (nadir == null) {
131 nadir = getZenith().negate();
132 }
133 return nadir;
134 }
135
136 /** Get the direction to the north of point, expressed in parent shape frame.
137 * <p>The north direction is defined in the horizontal plane
138 * (normal to zenith direction) and following the local meridian.</p>
139 * @return unit vector in the north direction
140 * @see #getSouth()
141 */
142 public Vector3D getNorth() {
143 if (north == null) {
144 final double cosLat = FastMath.cos(latitude);
145 final double sinLat = FastMath.sin(latitude);
146 final double cosLon = FastMath.cos(longitude);
147 final double sinLon = FastMath.sin(longitude);
148 north = new Vector3D(-cosLon * sinLat, -sinLon * sinLat, cosLat);
149 }
150 return north;
151 }
152
153 /** Get the direction to the south of point, expressed in parent shape frame.
154 * <p>The south direction is the opposite of north direction.</p>
155 * @return unit vector in the south direction
156 * @see #getNorth()
157 */
158 public Vector3D getSouth() {
159 if (south == null) {
160 south = getNorth().negate();
161 }
162 return south;
163 }
164
165 /** Get the direction to the east of point, expressed in parent shape frame.
166 * <p>The east direction is defined in the horizontal plane
167 * in order to complete direct triangle (east, north, zenith).</p>
168 * @return unit vector in the east direction
169 * @see #getWest()
170 */
171 public Vector3D getEast() {
172 if (east == null) {
173 east = new Vector3D(-FastMath.sin(longitude), FastMath.cos(longitude), 0);
174 }
175 return east;
176 }
177
178 /** Get the direction to the west of point, expressed in parent shape frame.
179 * <p>The west direction is the opposite of east direction.</p>
180 * @return unit vector in the west direction
181 * @see #getEast()
182 */
183 public Vector3D getWest() {
184 if (west == null) {
185 west = getEast().negate();
186 }
187 return west;
188 }
189
190 @Override
191 public boolean equals(final Object object) {
192 if (object instanceof GeodeticPoint) {
193 final GeodeticPoint../org/orekit/bodies/GeodeticPoint.html#GeodeticPoint">GeodeticPoint other = (GeodeticPoint) object;
194 return this.getLatitude() == other.getLatitude() &&
195 this.getLongitude() == other.getLongitude() &&
196 this.getAltitude() == other.getAltitude();
197 }
198 return false;
199 }
200
201 @Override
202 public int hashCode() {
203 return Double.valueOf(this.getLatitude()).hashCode() ^
204 Double.valueOf(this.getLongitude()).hashCode() ^
205 Double.valueOf(this.getAltitude()).hashCode();
206 }
207
208 @Override
209 public String toString() {
210 final NumberFormat format = CompositeFormat.getDefaultNumberFormat();
211 return "{lat: " +
212 format.format(FastMath.toDegrees(this.getLatitude())) +
213 " deg, lon: " +
214 format.format(FastMath.toDegrees(this.getLongitude())) +
215 " deg, alt: " +
216 format.format(this.getAltitude()) +
217 "}";
218 }
219 }