1 /* Copyright 2002-2024 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.frames; 18 19 import org.hipparchus.CalculusFieldElement; 20 import org.hipparchus.Field; 21 import org.hipparchus.geometry.euclidean.threed.FieldRotation; 22 import org.hipparchus.geometry.euclidean.threed.FieldVector3D; 23 import org.hipparchus.geometry.euclidean.threed.Rotation; 24 import org.hipparchus.geometry.euclidean.threed.RotationConvention; 25 import org.hipparchus.geometry.euclidean.threed.Vector3D; 26 import org.orekit.errors.OrekitException; 27 import org.orekit.errors.OrekitMessages; 28 import org.orekit.files.ccsds.definitions.OrbitRelativeFrame; 29 import org.orekit.time.AbsoluteDate; 30 import org.orekit.time.FieldAbsoluteDate; 31 import org.orekit.utils.FieldPVCoordinates; 32 import org.orekit.utils.PVCoordinates; 33 34 /** 35 * Enumerate for different types of Local Orbital Frames. 36 * 37 * @author Luc Maisonobe 38 * @author Maxime Journot 39 * @author Vincent Cucchietti 40 */ 41 public enum LOFType implements LOF { 42 43 /** Constant for TNW frame 44 * (X axis aligned with velocity, Z axis aligned with orbital momentum). 45 * <p> 46 * The axes of this frame are parallel to the axes of the {@link #VNC} 47 * and {@link #NTW} frames: 48 * <ul> 49 * <li>X<sub>TNW</sub> = X<sub>VNC</sub> = Y<sub>NTW</sub></li> 50 * <li>Y<sub>TNW</sub> = -Z<sub>VNC</sub> = -X<sub>NTW</sub></li> 51 * <li>Z<sub>TNW</sub> = Y<sub>VNC</sub> = Z<sub>NTW</sub></li> 52 * </ul> 53 * 54 * @see #VNC 55 * @see #NTW 56 */ 57 TNW { 58 /** {@inheritDoc} */ 59 @Override 60 public Rotation rotationFromInertial(final PVCoordinates pv) { 61 return new Rotation(pv.getVelocity(), pv.getMomentum(), 62 Vector3D.PLUS_I, Vector3D.PLUS_K); 63 } 64 65 /** {@inheritDoc} */ 66 @Override 67 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 68 final FieldPVCoordinates<T> pv) { 69 return new FieldRotation<>(pv.getVelocity(), pv.getMomentum(), 70 new FieldVector3D<>(field, Vector3D.PLUS_I), 71 new FieldVector3D<>(field, Vector3D.PLUS_K)); 72 } 73 74 /** {@inheritDoc} */ 75 @Override 76 public OrbitRelativeFrame toOrbitRelativeFrame() { 77 return OrbitRelativeFrame.TNW; 78 } 79 80 }, 81 82 /** 83 * Constant for TNW frame considered inertial (X axis aligned with velocity, Z axis aligned with orbital momentum). 84 * <p> 85 * The axes of this frame are parallel to the axes of the {@link #VNC} and {@link #NTW} frames: 86 * <ul> 87 * <li>X<sub>TNW</sub> = X<sub>VNC</sub> = Y<sub>NTW</sub></li> 88 * <li>Y<sub>TNW</sub> = -Z<sub>VNC</sub> = -X<sub>NTW</sub></li> 89 * <li>Z<sub>TNW</sub> = Y<sub>VNC</sub> = Z<sub>NTW</sub></li> 90 * </ul> 91 * 92 * @see #VNC 93 * @see #NTW 94 */ 95 TNW_INERTIAL { 96 /** {@inheritDoc} */ 97 @Override 98 public Rotation rotationFromInertial(final PVCoordinates pv) { 99 return TNW.rotationFromInertial(pv); 100 } 101 102 /** {@inheritDoc} */ 103 @Override 104 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 105 final FieldPVCoordinates<T> pv) { 106 return TNW.rotationFromInertial(field, pv); 107 } 108 109 /** {@inheritDoc} */ 110 @Override 111 public boolean isQuasiInertial() { 112 return true; 113 } 114 115 /** {@inheritDoc} */ 116 @Override 117 public OrbitRelativeFrame toOrbitRelativeFrame() { 118 return OrbitRelativeFrame.TNW_INERTIAL; 119 } 120 121 }, 122 123 /** Constant for QSW frame 124 * (X axis aligned with position, Z axis aligned with orbital momentum). 125 * <p> 126 * This frame is also known as the {@link #LVLH} frame, both constants are equivalent. 127 * </p> 128 * <p> 129 * The axes of these frames are parallel to the axes of the {@link #VVLH} frame: 130 * <ul> 131 * <li>X<sub>QSW/LVLH</sub> = -Z<sub>VVLH</sub></li> 132 * <li>Y<sub>QSW/LVLH</sub> = X<sub>VVLH</sub></li> 133 * <li>Z<sub>QSW/LVLH</sub> = -Y<sub>VVLH</sub></li> 134 * </ul> 135 * 136 * @see #LVLH 137 * @see #VVLH 138 */ 139 QSW { 140 /** {@inheritDoc} */ 141 @Override 142 public Rotation rotationFromInertial(final PVCoordinates pv) { 143 return new Rotation(pv.getPosition(), pv.getMomentum(), 144 Vector3D.PLUS_I, Vector3D.PLUS_K); 145 } 146 147 /** {@inheritDoc} */ 148 @Override 149 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 150 final FieldPVCoordinates<T> pv) { 151 return new FieldRotation<>(pv.getPosition(), pv.getMomentum(), 152 new FieldVector3D<>(field, Vector3D.PLUS_I), 153 new FieldVector3D<>(field, Vector3D.PLUS_K)); 154 } 155 156 /** {@inheritDoc} */ 157 @Override 158 public OrbitRelativeFrame toOrbitRelativeFrame() { 159 return OrbitRelativeFrame.QSW; 160 } 161 162 }, 163 164 /** 165 * Constant for QSW frame considered inertial (X axis aligned with position, Z axis aligned with orbital momentum). 166 * <p> 167 * This frame is also known as the {@link #LVLH} frame, both constants are equivalent. 168 * </p> 169 * <p> 170 * The axes of these frames are parallel to the axes of the {@link #VVLH} frame: 171 * <ul> 172 * <li>X<sub>QSW/LVLH</sub> = -Z<sub>VVLH</sub></li> 173 * <li>Y<sub>QSW/LVLH</sub> = X<sub>VVLH</sub></li> 174 * <li>Z<sub>QSW/LVLH</sub> = -Y<sub>VVLH</sub></li> 175 * </ul> 176 * 177 * @see #LVLH 178 * @see #VVLH 179 */ 180 QSW_INERTIAL { 181 /** {@inheritDoc} */ 182 @Override 183 public Rotation rotationFromInertial(final PVCoordinates pv) { 184 return QSW.rotationFromInertial(pv); 185 } 186 187 /** {@inheritDoc} */ 188 @Override 189 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 190 final FieldPVCoordinates<T> pv) { 191 return QSW.rotationFromInertial(field, pv); 192 } 193 194 /** {@inheritDoc} */ 195 @Override 196 public boolean isQuasiInertial() { 197 return true; 198 } 199 200 /** {@inheritDoc} */ 201 @Override 202 public OrbitRelativeFrame toOrbitRelativeFrame() { 203 return OrbitRelativeFrame.RSW_INERTIAL; 204 } 205 206 }, 207 208 /** Constant for Local Vertical, Local Horizontal frame 209 * (X axis aligned with position, Z axis aligned with orbital momentum). 210 * <p> 211 * BEWARE! Depending on the background (software used, textbook, community), 212 * different incompatible definitions for LVLH are used. This one is consistent 213 * with Vallado's book and with AGI's STK. However CCSDS standard, Wertz, and 214 * a.i. solutions' FreeFlyer use another definition (see {@link #LVLH_CCSDS}). 215 * </p> 216 * <p> 217 * This frame is also known as the {@link #QSW} frame, both constants are equivalent. 218 * </p> 219 * <p> 220 * The axes of these frames are parallel to the axes of the {@link #LVLH_CCSDS} frame: 221 * <ul> 222 * <li>X<sub>LVLH/QSW</sub> = -Z<sub>LVLH_CCSDS</sub></li> 223 * <li>Y<sub>LVLH/QSW</sub> = X<sub>LVLH_CCSDS</sub></li> 224 * <li>Z<sub>LVLH/QSW</sub> = -Y<sub>LVLH_CCSDS</sub></li> 225 * </ul> 226 * 227 * @see #QSW 228 * @see #VVLH 229 */ 230 LVLH { 231 /** {@inheritDoc} */ 232 @Override 233 public Rotation rotationFromInertial(final PVCoordinates pv) { 234 return new Rotation(pv.getPosition(), pv.getMomentum(), 235 Vector3D.PLUS_I, Vector3D.PLUS_K); 236 } 237 238 /** {@inheritDoc} */ 239 @Override 240 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 241 final FieldPVCoordinates<T> pv) { 242 return new FieldRotation<>(pv.getPosition(), pv.getMomentum(), 243 new FieldVector3D<>(field, Vector3D.PLUS_I), 244 new FieldVector3D<>(field, Vector3D.PLUS_K)); 245 } 246 247 /** {@inheritDoc} */ 248 @Override 249 public OrbitRelativeFrame toOrbitRelativeFrame() { 250 throw new OrekitException(OrekitMessages.CCSDS_DIFFERENT_LVLH_DEFINITION); 251 } 252 253 }, 254 255 /** 256 * Constant for Local Vertical, Local Horizontal frame considered inertial (X axis aligned with position, Z axis 257 * aligned with orbital momentum). 258 * <p> 259 * BEWARE! Depending on the background (software used, textbook, community), different incompatible definitions for 260 * LVLH are used. This one is consistent with Vallado's book and with AGI's STK. However CCSDS standard, Wertz, and 261 * a.i. solutions' FreeFlyer use another definition (see {@link #LVLH_CCSDS}). 262 * </p> 263 * <p> 264 * This frame is also known as the {@link #QSW} frame, both constants are equivalent. 265 * </p> 266 * <p> 267 * The axes of these frames are parallel to the axes of the {@link #LVLH_CCSDS} frame: 268 * <ul> 269 * <li>X<sub>LVLH/QSW</sub> = -Z<sub>LVLH_CCSDS</sub></li> 270 * <li>Y<sub>LVLH/QSW</sub> = X<sub>LVLH_CCSDS</sub></li> 271 * <li>Z<sub>LVLH/QSW</sub> = -Y<sub>LVLH_CCSDS</sub></li> 272 * </ul> 273 * 274 * @see #QSW 275 * @see #VVLH 276 */ 277 LVLH_INERTIAL { 278 /** {@inheritDoc} */ 279 @Override 280 public Rotation rotationFromInertial(final PVCoordinates pv) { 281 return LVLH.rotationFromInertial(pv); 282 } 283 284 /** {@inheritDoc} */ 285 @Override 286 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 287 final FieldPVCoordinates<T> pv) { 288 return LVLH.rotationFromInertial(field, pv); 289 } 290 291 /** {@inheritDoc} */ 292 @Override 293 public boolean isQuasiInertial() { 294 return true; 295 } 296 297 /** {@inheritDoc} */ 298 @Override 299 public OrbitRelativeFrame toOrbitRelativeFrame() { 300 throw new OrekitException(OrekitMessages.CCSDS_DIFFERENT_LVLH_DEFINITION); 301 } 302 303 }, 304 305 /** Constant for Local Vertical, Local Horizontal frame as defined by CCSDS 306 * (Z axis aligned with opposite of position, Y axis aligned with opposite of orbital momentum). 307 * <p> 308 * BEWARE! Depending on the background (software used, textbook, community), 309 * different incompatible definitions for LVLH are used. This one is consistent 310 * with CCSDS standard, Wertz, and a.i. solutions' FreeFlyer. However Vallado's 311 * book and with AGI's STK use another definition (see {@link #LVLH}). 312 * </p> 313 * <p> 314 * The axes of this frame are parallel to the axes of both the {@link #QSW} and {@link #LVLH} frames: 315 * <ul> 316 * <li>X<sub>LVLH_CCSDS/VVLH</sub> = Y<sub>QSW/LVLH</sub></li> 317 * <li>Y<sub>LVLH_CCSDS/VVLH</sub> = -Z<sub>QSW/LVLH</sub></li> 318 * <li>Z<sub>LVLH_CCSDS/VVLH</sub> = -X<sub>QSW/LVLH</sub></li> 319 * </ul> 320 * 321 * @see #QSW 322 * @see #LVLH 323 * @since 11.0 324 */ 325 LVLH_CCSDS { 326 /** {@inheritDoc} */ 327 @Override 328 public Rotation rotationFromInertial(final PVCoordinates pv) { 329 return new Rotation(pv.getPosition(), pv.getMomentum(), 330 Vector3D.MINUS_K, Vector3D.MINUS_J); 331 } 332 333 /** {@inheritDoc} */ 334 @Override 335 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 336 final FieldPVCoordinates<T> pv) { 337 return new FieldRotation<>(pv.getPosition(), pv.getMomentum(), 338 new FieldVector3D<>(field, Vector3D.MINUS_K), 339 new FieldVector3D<>(field, Vector3D.MINUS_J)); 340 } 341 342 /** {@inheritDoc} */ 343 @Override 344 public OrbitRelativeFrame toOrbitRelativeFrame() { 345 return OrbitRelativeFrame.LVLH; 346 } 347 348 }, 349 350 /** 351 * Constant for Local Vertical, Local Horizontal frame as defined by CCSDS considered inertial (Z axis aligned with 352 * opposite of position, Y axis aligned with opposite of orbital momentum). 353 * <p> 354 * BEWARE! Depending on the background (software used, textbook, community), different incompatible definitions for 355 * LVLH are used. This one is consistent with CCSDS standard, Wertz, and a.i. solutions' FreeFlyer. However 356 * Vallado's book and with AGI's STK use another definition (see {@link #LVLH}). 357 * </p> 358 * <p> 359 * The axes of this frame are parallel to the axes of both the {@link #QSW} and {@link #LVLH} frames: 360 * <ul> 361 * <li>X<sub>LVLH_CCSDS/VVLH</sub> = Y<sub>QSW/LVLH</sub></li> 362 * <li>Y<sub>LVLH_CCSDS/VVLH</sub> = -Z<sub>QSW/LVLH</sub></li> 363 * <li>Z<sub>LVLH_CCSDS/VVLH</sub> = -X<sub>QSW/LVLH</sub></li> 364 * </ul> 365 * 366 * @see #QSW 367 * @see #LVLH 368 * @since 11.0 369 */ 370 LVLH_CCSDS_INERTIAL { 371 /** {@inheritDoc} */ 372 @Override 373 public Rotation rotationFromInertial(final PVCoordinates pv) { 374 return LVLH_CCSDS.rotationFromInertial(pv); 375 } 376 377 /** {@inheritDoc} */ 378 @Override 379 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 380 final FieldPVCoordinates<T> pv) { 381 return LVLH_CCSDS.rotationFromInertial(field, pv); 382 } 383 384 /** {@inheritDoc} */ 385 @Override 386 public boolean isQuasiInertial() { 387 return true; 388 } 389 390 /** {@inheritDoc} */ 391 @Override 392 public OrbitRelativeFrame toOrbitRelativeFrame() { 393 return OrbitRelativeFrame.LVLH_INERTIAL; 394 } 395 396 }, 397 398 /** Constant for Vehicle Velocity, Local Horizontal frame 399 * (Z axis aligned with opposite of position, Y axis aligned with opposite of orbital momentum). 400 * <p> 401 * This is another name for {@link #LVLH_CCSDS}, kept here for compatibility with STK. 402 * </p> 403 * <p> 404 * Beware that the name is misleading: in the general case (i.e. not perfectly circular), 405 * none of the axes is perfectly aligned with velocity! The preferred name for this 406 * should be {@link #LVLH_CCSDS}. 407 * </p> 408 * <p> 409 * The axes of this frame are parallel to the axes of both the {@link #QSW} and {@link #LVLH} frames: 410 * <ul> 411 * <li>X<sub>LVLH_CCSDS/VVLH</sub> = Y<sub>QSW/LVLH</sub></li> 412 * <li>Y<sub>LVLH_CCSDS/VVLH</sub> = -Z<sub>QSW/LVLH</sub></li> 413 * <li>Z<sub>LVLH_CCSDS/VVLH</sub> = -X<sub>QSW/LVLH</sub></li> 414 * </ul> 415 * @see #LVLH_CCSDS 416 */ 417 VVLH { 418 /** {@inheritDoc} */ 419 @Override 420 public Rotation rotationFromInertial(final PVCoordinates pv) { 421 return LVLH_CCSDS.rotationFromInertial(pv); 422 } 423 424 /** {@inheritDoc} */ 425 @Override 426 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 427 final FieldPVCoordinates<T> pv) { 428 return LVLH_CCSDS.rotationFromInertial(field, pv); 429 } 430 431 /** {@inheritDoc} */ 432 @Override 433 public OrbitRelativeFrame toOrbitRelativeFrame() { 434 return OrbitRelativeFrame.LVLH; 435 } 436 437 }, 438 439 /** 440 * Constant for Vehicle Velocity, Local Horizontal frame considered inertial (Z axis aligned with opposite of 441 * position, Y axis aligned with opposite of orbital momentum). 442 * <p> 443 * This is another name for {@link #LVLH_CCSDS}, kept here for compatibility with STK. 444 * </p> 445 * <p> 446 * Beware that the name is misleading: in the general case (i.e. not perfectly circular), none of the axes is 447 * perfectly aligned with velocity! The preferred name for this should be {@link #LVLH_CCSDS}. 448 * </p> 449 * <p> 450 * The axes of this frame are parallel to the axes of both the {@link #QSW} and {@link #LVLH} frames: 451 * <ul> 452 * <li>X<sub>LVLH_CCSDS/VVLH</sub> = Y<sub>QSW/LVLH</sub></li> 453 * <li>Y<sub>LVLH_CCSDS/VVLH</sub> = -Z<sub>QSW/LVLH</sub></li> 454 * <li>Z<sub>LVLH_CCSDS/VVLH</sub> = -X<sub>QSW/LVLH</sub></li> 455 * </ul> 456 * 457 * @see #LVLH_CCSDS 458 */ 459 VVLH_INERTIAL { 460 /** {@inheritDoc} */ 461 @Override 462 public Rotation rotationFromInertial(final PVCoordinates pv) { 463 return VVLH.rotationFromInertial(pv); 464 } 465 466 /** {@inheritDoc} */ 467 @Override 468 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 469 final FieldPVCoordinates<T> pv) { 470 return VVLH.rotationFromInertial(field, pv); 471 } 472 473 /** {@inheritDoc} */ 474 @Override 475 public boolean isQuasiInertial() { 476 return true; 477 } 478 479 /** {@inheritDoc} */ 480 @Override 481 public OrbitRelativeFrame toOrbitRelativeFrame() { 482 return OrbitRelativeFrame.LVLH_INERTIAL; 483 } 484 485 }, 486 487 /** Constant for Velocity - Normal - Co-normal frame 488 * (X axis aligned with velocity, Y axis aligned with orbital momentum). 489 * <p> 490 * The axes of this frame are parallel to the axes of the {@link #TNW} 491 * and {@link #NTW} frames: 492 * <ul> 493 * <li>X<sub>VNC</sub> = X<sub>TNW</sub> = Y<sub>NTW</sub></li> 494 * <li>Y<sub>VNC</sub> = Z<sub>TNW</sub> = Z<sub>NTW</sub></li> 495 * <li>Z<sub>VNC</sub> = -Y<sub>TNW</sub> = X<sub>NTW</sub></li> 496 * </ul> 497 * 498 * @see #TNW 499 * @see #NTW 500 */ 501 VNC { 502 /** {@inheritDoc} */ 503 @Override 504 public Rotation rotationFromInertial(final PVCoordinates pv) { 505 return new Rotation(pv.getVelocity(), pv.getMomentum(), 506 Vector3D.PLUS_I, Vector3D.PLUS_J); 507 } 508 509 /** {@inheritDoc} */ 510 @Override 511 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 512 final FieldPVCoordinates<T> pv) { 513 return new FieldRotation<>(pv.getVelocity(), pv.getMomentum(), 514 new FieldVector3D<>(field, Vector3D.PLUS_I), 515 new FieldVector3D<>(field, Vector3D.PLUS_J)); 516 } 517 518 /** {@inheritDoc} */ 519 @Override 520 public OrbitRelativeFrame toOrbitRelativeFrame() { 521 return OrbitRelativeFrame.VNC_ROTATING; 522 } 523 524 }, 525 526 /** 527 * Constant for Velocity - Normal - Co-normal frame considered inertial (X axis aligned with velocity, Y axis 528 * aligned with orbital momentum). 529 * <p> 530 * The axes of this frame are parallel to the axes of the {@link #TNW} and {@link #NTW} frames: 531 * <ul> 532 * <li>X<sub>VNC</sub> = X<sub>TNW</sub> = Y<sub>NTW</sub></li> 533 * <li>Y<sub>VNC</sub> = Z<sub>TNW</sub> = Z<sub>NTW</sub></li> 534 * <li>Z<sub>VNC</sub> = -Y<sub>TNW</sub> = X<sub>NTW</sub></li> 535 * </ul> 536 * 537 * @see #TNW 538 * @see #NTW 539 */ 540 VNC_INERTIAL { 541 /** {@inheritDoc} */ 542 @Override 543 public Rotation rotationFromInertial(final PVCoordinates pv) { 544 return VNC.rotationFromInertial(pv); 545 } 546 547 /** {@inheritDoc} */ 548 @Override 549 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 550 final FieldPVCoordinates<T> pv) { 551 return VNC.rotationFromInertial(field, pv); 552 } 553 554 /** {@inheritDoc} */ 555 @Override 556 public boolean isQuasiInertial() { 557 return true; 558 } 559 560 /** {@inheritDoc} */ 561 @Override 562 public OrbitRelativeFrame toOrbitRelativeFrame() { 563 return OrbitRelativeFrame.VNC_INERTIAL; 564 } 565 566 }, 567 568 /** 569 * Constant for Equinoctial Coordinate System (X axis aligned with ascending node, Z axis aligned with orbital 570 * momentum). 571 * 572 * @since 11.0 573 */ 574 EQW { 575 /** {@inheritDoc} */ 576 @Override 577 public Rotation rotationFromInertial(final PVCoordinates pv) { 578 final Vector3D m = pv.getMomentum(); 579 return new Rotation(new Vector3D(-m.getY(), m.getX(), 0), m, 580 Vector3D.PLUS_I, Vector3D.PLUS_J); 581 } 582 583 /** {@inheritDoc} */ 584 @Override 585 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 586 final FieldPVCoordinates<T> pv) { 587 final FieldVector3D<T> m = pv.getMomentum(); 588 return new FieldRotation<>(new FieldVector3D<>(m.getY().negate(), m.getX(), field.getZero()), 589 m, 590 new FieldVector3D<>(field, Vector3D.PLUS_I), 591 new FieldVector3D<>(field, Vector3D.PLUS_J)); 592 } 593 594 /** {@inheritDoc} */ 595 @Override 596 public boolean isQuasiInertial() { 597 return true; 598 } 599 600 /** {@inheritDoc} */ 601 @Override 602 public OrbitRelativeFrame toOrbitRelativeFrame() { 603 return OrbitRelativeFrame.EQW_INERTIAL; 604 } 605 606 }, 607 608 /** Constant for Transverse Velocity Normal coordinate system 609 * (Y axis aligned with velocity, Z axis aligned with orbital momentum). 610 * <p> 611 * The axes of this frame are parallel to the axes of the {@link #TNW} 612 * and {@link #VNC} frames: 613 * <ul> 614 * <li>X<sub>NTW</sub> = -Y<sub>TNW</sub> = Z<sub>VNC</sub></li> 615 * <li>Y<sub>NTW</sub> = X<sub>TNW</sub> = X<sub>VNC</sub></li> 616 * <li>Z<sub>NTW</sub> = Z<sub>TNW</sub> = Y<sub>VNC</sub></li> 617 * </ul> 618 * @see #TNW 619 * @see #VNC 620 * @since 11.0 621 */ 622 NTW { 623 /** {@inheritDoc} */ 624 @Override 625 public Rotation rotationFromInertial(final PVCoordinates pv) { 626 return new Rotation(pv.getVelocity(), pv.getMomentum(), 627 Vector3D.PLUS_J, Vector3D.PLUS_K); 628 } 629 630 /** {@inheritDoc} */ 631 @Override 632 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 633 final FieldPVCoordinates<T> pv) { 634 return new FieldRotation<>(pv.getVelocity(), pv.getMomentum(), 635 new FieldVector3D<>(field, Vector3D.PLUS_J), 636 new FieldVector3D<>(field, Vector3D.PLUS_K)); 637 } 638 639 /** {@inheritDoc} */ 640 @Override 641 public OrbitRelativeFrame toOrbitRelativeFrame() { 642 return OrbitRelativeFrame.NTW_ROTATING; 643 } 644 645 }, 646 647 /** 648 * Constant for Transverse Velocity Normal coordinate system considered inertial (Y axis aligned with velocity, Z 649 * axis aligned with orbital momentum). 650 * <p> 651 * The axes of this frame are parallel to the axes of the {@link #TNW} and {@link #VNC} frames: 652 * <ul> 653 * <li>X<sub>NTW</sub> = -Y<sub>TNW</sub> = Z<sub>VNC</sub></li> 654 * <li>Y<sub>NTW</sub> = X<sub>TNW</sub> = X<sub>VNC</sub></li> 655 * <li>Z<sub>NTW</sub> = Z<sub>TNW</sub> = Y<sub>VNC</sub></li> 656 * </ul> 657 * 658 * @see #TNW 659 * @see #VNC 660 * @since 11.0 661 */ 662 NTW_INERTIAL { 663 /** {@inheritDoc} */ 664 @Override 665 public Rotation rotationFromInertial(final PVCoordinates pv) { 666 return NTW.rotationFromInertial(pv); 667 } 668 669 /** {@inheritDoc} */ 670 @Override 671 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 672 final FieldPVCoordinates<T> pv) { 673 return NTW.rotationFromInertial(field, pv); 674 } 675 676 /** {@inheritDoc} */ 677 @Override 678 public boolean isQuasiInertial() { 679 return true; 680 } 681 682 /** {@inheritDoc} */ 683 @Override 684 public OrbitRelativeFrame toOrbitRelativeFrame() { 685 return OrbitRelativeFrame.NTW_INERTIAL; 686 } 687 688 }; 689 690 /** {@inheritDoc} */ 691 public String getName() { 692 return this.name(); 693 }; 694 695 /** 696 * Get the rotation from input to output {@link LOFType local orbital frame}. 697 * <p> 698 * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well, 699 * the full {@link #transformFromLOFInToLOFOut(LOF, LOF, AbsoluteDate, PVCoordinates)} method must be called and 700 * the complete rotation transform must be extracted from it. 701 * 702 * @param in input commonly used local orbital frame 703 * @param out output commonly used local orbital frame 704 * @param pv position-velocity of the spacecraft in some inertial frame 705 * 706 * @return rotation from input to output local orbital frame 707 */ 708 static Rotation rotationFromLOFInToLOFOut(final LOFType in, final LOFType out, final PVCoordinates pv) { 709 return out.rotationFromLOF(in, pv); 710 } 711 712 /** 713 * Get the rotation from input to output {@link LOFType local orbital frame}. 714 * <p> 715 * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well, 716 * the full {@link #transformFromLOFInToLOFOut(LOF, LOF, FieldAbsoluteDate, FieldPVCoordinates)} method must be called and 717 * the complete rotation transform must be extracted from it. 718 * 719 * @param field field to which the elements belong 720 * @param in input commonly used local orbital frame 721 * @param out output commonly used local orbital frame 722 * @param pv position-velocity of the spacecraft in some inertial frame 723 * @param <T> type of the field elements 724 * 725 * @return rotation from input to output local orbital frame 726 */ 727 static <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromLOFInToLOFOut(final Field<T> field, 728 final LOFType in, 729 final LOFType out, 730 final FieldPVCoordinates<T> pv) { 731 return out.rotationFromLOF(field, in, pv); 732 } 733 734 /** 735 * Get the rotation from input {@link LOF local orbital frame} to the instance. 736 * <p> 737 * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well, 738 * the full {@link #transformFromLOF(LOF, AbsoluteDate, PVCoordinates)} method must be called and the complete rotation 739 * transform must be extracted from it. 740 * 741 * @param fromLOF input local orbital frame 742 * @param pv position-velocity of the spacecraft in some inertial frame 743 * 744 * @return rotation from input local orbital frame to the instance 745 */ 746 public Rotation rotationFromLOF(final LOFType fromLOF, final PVCoordinates pv) { 747 748 // First compute the rotation from the input LOF to the pivot inertial 749 final Rotation fromLOFToInertial = fromLOF.rotationFromInertial(pv).revert(); 750 751 // Then compute the rotation from the pivot inertial to the output LOF 752 final Rotation inertialToThis = this.rotationFromInertial(pv); 753 754 // Output composed rotation 755 return fromLOFToInertial.compose(inertialToThis, RotationConvention.FRAME_TRANSFORM); 756 } 757 758 /** 759 * Get the rotation from input {@link LOFType local orbital frame} to the instance. 760 * <p> 761 * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well, 762 * the full {@link #transformFromLOF(LOF, FieldAbsoluteDate, FieldPVCoordinates)} method must be called and the complete 763 * rotation transform must be extracted from it. 764 * 765 * @param field field to which the elements belong 766 * @param fromLOF input local orbital frame 767 * @param pv position-velocity of the spacecraft in some inertial frame 768 * @param <T> type of the field elements 769 * 770 * @return rotation from input local orbital frame to the instance 771 */ 772 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromLOF(final Field<T> field, 773 final LOFType fromLOF, 774 final FieldPVCoordinates<T> pv) { 775 776 // First compute the rotation from the input LOF to the pivot inertial 777 final FieldRotation<T> fromLOFToInertial = fromLOF.rotationFromInertial(field, pv).revert(); 778 779 // Then compute the rotation from the pivot inertial to the output LOF 780 final FieldRotation<T> inertialToThis = this.rotationFromInertial(field, pv); 781 782 // Output composed rotation 783 return fromLOFToInertial.compose(inertialToThis, RotationConvention.FRAME_TRANSFORM); 784 } 785 786 /** 787 * {@inheritDoc} It is unnecessary to use this method when dealing with {@link LOFType}, use 788 * {@link #rotationFromInertial(PVCoordinates)} instead. 789 */ 790 @Override 791 public Rotation rotationFromInertial(final AbsoluteDate date, final PVCoordinates pv) { 792 return rotationFromInertial(pv); 793 } 794 795 /** 796 * Get the rotation from inertial frame to local orbital frame. 797 * <p> 798 * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well, 799 * the full {@link #transformFromInertial(AbsoluteDate, PVCoordinates)} method must be called and 800 * the complete rotation transform must be extracted from it. 801 * </p> 802 * 803 * @param pv position-velocity of the spacecraft in some inertial frame 804 * 805 * @return rotation from inertial frame to local orbital frame 806 */ 807 public abstract Rotation rotationFromInertial(PVCoordinates pv); 808 809 /** 810 * {@inheritDoc} It is unnecessary to use this method when dealing with {@link LOFType}, use 811 * {@link #rotationFromInertial(Field, FieldPVCoordinates)} instead. 812 */ 813 @Override 814 public <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field, 815 final FieldAbsoluteDate<T> date, 816 final FieldPVCoordinates<T> pv) { 817 return rotationFromInertial(field, pv); 818 } 819 820 /** 821 * Get the rotation from inertial frame to local orbital frame. 822 * <p> 823 * This rotation does not include any time derivatives. If first time derivatives (i.e. rotation rate) is needed as well, 824 * the full {@link #transformFromInertial(FieldAbsoluteDate, FieldPVCoordinates)} method must be 825 * called and the complete rotation transform must be extracted from it. 826 * </p> 827 * 828 * @param field field to which the elements belong 829 * @param pv position-velocity of the spacecraft in some inertial frame 830 * @param <T> type of the field elements 831 * 832 * @return rotation from inertial frame to local orbital frame 833 */ 834 public abstract <T extends CalculusFieldElement<T>> FieldRotation<T> rotationFromInertial(Field<T> field, 835 FieldPVCoordinates<T> pv); 836 837 /** 838 * Convert current local orbital frame to CCSDS equivalent orbit relative frame when possible, null otherwise. 839 * 840 * @return CCSDS equivalent orbit relative frame when possible, null otherwise 841 * 842 * @see OrbitRelativeFrame 843 */ 844 public abstract OrbitRelativeFrame toOrbitRelativeFrame(); 845 846 }