1 /* Copyright 2002-2015 CS Systèmes d'Information 2 * Licensed to CS Systèmes d'Information (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.orbits; 18 19 import java.io.Serializable; 20 21 import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; 22 import org.apache.commons.math3.linear.DecompositionSolver; 23 import org.apache.commons.math3.linear.MatrixUtils; 24 import org.apache.commons.math3.linear.QRDecomposition; 25 import org.apache.commons.math3.linear.RealMatrix; 26 import org.apache.commons.math3.util.FastMath; 27 import org.orekit.errors.OrekitException; 28 import org.orekit.errors.OrekitMessages; 29 import org.orekit.frames.Frame; 30 import org.orekit.frames.Transform; 31 import org.orekit.time.AbsoluteDate; 32 import org.orekit.time.TimeInterpolable; 33 import org.orekit.time.TimeShiftable; 34 import org.orekit.time.TimeStamped; 35 import org.orekit.utils.PVCoordinatesProvider; 36 import org.orekit.utils.TimeStampedPVCoordinates; 37 38 /** 39 * This class handles orbital parameters. 40 41 * <p> 42 * For user convenience, both the Cartesian and the equinoctial elements 43 * are provided by this class, regardless of the canonical representation 44 * implemented in the derived class (which may be classical keplerian 45 * elements for example). 46 * </p> 47 * <p> 48 * The parameters are defined in a frame specified by the user. It is important 49 * to make sure this frame is consistent: it probably is inertial and centered 50 * on the central body. This information is used for example by some 51 * force models. 52 * </p> 53 * <p> 54 * The object <code>OrbitalParameters</code> is guaranteed to be immutable. 55 * </p> 56 * @author Luc Maisonobe 57 * @author Guylaine Prat 58 * @author Fabien Maussion 59 * @author Véronique Pommier-Maurussane 60 */ 61 public abstract class Orbit 62 implements TimeStamped, TimeShiftable<Orbit>, TimeInterpolable<Orbit>, 63 Serializable, PVCoordinatesProvider { 64 65 /** Serializable UID. */ 66 private static final long serialVersionUID = 438733454597999578L; 67 68 /** Frame in which are defined the orbital parameters. */ 69 private final Frame frame; 70 71 /** Date of the orbital parameters. */ 72 private final AbsoluteDate date; 73 74 /** Value of mu used to compute position and velocity (m³/s²). */ 75 private final double mu; 76 77 /** Computed PVCoordinates. */ 78 private transient TimeStampedPVCoordinates pvCoordinates; 79 80 /** Jacobian of the orbital parameters with mean angle with respect to the Cartesian coordinates. */ 81 private transient double[][] jacobianMeanWrtCartesian; 82 83 /** Jacobian of the Cartesian coordinates with respect to the orbital parameters with mean angle. */ 84 private transient double[][] jacobianWrtParametersMean; 85 86 /** Jacobian of the orbital parameters with eccentric angle with respect to the Cartesian coordinates. */ 87 private transient double[][] jacobianEccentricWrtCartesian; 88 89 /** Jacobian of the Cartesian coordinates with respect to the orbital parameters with eccentric angle. */ 90 private transient double[][] jacobianWrtParametersEccentric; 91 92 /** Jacobian of the orbital parameters with true angle with respect to the Cartesian coordinates. */ 93 private transient double[][] jacobianTrueWrtCartesian; 94 95 /** Jacobian of the Cartesian coordinates with respect to the orbital parameters with true angle. */ 96 private transient double[][] jacobianWrtParametersTrue; 97 98 /** Default constructor. 99 * Build a new instance with arbitrary default elements. 100 * @param frame the frame in which the parameters are defined 101 * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame}) 102 * @param date date of the orbital parameters 103 * @param mu central attraction coefficient (m^3/s^2) 104 * @exception IllegalArgumentException if frame is not a {@link 105 * Frame#isPseudoInertial pseudo-inertial frame} 106 */ 107 protected Orbit(final Frame frame, final AbsoluteDate date, final double mu) 108 throws IllegalArgumentException { 109 ensurePseudoInertialFrame(frame); 110 this.date = date; 111 this.mu = mu; 112 this.pvCoordinates = null; 113 this.frame = frame; 114 jacobianMeanWrtCartesian = null; 115 jacobianWrtParametersMean = null; 116 jacobianEccentricWrtCartesian = null; 117 jacobianWrtParametersEccentric = null; 118 jacobianTrueWrtCartesian = null; 119 jacobianWrtParametersTrue = null; 120 } 121 122 /** Set the orbit from Cartesian parameters. 123 * 124 * <p> The acceleration provided in {@code pvCoordinates} is accessible using 125 * {@link #getPVCoordinates()} and {@link #getPVCoordinates(Frame)}. All other methods 126 * use {@code mu} and the position to compute the acceleration, including 127 * {@link #shiftedBy(double)} and {@link #getPVCoordinates(AbsoluteDate, Frame)}. 128 * 129 * @param pvCoordinates the position and velocity in the inertial frame 130 * @param frame the frame in which the {@link TimeStampedPVCoordinates} are defined 131 * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame}) 132 * @param mu central attraction coefficient (m^3/s^2) 133 * @exception IllegalArgumentException if frame is not a {@link 134 * Frame#isPseudoInertial pseudo-inertial frame} 135 */ 136 protected Orbit(final TimeStampedPVCoordinates pvCoordinates, final Frame frame, final double mu) 137 throws IllegalArgumentException { 138 ensurePseudoInertialFrame(frame); 139 this.date = pvCoordinates.getDate(); 140 this.mu = mu; 141 if (pvCoordinates.getAcceleration().getNormSq() == 0) { 142 // the acceleration was not provided, 143 // compute it from Newtonian attraction 144 final double r2 = pvCoordinates.getPosition().getNormSq(); 145 final double r3 = r2 * FastMath.sqrt(r2); 146 this.pvCoordinates = new TimeStampedPVCoordinates(pvCoordinates.getDate(), 147 pvCoordinates.getPosition(), 148 pvCoordinates.getVelocity(), 149 new Vector3D(-mu / r3, pvCoordinates.getPosition())); 150 } else { 151 this.pvCoordinates = pvCoordinates; 152 } 153 this.frame = frame; 154 } 155 156 /** Get the orbit type. 157 * @return orbit type 158 */ 159 public abstract OrbitType getType(); 160 161 /** Ensure the defining frame is a pseudo-inertial frame. 162 * @param frame frame to check 163 * @exception IllegalArgumentException if frame is not a {@link 164 * Frame#isPseudoInertial pseudo-inertial frame} 165 */ 166 private static void ensurePseudoInertialFrame(final Frame frame) 167 throws IllegalArgumentException { 168 if (!frame.isPseudoInertial()) { 169 throw OrekitException.createIllegalArgumentException( 170 OrekitMessages.NON_PSEUDO_INERTIAL_FRAME_NOT_SUITABLE_FOR_DEFINING_ORBITS, 171 frame.getName()); 172 } 173 } 174 175 /** Get the frame in which the orbital parameters are defined. 176 * @return frame in which the orbital parameters are defined 177 */ 178 public Frame getFrame() { 179 return frame; 180 } 181 182 /** Get the semi-major axis. 183 * <p>Note that the semi-major axis is considered negative for hyperbolic orbits.</p> 184 * @return semi-major axis (m) 185 */ 186 public abstract double getA(); 187 188 /** Get the first component of the equinoctial eccentricity vector. 189 * @return first component of the equinoctial eccentricity vector 190 */ 191 public abstract double getEquinoctialEx(); 192 193 /** Get the second component of the equinoctial eccentricity vector. 194 * @return second component of the equinoctial eccentricity vector 195 */ 196 public abstract double getEquinoctialEy(); 197 198 /** Get the first component of the inclination vector. 199 * @return first component of the inclination vector 200 */ 201 public abstract double getHx(); 202 203 /** Get the second component of the inclination vector. 204 * @return second component of the inclination vector 205 */ 206 public abstract double getHy(); 207 208 /** Get the eccentric longitude argument. 209 * @return E + ω + Ω eccentric longitude argument (rad) 210 */ 211 public abstract double getLE(); 212 213 /** Get the true longitude argument. 214 * @return v + ω + Ω true longitude argument (rad) 215 */ 216 public abstract double getLv(); 217 218 /** Get the mean longitude argument. 219 * @return M + ω + Ω mean longitude argument (rad) 220 */ 221 public abstract double getLM(); 222 223 // Additional orbital elements 224 225 /** Get the eccentricity. 226 * @return eccentricity 227 */ 228 public abstract double getE(); 229 230 /** Get the inclination. 231 * @return inclination (rad) 232 */ 233 public abstract double getI(); 234 235 /** Get the central acceleration constant. 236 * @return central acceleration constant 237 */ 238 public double getMu() { 239 return mu; 240 } 241 242 /** Get the keplerian period. 243 * <p>The keplerian period is computed directly from semi major axis 244 * and central acceleration constant.</p> 245 * @return keplerian period in seconds, or positive infinity for hyperbolic orbits 246 */ 247 public double getKeplerianPeriod() { 248 final double a = getA(); 249 return (a < 0) ? Double.POSITIVE_INFINITY : 2.0 * FastMath.PI * a * FastMath.sqrt(a / mu); 250 } 251 252 /** Get the keplerian mean motion. 253 * <p>The keplerian mean motion is computed directly from semi major axis 254 * and central acceleration constant.</p> 255 * @return keplerian mean motion in radians per second 256 */ 257 public double getKeplerianMeanMotion() { 258 final double absA = FastMath.abs(getA()); 259 return FastMath.sqrt(mu / absA) / absA; 260 } 261 262 /** Get the date of orbital parameters. 263 * @return date of the orbital parameters 264 */ 265 public AbsoluteDate getDate() { 266 return date; 267 } 268 269 /** Get the {@link TimeStampedPVCoordinates} in a specified frame. 270 * @param outputFrame frame in which the position/velocity coordinates shall be computed 271 * @return pvCoordinates in the specified output frame 272 * @exception OrekitException if transformation between frames cannot be computed 273 * @see #getPVCoordinates() 274 */ 275 public TimeStampedPVCoordinates getPVCoordinates(final Frame outputFrame) 276 throws OrekitException { 277 if (pvCoordinates == null) { 278 pvCoordinates = initPVCoordinates(); 279 } 280 281 // If output frame requested is the same as definition frame, 282 // PV coordinates are returned directly 283 if (outputFrame == frame) { 284 return pvCoordinates; 285 } 286 287 // Else, PV coordinates are transformed to output frame 288 final Transform t = frame.getTransformTo(outputFrame, date); 289 return t.transformPVCoordinates(pvCoordinates); 290 } 291 292 /** {@inheritDoc} */ 293 public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate otherDate, final Frame otherFrame) 294 throws OrekitException { 295 return shiftedBy(otherDate.durationFrom(getDate())).getPVCoordinates(otherFrame); 296 } 297 298 299 /** Get the {@link TimeStampedPVCoordinates} in definition frame. 300 * @return pvCoordinates in the definition frame 301 * @see #getPVCoordinates(Frame) 302 */ 303 public TimeStampedPVCoordinates getPVCoordinates() { 304 if (pvCoordinates == null) { 305 pvCoordinates = initPVCoordinates(); 306 } 307 return pvCoordinates; 308 } 309 310 /** Compute the position/velocity coordinates from the canonical parameters. 311 * @return computed position/velocity coordinates 312 */ 313 protected abstract TimeStampedPVCoordinates initPVCoordinates(); 314 315 /** Get a time-shifted orbit. 316 * <p> 317 * The orbit can be slightly shifted to close dates. This shift is based on 318 * a simple keplerian model. It is <em>not</em> intended as a replacement 319 * for proper orbit and attitude propagation but should be sufficient for 320 * small time shifts or coarse accuracy. 321 * </p> 322 * @param dt time shift in seconds 323 * @return a new orbit, shifted with respect to the instance (which is immutable) 324 */ 325 public abstract Orbit shiftedBy(final double dt); 326 327 /** Compute the Jacobian of the orbital parameters with respect to the Cartesian parameters. 328 * <p> 329 * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with 330 * respect to Cartesian coordinate j. This means each row corresponds to one orbital parameter 331 * whereas columns 0 to 5 correspond to the Cartesian coordinates x, y, z, xDot, yDot and zDot. 332 * </p> 333 * @param type type of the position angle to use 334 * @param jacobian placeholder 6x6 (or larger) matrix to be filled with the Jacobian, if matrix 335 * is larger than 6x6, only the 6x6 upper left corner will be modified 336 */ 337 public void getJacobianWrtCartesian(final PositionAngle type, final double[][] jacobian) { 338 339 final double[][] cachedJacobian; 340 synchronized (this) { 341 switch (type) { 342 case MEAN : 343 if (jacobianMeanWrtCartesian == null) { 344 // first call, we need to compute the jacobian and cache it 345 jacobianMeanWrtCartesian = computeJacobianMeanWrtCartesian(); 346 } 347 cachedJacobian = jacobianMeanWrtCartesian; 348 break; 349 case ECCENTRIC : 350 if (jacobianEccentricWrtCartesian == null) { 351 // first call, we need to compute the jacobian and cache it 352 jacobianEccentricWrtCartesian = computeJacobianEccentricWrtCartesian(); 353 } 354 cachedJacobian = jacobianEccentricWrtCartesian; 355 break; 356 case TRUE : 357 if (jacobianTrueWrtCartesian == null) { 358 // first call, we need to compute the jacobian and cache it 359 jacobianTrueWrtCartesian = computeJacobianTrueWrtCartesian(); 360 } 361 cachedJacobian = jacobianTrueWrtCartesian; 362 break; 363 default : 364 throw OrekitException.createInternalError(null); 365 } 366 } 367 368 // fill the user provided array 369 for (int i = 0; i < cachedJacobian.length; ++i) { 370 System.arraycopy(cachedJacobian[i], 0, jacobian[i], 0, cachedJacobian[i].length); 371 } 372 373 } 374 375 /** Compute the Jacobian of the Cartesian parameters with respect to the orbital parameters. 376 * <p> 377 * Element {@code jacobian[i][j]} is the derivative of Cartesian coordinate i of the orbit with 378 * respect to orbital parameter j. This means each row corresponds to one Cartesian coordinate 379 * x, y, z, xdot, ydot, zdot whereas columns 0 to 5 correspond to the orbital parameters. 380 * </p> 381 * @param type type of the position angle to use 382 * @param jacobian placeholder 6x6 (or larger) matrix to be filled with the Jacobian, if matrix 383 * is larger than 6x6, only the 6x6 upper left corner will be modified 384 */ 385 public void getJacobianWrtParameters(final PositionAngle type, final double[][] jacobian) { 386 387 final double[][] cachedJacobian; 388 synchronized (this) { 389 switch (type) { 390 case MEAN : 391 if (jacobianWrtParametersMean == null) { 392 // first call, we need to compute the jacobian and cache it 393 jacobianWrtParametersMean = createInverseJacobian(type); 394 } 395 cachedJacobian = jacobianWrtParametersMean; 396 break; 397 case ECCENTRIC : 398 if (jacobianWrtParametersEccentric == null) { 399 // first call, we need to compute the jacobian and cache it 400 jacobianWrtParametersEccentric = createInverseJacobian(type); 401 } 402 cachedJacobian = jacobianWrtParametersEccentric; 403 break; 404 case TRUE : 405 if (jacobianWrtParametersTrue == null) { 406 // first call, we need to compute the jacobian and cache it 407 jacobianWrtParametersTrue = createInverseJacobian(type); 408 } 409 cachedJacobian = jacobianWrtParametersTrue; 410 break; 411 default : 412 throw OrekitException.createInternalError(null); 413 } 414 } 415 416 // fill the user-provided array 417 for (int i = 0; i < cachedJacobian.length; ++i) { 418 System.arraycopy(cachedJacobian[i], 0, jacobian[i], 0, cachedJacobian[i].length); 419 } 420 421 } 422 423 /** Create an inverse Jacobian. 424 * @param type type of the position angle to use 425 * @return inverse Jacobian 426 */ 427 private double[][] createInverseJacobian(final PositionAngle type) { 428 429 // get the direct Jacobian 430 final double[][] directJacobian = new double[6][6]; 431 getJacobianWrtCartesian(type, directJacobian); 432 433 // invert the direct Jacobian 434 final RealMatrix matrix = MatrixUtils.createRealMatrix(directJacobian); 435 final DecompositionSolver solver = new QRDecomposition(matrix).getSolver(); 436 return solver.getInverse().getData(); 437 438 } 439 440 /** Compute the Jacobian of the orbital parameters with mean angle with respect to the Cartesian parameters. 441 * <p> 442 * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with 443 * respect to Cartesian coordinate j. This means each row correspond to one orbital parameter 444 * whereas columns 0 to 5 correspond to the Cartesian coordinates x, y, z, xDot, yDot and zDot. 445 * </p> 446 * @return 6x6 Jacobian matrix 447 * @see #computeJacobianEccentricWrtCartesian() 448 * @see #computeJacobianTrueWrtCartesian() 449 */ 450 protected abstract double[][] computeJacobianMeanWrtCartesian(); 451 452 /** Compute the Jacobian of the orbital parameters with eccentric angle with respect to the Cartesian parameters. 453 * <p> 454 * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with 455 * respect to Cartesian coordinate j. This means each row correspond to one orbital parameter 456 * whereas columns 0 to 5 correspond to the Cartesian coordinates x, y, z, xDot, yDot and zDot. 457 * </p> 458 * @return 6x6 Jacobian matrix 459 * @see #computeJacobianMeanWrtCartesian() 460 * @see #computeJacobianTrueWrtCartesian() 461 */ 462 protected abstract double[][] computeJacobianEccentricWrtCartesian(); 463 464 /** Compute the Jacobian of the orbital parameters with true angle with respect to the Cartesian parameters. 465 * <p> 466 * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with 467 * respect to Cartesian coordinate j. This means each row correspond to one orbital parameter 468 * whereas columns 0 to 5 correspond to the Cartesian coordinates x, y, z, xDot, yDot and zDot. 469 * </p> 470 * @return 6x6 Jacobian matrix 471 * @see #computeJacobianMeanWrtCartesian() 472 * @see #computeJacobianEccentricWrtCartesian() 473 */ 474 protected abstract double[][] computeJacobianTrueWrtCartesian(); 475 476 /** Add the contribution of the Keplerian motion to parameters derivatives 477 * <p> 478 * This method is used by integration-based propagators to evaluate the part of Keplerian 479 * motion to evolution of the orbital state. 480 * </p> 481 * @param type type of the position angle in the state 482 * @param gm attraction coefficient to use 483 * @param pDot array containing orbital state derivatives to update (the Keplerian 484 * part must be <em>added</em> to the array components, as the array may already 485 * contain some non-zero elements corresponding to non-Keplerian parts) 486 */ 487 public abstract void addKeplerContribution(final PositionAngle type, final double gm, double[] pDot); 488 489 /** Fill a Jacobian half row with a single vector. 490 * @param a coefficient of the vector 491 * @param v vector 492 * @param row Jacobian matrix row 493 * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set) 494 */ 495 protected static void fillHalfRow(final double a, final Vector3D v, final double[] row, final int j) { 496 row[j] = a * v.getX(); 497 row[j + 1] = a * v.getY(); 498 row[j + 2] = a * v.getZ(); 499 } 500 501 /** Fill a Jacobian half row with a linear combination of vectors. 502 * @param a1 coefficient of the first vector 503 * @param v1 first vector 504 * @param a2 coefficient of the second vector 505 * @param v2 second vector 506 * @param row Jacobian matrix row 507 * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set) 508 */ 509 protected static void fillHalfRow(final double a1, final Vector3D v1, final double a2, final Vector3D v2, 510 final double[] row, final int j) { 511 row[j] = a1 * v1.getX() + a2 * v2.getX(); 512 row[j + 1] = a1 * v1.getY() + a2 * v2.getY(); 513 row[j + 2] = a1 * v1.getZ() + a2 * v2.getZ(); 514 } 515 516 /** Fill a Jacobian half row with a linear combination of vectors. 517 * @param a1 coefficient of the first vector 518 * @param v1 first vector 519 * @param a2 coefficient of the second vector 520 * @param v2 second vector 521 * @param a3 coefficient of the third vector 522 * @param v3 third vector 523 * @param row Jacobian matrix row 524 * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set) 525 */ 526 protected static void fillHalfRow(final double a1, final Vector3D v1, final double a2, final Vector3D v2, 527 final double a3, final Vector3D v3, 528 final double[] row, final int j) { 529 row[j] = a1 * v1.getX() + a2 * v2.getX() + a3 * v3.getX(); 530 row[j + 1] = a1 * v1.getY() + a2 * v2.getY() + a3 * v3.getY(); 531 row[j + 2] = a1 * v1.getZ() + a2 * v2.getZ() + a3 * v3.getZ(); 532 } 533 534 /** Fill a Jacobian half row with a linear combination of vectors. 535 * @param a1 coefficient of the first vector 536 * @param v1 first vector 537 * @param a2 coefficient of the second vector 538 * @param v2 second vector 539 * @param a3 coefficient of the third vector 540 * @param v3 third vector 541 * @param a4 coefficient of the fourth vector 542 * @param v4 fourth vector 543 * @param row Jacobian matrix row 544 * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set) 545 */ 546 protected static void fillHalfRow(final double a1, final Vector3D v1, final double a2, final Vector3D v2, 547 final double a3, final Vector3D v3, final double a4, final Vector3D v4, 548 final double[] row, final int j) { 549 row[j] = a1 * v1.getX() + a2 * v2.getX() + a3 * v3.getX() + a4 * v4.getX(); 550 row[j + 1] = a1 * v1.getY() + a2 * v2.getY() + a3 * v3.getY() + a4 * v4.getY(); 551 row[j + 2] = a1 * v1.getZ() + a2 * v2.getZ() + a3 * v3.getZ() + a4 * v4.getZ(); 552 } 553 554 /** Fill a Jacobian half row with a linear combination of vectors. 555 * @param a1 coefficient of the first vector 556 * @param v1 first vector 557 * @param a2 coefficient of the second vector 558 * @param v2 second vector 559 * @param a3 coefficient of the third vector 560 * @param v3 third vector 561 * @param a4 coefficient of the fourth vector 562 * @param v4 fourth vector 563 * @param a5 coefficient of the fifth vector 564 * @param v5 fifth vector 565 * @param row Jacobian matrix row 566 * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set) 567 */ 568 protected static void fillHalfRow(final double a1, final Vector3D v1, final double a2, final Vector3D v2, 569 final double a3, final Vector3D v3, final double a4, final Vector3D v4, 570 final double a5, final Vector3D v5, 571 final double[] row, final int j) { 572 row[j] = a1 * v1.getX() + a2 * v2.getX() + a3 * v3.getX() + a4 * v4.getX() + a5 * v5.getX(); 573 row[j + 1] = a1 * v1.getY() + a2 * v2.getY() + a3 * v3.getY() + a4 * v4.getY() + a5 * v5.getY(); 574 row[j + 2] = a1 * v1.getZ() + a2 * v2.getZ() + a3 * v3.getZ() + a4 * v4.getZ() + a5 * v5.getZ(); 575 } 576 577 /** Fill a Jacobian half row with a linear combination of vectors. 578 * @param a1 coefficient of the first vector 579 * @param v1 first vector 580 * @param a2 coefficient of the second vector 581 * @param v2 second vector 582 * @param a3 coefficient of the third vector 583 * @param v3 third vector 584 * @param a4 coefficient of the fourth vector 585 * @param v4 fourth vector 586 * @param a5 coefficient of the fifth vector 587 * @param v5 fifth vector 588 * @param a6 coefficient of the sixth vector 589 * @param v6 sixth vector 590 * @param row Jacobian matrix row 591 * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set) 592 */ 593 protected static void fillHalfRow(final double a1, final Vector3D v1, final double a2, final Vector3D v2, 594 final double a3, final Vector3D v3, final double a4, final Vector3D v4, 595 final double a5, final Vector3D v5, final double a6, final Vector3D v6, 596 final double[] row, final int j) { 597 row[j] = a1 * v1.getX() + a2 * v2.getX() + a3 * v3.getX() + a4 * v4.getX() + a5 * v5.getX() + a6 * v6.getX(); 598 row[j + 1] = a1 * v1.getY() + a2 * v2.getY() + a3 * v3.getY() + a4 * v4.getY() + a5 * v5.getY() + a6 * v6.getY(); 599 row[j + 2] = a1 * v1.getZ() + a2 * v2.getZ() + a3 * v3.getZ() + a4 * v4.getZ() + a5 * v5.getZ() + a6 * v6.getZ(); 600 } 601 602 }