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