001 package fr.isae.orbit;
002
003 import fr.isae.geometry.Point;
004
005 /**
006 * <code>Orbite</code> represente une orbite elliptique autour de
007 * la Terre avec lancement a l'equateur (argument du perigee nul).
008 * Sur cette orbite sont positionnes trois satellites separes par
009 * 120 degres possedant chacun un instrument faisant un angle de 45
010 * degres avec le vecteur tangent a la trajectoire du satellite.
011 * L'ouverture de l'instrument est de 45 degres. On peut verifier
012 * si un satellite a une position angulaire donnee voit le satellite
013 * le precedant.
014 *
015 * @author <a href="mailto:garion@isae.fr">Christophe Garion</a>
016 * @version 1.0
017 */
018 public class Orbite {
019
020 private double e;
021 private double a;
022 private Point foyer;
023 private double b;
024
025 /**
026 * La valeur de l'ouverture de l'appareil, consideree comme constante.
027 */
028 public static final double OUVERTURE = Math.PI / 4.0;
029
030 /**
031 * L'angle de visee de l'appareil par rapport a la tangente a la trajectoire.
032 */
033 public static final double ANGLE_VISEE = Math.PI / 4.0;
034
035 /**
036 * Une constante pour comparer des valeurs reelles.
037 */
038 public static final double EPS = 1E-6;
039
040 /**
041 * Creer une nouvelle instance de <code>Orbite</code>.
042 *
043 * @param e valeur de l'excentricite de l'orbite. <b>Doit etre comprise
044 * entre 0 et 1</b>
045 * @param a valeur du demi-grand axe de l'ellipse. <b>Doit etre positive</b>
046 * @param foyer un point representant le foyer de l'ellipse sur
047 * lequel est situe la Terre. Attention, ce point n'est pas copie.
048 */
049 public Orbite(double e, double a, Point foyer) {
050 this.e = e;
051 this.a = a;
052 this.foyer = foyer.clone();
053 this.calculerB();
054 }
055
056 /**
057 * Creer une nouvelle instance de <code>Orbite</code>. On considere
058 * que la Terre a pour coordonnees <code>(0, 0)</code>.
059 *
060 * @param e valeur de l'excentricite de l'orbite. <b>Doit etre comprise
061 * entre 0 et 1</b>
062 * @param a valeur du demi-grand axe de l'ellipse. <b>Doit etre positive</b>
063 */
064 public Orbite(double e, double a) {
065 this.e = e;
066 this.a = a;
067 this.foyer = Point.ORIGINE;
068 this.calculerB();
069 }
070
071 /**
072 * La valeur de l'excentricite de l'orbite.
073 *
074 * @return la valeur de l'exentricite (comprise
075 * entre 0 et 1)
076 */
077 public double getE() {
078 return this.e;
079 }
080
081 /**
082 * Changer la valeur de l'excentricite de l'orbite.
083 *
084 * @param e la nouvelle valeur de l'excentricite. <b>Doit etre comprise
085 * entre 0 et 1</b>
086 */
087 public void setE(double e) {
088 this.e = e;
089 this.calculerB();
090 }
091
092 /**
093 * La valeur du demi-grand axe de l'orbite.
094 *
095 * @return la valeur du demi-grand axe (positive)
096 */
097 public double getA() {
098 return this.a;
099 }
100
101 /**
102 * Changer la valeur du demi-grand axe de l'orbite.
103 *
104 * @param a la nouvelle valeur du demi-grand axe.<b>Doit etre positive</b>
105 */
106 public void setA(double a) {
107 this.a = a;
108 this.calculerB();
109 }
110
111 /**
112 * La valeur du demi-petit axe de l'orbite.
113 *
114 * @return la valeur du demi-petit axe (positive)
115 */
116 public double getB() {
117 return this.b;
118 }
119
120 /**
121 * Changer la valeur du demi-petit axe de l'orbite. On considere
122 * que la valeur du demi-grand axe ne change pas et que c'est l'
123 * excentricite qui est modifiee.
124 *
125 * @param b la nouvelle valeur du demi-petit axe.<b>Doit etre positive</b>
126 */
127 public void setB(double b) {
128 this.b = b;
129 this.e = Math.sqrt(a * a - b * b) / a;
130 }
131
132 /**
133 * Le point ou est situe la Terre.
134 *
135 * @return une reference vers le point representant la Terre. Attention,
136 * le point n'est pas copie.
137 */
138 public Point getFoyer() {
139 return this.foyer.clone();
140 }
141
142 /**
143 * Changer le point representant la Terre.
144 *
145 * @param foyer le nouveau point representant la Terre
146 */
147 public void setFoyer(Point foyer) {
148 this.foyer = foyer.clone();
149 }
150
151 /**
152 * La distance entre le centre de l'ellipse et un foyer.
153 *
154 * @return la valeur de la distance entre le centre de l'ellipse et un foyer
155 */
156 public double getC() {
157 return this.a * this.e;
158 }
159
160 /**
161 * <code>equals</code> permet de verifier si deux orbites sont egales, i.e.
162 * s'ils ont les memes parametres.
163 *
164 * <p> Nous verrons plus tard que cette methode est en fait heritee de la
165 * classe <code>Object</code>
166 *
167 * @param o une <code>Orbite</code> qui est l'orbite dont on veut verifier si
168 * elle est egale a <code>this</code>
169 * @return un <code>boolean</code> qui est <code>true</code> si les deux
170 * orbites sont egales
171 */
172
173 public boolean equals(Orbite o) {
174 return ((o != null) &&
175 (this.e == o.e) &&
176 (this.a == o.a) &&
177 (this.foyer.equals(o.foyer)));
178 }
179
180 /**
181 * <code>clone</code> permet d'obtenir une copie de <code>this</code>. On obtient
182 * une nouvelle orbite avec des parametres identiques.
183 *
184 * <p> Nous verrons plus tard que cette methode est en fait heritee de la
185 * classe <code>Object</code>
186 *
187 * @return une <code>Orbite o</code> tel que <code>this != o</code> et
188 * <code>this.equals(o)</code>
189 */
190 public Orbite clone() {
191 return new Orbite(this.e, this.a, this.foyer);
192 }
193
194 /**
195 * Renvoyer une chaine de caracteres representant l'orbite sous la forme
196 * <code>[Orbite e=... a=... foyer=(...,...)]</code>
197 *
198 * @return la representation de l'orbite
199 */
200 public String toString() {
201 return "[Orbite" +
202 " e=" + this.e +
203 " a=" + this.a +
204 " foyer=" + this.foyer +
205 "]";
206 }
207
208 /**
209 * Calculer les coordonnes d'un point sur l'orbite en fonction d'un angle
210 * pris par rapport a l'origine de l'ellipse (anomalie excentrique).
211 * On suppose que si l'angle vaut 0, le point est le perigee.
212 *
213 * @param theta l'anomalie excentrique decrivant la position du point
214 * @return le point sur l'orbite correspondant a l'angle
215 */
216 public Point calculerPointSurOrbite(double theta) {
217 return new Point(this.foyer.getX() - this.getC() +
218 this.a * Math.cos(theta),
219 this.b * Math.sin(theta) + this.foyer.getY());
220 }
221
222 /**
223 * Calculer les coordonnes d'un point sur l'orbite en fonction d'un angle
224 * pris par rapport au foyer de l'ellipse.
225 * On suppose que si l'angle vaut 0, le point est le perigee.
226 *
227 * @param v l'angle decrivant la position du point
228 * @return le point sur l'orbite correspondant a l'angle
229 */
230 public Point calculerPointSurOrbiteFoyer(double v) {
231 return this.calculerPointSurOrbite(this.calculerTheta(v));
232 }
233
234 /**
235 * Renvoie un point representant un vecteur tangent a l'ellipse au point
236 * defini par <code>theta</code>. Le vecteur tangent va dans la direction
237 * de la vitesse du satellite.
238 *
239 * @param theta l'anomalie excentrique situant le point
240 * @return un vecteur tangent a l'ellipse au point defini par theta.
241 */
242 public Point calculerVecteurTangent(double theta) {
243 // on s'occupe des cas aux limites
244 if (Math.abs(theta % (2.0 * Math.PI)) < EPS) {
245 return new Point(0.0, 1.0);
246 }
247
248 if (Math.abs(theta % Math.PI) < EPS) {
249 return new Point(0.0, -1.0);
250 }
251
252 // calcul dans les autres cas
253 Point centre = new Point(this.foyer.getX() - this.getC(),
254 this.foyer.getY());
255
256 Point p = this.calculerPointSurOrbite(theta);
257
258 // on se ramene a un centre a l'origine
259 p.translater(-centre.getX(), -centre.getY());
260
261 // on choisit un vecteur avec une abscisse qui vaut celle du
262 // demi-grand axe. Comme on sait que theta via atan2 sera
263 // compris entre -PI et PI, c'est facile...
264 double x = ((theta < 0.0) ? 1.0 : -1.0) * this.a + p.getX();
265
266 double y = (1.0 - (x * p.getX()) / (this.a * this.a)) *
267 (this.b * this.b) / p.getY();
268
269 // on normalise le vecteur
270 Point vec = new Point(x - p.getX(), y - p.getY());
271
272 double lvec = vec.distance(Point.ORIGINE);
273
274 return new Point(vec.getX() / lvec, vec.getY() / lvec);
275 }
276
277 /**
278 * Permet de verifier si un satellite a une position angulaire donnee voit via
279 * son instrument de bord le satellite suivant situe a 120 degres. Les angles sont
280 * donnes par rapport au foyer.
281 *
282 * @param v l'angle definissant la position du satellite par rapport au foyer
283 * @return <code>true</code> si le satellite suivant est visible
284 */
285 public boolean voitSatelliteSuivant(double v) {
286 Point sat = this.calculerPointSurOrbiteFoyer(v);
287 Point satSuivant = this.calculerPointSurOrbiteFoyer(v + Math.PI * 2.0 / 3.0);
288
289 // calcul vecteur tangent
290 // on assimile les vecteurs a des points...
291 Point vTangent = this.calculerVecteurTangent(this.calculerTheta(v));
292 double lvTangent = vTangent.distance(Point.ORIGINE);
293
294 // vecteur vers prochain satellite (normalise)
295 Point vSat = new Point(satSuivant.getX() - sat.getX(),
296 satSuivant.getY() - sat.getY());
297 double lvSat = vSat.distance(Point.ORIGINE);
298 vSat = new Point(vSat.getX() / lvSat, vSat.getY() / lvSat);
299 lvSat = vSat.distance(Point.ORIGINE);
300
301 double cosVSatTangent = (vTangent.getX() * vSat.getX() +
302 vTangent.getY() * vSat.getY()) /
303 (lvTangent * lvSat);
304
305 return ((cosVSatTangent >= Math.cos(ANGLE_VISEE + OUVERTURE / 2.0)) &&
306 (cosVSatTangent <= Math.cos(ANGLE_VISEE - OUVERTURE / 2.0)));
307 }
308
309
310 private void calculerB() {
311 this.b = this.a * Math.sqrt(1.0 - this.e * this.e);
312 }
313
314 private double calculerTheta(double v) {
315 return Math.atan2(Math.sqrt(1.0 - Math.pow(this.e, 2)) * Math.sin(v),
316 this.e + Math.cos(v));
317 }
318 }
|