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