1 /* 2 * Copyright (C) 2019 Alberto Irurueta Carro (alberto@irurueta.com) 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.irurueta.navigation.frames; 17 18 import com.irurueta.algebra.Matrix; 19 import com.irurueta.algebra.WrongSizeException; 20 import com.irurueta.geometry.InhomogeneousPoint3D; 21 import com.irurueta.geometry.InvalidRotationMatrixException; 22 import com.irurueta.geometry.Point3D; 23 import com.irurueta.geometry.Rotation3D; 24 import com.irurueta.units.Distance; 25 import com.irurueta.units.DistanceConverter; 26 import com.irurueta.units.DistanceUnit; 27 import com.irurueta.units.Speed; 28 import com.irurueta.units.SpeedConverter; 29 import com.irurueta.units.SpeedUnit; 30 31 import java.io.Serializable; 32 import java.util.Objects; 33 34 /** 35 * Base class for ECI or ECEF frames containing common logic and data for such frames. 36 */ 37 public abstract class ECIorECEFFrame<T extends ECIorECEFFrame<?>> implements Frame, Serializable { 38 39 /** 40 * Number of coordinates representing position. 41 */ 42 public static final int NUM_POSITION_COORDINATES = 3; 43 44 /** 45 * Number of coordinates representing velocity. 46 */ 47 public static final int NUM_VELOCITY_COORDINATES = 3; 48 49 /** 50 * Cartesian x coordinate of body position expressed in meters (m) with respect ECI or ECEF frame, resolved along 51 * the corresponding frame axes. 52 */ 53 double x; 54 55 /** 56 * Cartesian y coordinate of body position expressed in meters (m) with respect ECI or ECEF frame, resolved along 57 * the corresponding frame axes. 58 */ 59 double y; 60 61 /** 62 * Cartesian z coordinate of body position expressed in meters (m) with respect ECI or ECEF frame, resolved along 63 * the corresponding frame axes. 64 */ 65 double z; 66 67 /** 68 * X coordinate of velocity of body frame expressed in meters per second (m/s) with respect ECI or ECEF frame, 69 * resolved along the corresponding frame axes. 70 */ 71 double vx; 72 73 /** 74 * Y coordinate of velocity of body frame expressed in meters per second (m/s) with respect ECI or ECEF frame, 75 * resolved along the corresponding frame axes. 76 */ 77 double vy; 78 79 /** 80 * Z coordinate of velocity of body frame expressed in meters per second (m/s) with respect ECI or ECEF frame, 81 * resolved along the corresponding frame axes. 82 */ 83 double vz; 84 85 /** 86 * Body to ECI frame coordinate transformation matrix. 87 */ 88 CoordinateTransformation c; 89 90 /** 91 * Actual type class 92 */ 93 transient Class<T> clazz; 94 95 /** 96 * Constructor. 97 */ 98 ECIorECEFFrame(final Class<T> c) { 99 clazz = c; 100 } 101 102 /** 103 * Constructor. 104 * 105 * @param c Body to ECI or ECEF coordinate transformation. 106 * @throws InvalidSourceAndDestinationFrameTypeException if source or destination frame types are invalid. 107 */ 108 ECIorECEFFrame(final CoordinateTransformation c) throws InvalidSourceAndDestinationFrameTypeException { 109 setCoordinateTransformation(c); 110 } 111 112 /** 113 * Gets cartesian x coordinate of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes. 114 * 115 * @return cartesian x coordinate of body position. 116 */ 117 public double getX() { 118 return x; 119 } 120 121 /** 122 * Sets cartesian x coordinate of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes. 123 * 124 * @param x cartesian x coordinate of body position. 125 */ 126 public void setX(final double x) { 127 this.x = x; 128 } 129 130 /** 131 * Gets cartesian y coordinate of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes. 132 * 133 * @return cartesian y coordinate of body position. 134 */ 135 public double getY() { 136 return y; 137 } 138 139 /** 140 * Sets cartesian y coordinate of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes. 141 * 142 * @param y cartesian y coordinate of body position. 143 */ 144 public void setY(final double y) { 145 this.y = y; 146 } 147 148 /** 149 * Gets cartesian z coordinate of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes. 150 * 151 * @return cartesian z coordinate of body position. 152 */ 153 public double getZ() { 154 return z; 155 } 156 157 /** 158 * Sets cartesian z coordinate of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes. 159 * 160 * @param z cartesian z coordinate of body position. 161 */ 162 public void setZ(final double z) { 163 this.z = z; 164 } 165 166 /** 167 * Sets cartesian coordinates of body position expressed in meters (m) and resolved along ECI or ECEF-frame axes. 168 * 169 * @param x cartesian x coordinate of body position, resolved along ECI or ECEF-frame axes. 170 * @param y cartesian y coordinate of body position, resolved along ECI or ECEF-frame axes. 171 * @param z cartesian z coordinate of body position, resolved along ECI or ECEF-frame axes. 172 */ 173 public void setCoordinates(final double x, final double y, final double z) { 174 this.x = x; 175 this.y = y; 176 this.z = z; 177 } 178 179 /** 180 * Gets body position expressed in meters (m) and resolved along ECI or ECEF-frame axes. 181 * 182 * @return body position. 183 */ 184 public Point3D getPosition() { 185 return new InhomogeneousPoint3D(x, y, z); 186 } 187 188 /** 189 * Gets body position expressed in meters (m) and resolved along ECI or ECEF-frame axes. 190 * 191 * @param result instance where position data is copied to. 192 */ 193 public void getPosition(final Point3D result) { 194 result.setInhomogeneousCoordinates(x, y, z); 195 } 196 197 /** 198 * Sets body position expressed in meters (m) and resolved along ECI or ECEF-frame axes. 199 * 200 * @param point body position to be set. 201 */ 202 public void setPosition(final Point3D point) { 203 x = point.getInhomX(); 204 y = point.getInhomY(); 205 z = point.getInhomZ(); 206 } 207 208 /** 209 * Gets cartesian x coordinate of body position resolved along ECI or ECEF-frame axes. 210 * 211 * @param result instance where cartesian x coordinate of body position will be stored. 212 */ 213 public void getPositionX(final Distance result) { 214 result.setValue(x); 215 result.setUnit(DistanceUnit.METER); 216 } 217 218 /** 219 * Gets cartesian x coordinate of body position resolved along ECI or ECEF-frame axes. 220 * 221 * @return x coordinate of body position resolved along ECI or ECEF-frame axes. 222 */ 223 public Distance getPositionX() { 224 return new Distance(x, DistanceUnit.METER); 225 } 226 227 /** 228 * Sets cartesian x coordinate of body position resolved along ECI or ECEF-frame axes. 229 * 230 * @param positionX cartesian x coordinate of body position to be set. 231 */ 232 public void setPositionX(final Distance positionX) { 233 x = DistanceConverter.convert(positionX.getValue().doubleValue(), positionX.getUnit(), DistanceUnit.METER); 234 } 235 236 /** 237 * Gets cartesian y coordinate of body position resolved along ECI or ECEF-frame axes. 238 * 239 * @param result instance where cartesian y coordinate of body position will be stored. 240 */ 241 public void getPositionY(final Distance result) { 242 result.setValue(y); 243 result.setUnit(DistanceUnit.METER); 244 } 245 246 /** 247 * Gets cartesian y coordinate of body position resolved along ECI or ECEF-frame axes. 248 * 249 * @return y coordinate of body position resolved along ECI or ECEF-frame axes. 250 */ 251 public Distance getPositionY() { 252 return new Distance(y, DistanceUnit.METER); 253 } 254 255 /** 256 * Sets cartesian y coordinate of body position resolved along ECI or ECEF-frame axes. 257 * 258 * @param positionY cartesian y coordinate of body position to be set. 259 */ 260 public void setPositionY(final Distance positionY) { 261 y = DistanceConverter.convert(positionY.getValue().doubleValue(), positionY.getUnit(), DistanceUnit.METER); 262 } 263 264 /** 265 * Gets cartesian z coordinate of body position resolved along ECI or ECEF-frame axes. 266 * 267 * @param result instance where cartesian z coordinate of body position will be stored. 268 */ 269 public void getPositionZ(final Distance result) { 270 result.setValue(z); 271 result.setUnit(DistanceUnit.METER); 272 } 273 274 /** 275 * Gets cartesian z coordinate of body position resolved along ECI or ECEF-frame axes. 276 * 277 * @return z coordinate of body position resolved along ECI or ECEF-frame axes. 278 */ 279 public Distance getPositionZ() { 280 return new Distance(z, DistanceUnit.METER); 281 } 282 283 /** 284 * Sets cartesian z coordinate of body position resolved along ECI or ECEF-frame axes. 285 * 286 * @param positionZ cartesian z coordinate of body position to be set. 287 */ 288 public void setPositionZ(final Distance positionZ) { 289 z = DistanceConverter.convert(positionZ.getValue().doubleValue(), positionZ.getUnit(), DistanceUnit.METER); 290 } 291 292 /** 293 * Sets cartesian coordinates of body position resolved along ECI or ECEF-frame axes. 294 * 295 * @param positionX cartesian x coordinate of body position to be set, resolved along ECI or ECEF-frame axes. 296 * @param positionY cartesian y coordinate of body position to be set, resolved along ECI or ECEF-frame axes. 297 * @param positionZ cartesian z coordinate of body position to be set, resolved along ECI or ECEF-frame axes. 298 */ 299 public void setPositionCoordinates(final Distance positionX, final Distance positionY, final Distance positionZ) { 300 setPositionX(positionX); 301 setPositionY(positionY); 302 setPositionZ(positionZ); 303 } 304 305 /** 306 * Gets norm of position expressed in meters (m), which represents the distance to 307 * Earth's center of mass. 308 * 309 * @return position norm expressed in meters (m). 310 */ 311 public double getPositionNorm() { 312 return Math.sqrt(x * x + y * y + z * z); 313 } 314 315 /** 316 * Gets norm of position, which represents the distance to Earth's center of mass. 317 * 318 * @param result instance where result will be stored. 319 */ 320 public void getPositionNormAsDistance(final Distance result) { 321 result.setValue(getPositionNorm()); 322 result.setUnit(DistanceUnit.METER); 323 } 324 325 /** 326 * Gets norm of position, which represents the distance to Earth's center of mass. 327 * 328 * @return position norm. 329 */ 330 public Distance getPositionNormAsDistance() { 331 return new Distance(getPositionNorm(), DistanceUnit.METER); 332 } 333 334 /** 335 * Gets x coordinate of velocity of body frame expressed in meters per second (m/s) resolved along ECI or 336 * ECEF-frame axes. 337 * 338 * @return x coordinate of velocity. 339 */ 340 public double getVx() { 341 return vx; 342 } 343 344 /** 345 * Sets x coordinate of velocity of body frame expressed in meters per second (m/s) resolved along ECI or 346 * ECEF-frame axes. 347 * 348 * @param vx x coordinate of velocity. 349 */ 350 public void setVx(final double vx) { 351 this.vx = vx; 352 } 353 354 /** 355 * Gets y coordinate of velocity of body frame expressed in meters per second (m/s) resolved along ECI or 356 * ECEF-frame axes. 357 * 358 * @return y coordinate of velocity. 359 */ 360 public double getVy() { 361 return vy; 362 } 363 364 /** 365 * Sets y coordinate of velocity of body frame expressed in meters per second (m/s) resolved along ECI or 366 * ECEF-frame axes. 367 * 368 * @param vy y coordinate of velocity. 369 */ 370 public void setVy(final double vy) { 371 this.vy = vy; 372 } 373 374 /** 375 * Gets z coordinate of velocity of body frame expressed in meters per second (m/s) resolved along ECI or 376 * ECEF-frame axes. 377 * 378 * @return z coordinate of velocity. 379 */ 380 public double getVz() { 381 return vz; 382 } 383 384 /** 385 * Sets z coordinate of velocity of body frame expressed in meters per second (m/s) resolved along ECI or 386 * ECEF-frame axes. 387 * 388 * @param vz z coordinate of velocity. 389 */ 390 public void setVz(final double vz) { 391 this.vz = vz; 392 } 393 394 /** 395 * Sets velocity coordinates of body frame expressed in meters per second (m/s) resolved along ECI or 396 * ECEF-frame axes. 397 * 398 * @param vx x coordinate of velocity. 399 * @param vy y coordinate of velocity. 400 * @param vz z coordinate of velocity. 401 */ 402 public void setVelocityCoordinates(final double vx, final double vy, final double vz) { 403 this.vx = vx; 404 this.vy = vy; 405 this.vz = vz; 406 } 407 408 /** 409 * Gets norm of velocity expressed in meters per second (m/s), which represents 410 * the speed of the body. 411 * 412 * @return norm of velocity expressed in meters per second (m/s). 413 */ 414 public double getVelocityNorm() { 415 return Math.sqrt(vx * vx + vy * vy + vz * vz); 416 } 417 418 /** 419 * Gets norm of velocity, which represents the speed of the body. 420 * 421 * @param result velocity norm. 422 */ 423 public void getVelocityNormAsSpeed(final Speed result) { 424 result.setValue(getVelocityNorm()); 425 result.setUnit(SpeedUnit.METERS_PER_SECOND); 426 } 427 428 /** 429 * Gets norm of velocity, which represents the speed of the body. 430 * 431 * @return velocity norm. 432 */ 433 public Speed getVelocityNormAsSpeed() { 434 return new Speed(getVelocityNorm(), SpeedUnit.METERS_PER_SECOND); 435 } 436 437 /** 438 * Gets x coordinate of velocity of body frame resolved along ECEF-frame axes. 439 * 440 * @param result instance where x coordinate of velocity will be stored. 441 */ 442 public void getSpeedX(final Speed result) { 443 result.setValue(vx); 444 result.setUnit(SpeedUnit.METERS_PER_SECOND); 445 } 446 447 /** 448 * Gets x coordinate of velocity of body frame resolved along ECI or ECEF-frame axes. 449 * 450 * @return x coordinate of velocity of body frame resolved along ECI or ECEF-frame axes. 451 */ 452 public Speed getSpeedX() { 453 return new Speed(vx, SpeedUnit.METERS_PER_SECOND); 454 } 455 456 /** 457 * Sets x coordinate of velocity of body frame resolved along ECI or ECEF-frame axes. 458 * 459 * @param speedX x coordinate of velocity of body frame resolved along ECI or ECEF-frame 460 * axes to be set. 461 */ 462 public void setSpeedX(final Speed speedX) { 463 vx = SpeedConverter.convert(speedX.getValue().doubleValue(), speedX.getUnit(), SpeedUnit.METERS_PER_SECOND); 464 } 465 466 /** 467 * Gets y coordinate of velocity of body frame resolved along ECI or ECEF-frame axes. 468 * 469 * @param result instance where y coordinate of velocity will be stored. 470 */ 471 public void getSpeedY(final Speed result) { 472 result.setValue(vy); 473 result.setUnit(SpeedUnit.METERS_PER_SECOND); 474 } 475 476 /** 477 * Gets y coordinate of velocity of body frame resolved along ECI or ECEF-frame axes. 478 * 479 * @return y coordinate of velocity of body frame resolved along ECI or ECEF-frame axes. 480 */ 481 public Speed getSpeedY() { 482 return new Speed(vy, SpeedUnit.METERS_PER_SECOND); 483 } 484 485 /** 486 * Sets y coordinate of velocity of body frame resolved along ECI or ECEF-frame axes. 487 * 488 * @param speedY y coordinate of velocity of body frame resolved along ECI or ECEF-frame 489 * axes to be set. 490 */ 491 public void setSpeedY(final Speed speedY) { 492 vy = SpeedConverter.convert(speedY.getValue().doubleValue(), speedY.getUnit(), SpeedUnit.METERS_PER_SECOND); 493 } 494 495 /** 496 * Gets z coordinate of velocity of body frame resolved along ECI or ECEF-frame axes. 497 * 498 * @param result instance where z coordinate of velocity will be stored. 499 */ 500 public void getSpeedZ(final Speed result) { 501 result.setValue(vz); 502 result.setUnit(SpeedUnit.METERS_PER_SECOND); 503 } 504 505 /** 506 * Gets z coordinate of velocity of body frame resolved along ECI or ECEF-frame axes. 507 * 508 * @return z coordinate of velocity of body frame resolved along ECI or ECEF-frame axes. 509 */ 510 public Speed getSpeedZ() { 511 return new Speed(vz, SpeedUnit.METERS_PER_SECOND); 512 } 513 514 /** 515 * Sets z coordinate of velocity of body frame resolved along ECI or ECEF-frame axes. 516 * 517 * @param speedZ z coordinate of velocity of body frame resolved along ECI or ECEF-frame 518 * axes to be set. 519 */ 520 public void setSpeedZ(final Speed speedZ) { 521 vz = SpeedConverter.convert(speedZ.getValue().doubleValue(), speedZ.getUnit(), SpeedUnit.METERS_PER_SECOND); 522 } 523 524 /** 525 * Sets velocity coordinates of body frame resolved along ECI or ECEF-frame axes. 526 * 527 * @param speedX x coordinate of velocity to be set. 528 * @param speedY y coordinate of velocity to be set. 529 * @param speedZ z coordinate of velocity to be set. 530 */ 531 public void setSpeedCoordinates(final Speed speedX, final Speed speedY, final Speed speedZ) { 532 setSpeedX(speedX); 533 setSpeedY(speedY); 534 setSpeedZ(speedZ); 535 } 536 537 /** 538 * Gets coordinate transformation matrix. 539 * This is equivalent to calling getCoordinateTransformation(), but more efficient 540 * 541 * @return coordinate transformation matrix. 542 */ 543 @Override 544 public Matrix getCoordinateTransformationMatrix() { 545 Matrix result; 546 try { 547 result = new Matrix(CoordinateTransformation.ROWS, CoordinateTransformation.COLS); 548 getCoordinateTransformationMatrix(result); 549 } catch (final WrongSizeException ignore) { 550 // never happens 551 result = null; 552 } 553 return result; 554 } 555 556 /** 557 * Gets coordinate transformation matrix. 558 * This is equivalent to calling getCoordinateTransformation().getMatrix(), but more efficient 559 * 560 * @param result instance where coordinate transformation matrix will be copied to. 561 */ 562 @Override 563 public void getCoordinateTransformationMatrix(final Matrix result) { 564 c.matrix.copyTo(result); 565 } 566 567 /** 568 * Sets coordinate transformation matrix keeping current source and destination {@link FrameType}. 569 * This is more efficient than getting a copy of coordinate transformation calling to 570 * {@link #getCoordinateTransformation()}, setting coordinate matrix into copied coordinate transformation and 571 * then setting the coordinate transformation calling {@link #setCoordinateTransformation(CoordinateTransformation)}. 572 * 573 * @param matrix a 3x3 coordinate transformation matrix to be set. 574 * @param threshold threshold to validate rotation matrix. 575 * @throws InvalidRotationMatrixException if provided matrix is not a valid rotation matrix (3x3 and orthonormal). 576 * @throws IllegalArgumentException if provided threshold is negative. 577 */ 578 @Override 579 public void setCoordinateTransformationMatrix(final Matrix matrix, final double threshold) 580 throws InvalidRotationMatrixException { 581 c.setMatrix(matrix,threshold); 582 } 583 584 /** 585 * Sts coordinate transformation matrix keeping current source and destination {@link FrameType}. 586 * This is more efficient than getting a copy of coordinate transformation calling to 587 * {@link #getCoordinateTransformation()}, setting coordinate matrix into copied coordinate transformation and 588 * then setting the coordinate transformation calling {@link #setCoordinateTransformation(CoordinateTransformation)}. 589 * 590 * @param matrix a 3x3 coordinate transformation matrix to be set. 591 * @throws InvalidRotationMatrixException if provided matrix is not a valid rotation matrix (3x3 and orthonormal). 592 */ 593 @Override 594 public void setCoordinateTransformationMatrix(final Matrix matrix) throws InvalidRotationMatrixException { 595 c.setMatrix(matrix); 596 } 597 598 /** 599 * Gets coordinate transformation as a new 3D rotation instance. 600 * This is equivalent to calling getCoordinateTransformation().asRotation(), but more efficient. 601 * 602 * @return new coordinate transformation as a 3D rotation. 603 * @throws InvalidRotationMatrixException if internal matrix cannot be converted to a 3D rotation. 604 */ 605 @Override 606 public Rotation3D getCoordinateTransformationRotation() throws InvalidRotationMatrixException { 607 return c.asRotation(); 608 } 609 610 /** 611 * Gets coordinate transformation as a 3D rotation. 612 * This is equivalent to calling getCoordinateTransformation().asRotation(), but more efficient. 613 * 614 * @param result instance where coordinate transformation 3D rotation will be copied to. 615 * @throws InvalidRotationMatrixException if internal matrix cannot be converted to a 3D rotation. 616 */ 617 @Override 618 public void getCoordinateTransformationRotation(final Rotation3D result) throws InvalidRotationMatrixException { 619 c.asRotation(result); 620 } 621 622 /** 623 * Sets coordinate transformation from 3D rotation and keeping current source and destination {@link FrameType}. 624 * This is more efficient than getting a copy of coordinate transformation calling to 625 * {@link #getCoordinateTransformation()}, setting rotation into copied coordinate transformation and 626 * then setting the coordinate transformation calling {@link #setCoordinateTransformation(CoordinateTransformation)}. 627 * 628 * @param rotation set rotation into current coordinate rotation. 629 */ 630 @Override 631 public void setCoordinateTransformationRotation(final Rotation3D rotation) { 632 c.fromRotation(rotation); 633 } 634 635 /** 636 * Copies this instance data into provided instance. 637 * 638 * @param output destination instance where data will be copied to. 639 */ 640 public void copyTo(final T output) { 641 output.x = x; 642 output.y = y; 643 output.z = z; 644 645 output.vx = vx; 646 output.vy = vy; 647 output.vz = vz; 648 649 c.copyTo(output.c); 650 } 651 652 /** 653 * Copies data of provided instance into this instance. 654 * 655 * @param input instance to copy data from. 656 */ 657 public void copyFrom(final T input) { 658 x = input.x; 659 y = input.y; 660 z = input.z; 661 662 vx = input.vx; 663 vy = input.vy; 664 vz = input.vz; 665 666 c.copyFrom(input.c); 667 } 668 669 /** 670 * Computes and returns hash code for this instance. Hash codes are almost unique 671 * values that are useful for fast classification and storage of objects in collections. 672 * 673 * @return Hash code. 674 */ 675 @Override 676 public int hashCode() { 677 return Objects.hash(x, y, z, vx, vy, vz, c); 678 } 679 680 /** 681 * Checks if provided instance has exactly the same contents as this instance. 682 * 683 * @param obj instance to be compared. 684 * @return true if both instances are considered to be equal, false otherwise. 685 */ 686 @Override 687 public boolean equals(final Object obj) { 688 if (obj == null) { 689 return false; 690 } 691 if (obj == this) { 692 return true; 693 } 694 if (!clazz.isInstance(obj)) { 695 return false; 696 } 697 698 //noinspection unchecked 699 final T other = (T) obj; 700 return equals(other, 0.0); 701 } 702 703 /** 704 * Checks if provided instance has contents similar to this instance up to provided 705 * threshold value. 706 * 707 * @param other instance to be compared. 708 * @param threshold maximum difference allowed between position, velocity and coordinate transformation matrix. 709 * @return true if both instances are considered to be equal (up to provided threshold), false otherwise. 710 */ 711 public boolean equals(final T other, final double threshold) { 712 if (other == null) { 713 return false; 714 } 715 716 return Math.abs(x - other.x) <= threshold 717 && Math.abs(y - other.y) <= threshold 718 && Math.abs(z - other.z) <= threshold 719 && Math.abs(vx - other.vx) <= threshold 720 && Math.abs(vy - other.vy) <= threshold 721 && Math.abs(vz - other.vz) <= threshold 722 && c.equals(other.c, threshold); 723 } 724 }