/* $Procedure M2EUL ( Matrix to Euler angles ) */ /* Subroutine */ int m2eul_(doublereal *r__, integer *axis3, integer *axis2, integer *axis1, doublereal *angle3, doublereal *angle2, doublereal * angle1) { /* Initialized data */ static integer next[3] = { 2,3,1 }; /* System generated locals */ integer i__1, i__2; /* Builtin functions */ integer s_rnge(char *, integer, char *, integer); double acos(doublereal), atan2(doublereal, doublereal), asin(doublereal); /* Local variables */ doublereal sign; extern /* Subroutine */ int vhat_(doublereal *, doublereal *), mtxm_( doublereal *, doublereal *, doublereal *); integer c__, i__; logical degen; extern /* Subroutine */ int chkin_(char *, ftnlen); extern logical isrot_(doublereal *, doublereal *, doublereal *); doublereal change[9] /* was [3][3] */; extern /* Subroutine */ int cleard_(integer *, doublereal *), sigerr_( char *, ftnlen), chkout_(char *, ftnlen); doublereal tmpmat[9] /* was [3][3] */; extern /* Subroutine */ int setmsg_(char *, ftnlen), errint_(char *, integer *, ftnlen); extern logical return_(void); doublereal tmprot[9] /* was [3][3] */; extern /* Subroutine */ int mxm_(doublereal *, doublereal *, doublereal *) ; /* $ Abstract */ /* Factor a rotation matrix as a product of three rotations about */ /* specified coordinate axes. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* ROTATION */ /* $ Keywords */ /* ANGLE */ /* MATRIX */ /* ROTATION */ /* TRANSFORMATION */ /* $ Declarations */ /* $ Brief_I/O */ /* Variable I/O Description */ /* -------- --- -------------------------------------------------- */ /* R I A rotation matrix to be factored. */ /* AXIS3, */ /* AXIS2, */ /* AXIS1 I Numbers of third, second, and first rotation axes. */ /* ANGLE3, */ /* ANGLE2, */ /* ANGLE1 O Third, second, and first Euler angles, in radians. */ /* $ Detailed_Input */ /* R is a 3x3 rotation matrix that is to be factored as */ /* a product of three rotations about a specified */ /* coordinate axes. The angles of these rotations are */ /* called `Euler angles'. */ /* AXIS3, */ /* AXIS2, */ /* AXIS1 are the indices of the rotation axes of the */ /* `factor' rotations, whose product is R. R is */ /* factored as */ /* R = [ ANGLE3 ] [ ANGLE2 ] [ ANGLE1 ] . */ /* AXIS3 AXIS2 AXIS1 */ /* The axis numbers must belong to the set {1, 2, 3}. */ /* The second axis number MUST differ from the first */ /* and third axis numbers. */ /* See the $ Particulars section below for details */ /* concerning this notation. */ /* $ Detailed_Output */ /* ANGLE3, */ /* ANGLE2, */ /* ANGLE1 are the Euler angles corresponding to the matrix */ /* R and the axes specified by AXIS3, AXIS2, and */ /* AXIS1. These angles satisfy the equality */ /* R = [ ANGLE3 ] [ ANGLE2 ] [ ANGLE1 ] */ /* AXIS3 AXIS2 AXIS1 */ /* See the $ Particulars section below for details */ /* concerning this notation. */ /* The range of ANGLE3 and ANGLE1 is (-pi, pi]. */ /* The range of ANGLE2 depends on the exact set of */ /* axes used for the factorization. For */ /* factorizations in which the first and third axes */ /* are the same, */ /* R = [r] [s] [t] , */ /* a b a */ /* the range of ANGLE2 is [0, pi]. */ /* For factorizations in which the first and third */ /* axes are different, */ /* R = [r] [s] [t] , */ /* a b c */ /* the range of ANGLE2 is [-pi/2, pi/2]. */ /* For rotations such that ANGLE3 and ANGLE1 are not */ /* uniquely determined, ANGLE3 will always be set to */ /* zero; ANGLE1 is then uniquely determined. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If any of AXIS3, AXIS2, or AXIS1 do not have values in */ /* { 1, 2, 3 }, */ /* then the error SPICE(BADAXISNUMBERS) is signaled. */ /* 2) An arbitrary rotation matrix cannot be expressed using */ /* a sequence of Euler angles unless the second rotation axis */ /* differs from the other two. If AXIS2 is equal to AXIS3 or */ /* AXIS1, then then error SPICE(BADAXISNUMBERS) is signaled. */ /* 3) If the input matrix R is not a rotation matrix, the error */ /* SPICE(NOTAROTATION) is signaled. */ /* 4) If ANGLE3 and ANGLE1 are not uniquely determined, ANGLE3 */ /* is set to zero, and ANGLE1 is determined. */ /* $ Files */ /* None. */ /* $ Particulars */ /* A word about notation: the symbol */ /* [ x ] */ /* i */ /* indicates a coordinate system rotation of x radians about the */ /* ith coordinate axis. To be specific, the symbol */ /* [ x ] */ /* 1 */ /* indicates a coordinate system rotation of x radians about the */ /* first, or x-, axis; the corresponding matrix is */ /* +- -+ */ /* | 1 0 0 | */ /* | | */ /* | 0 cos(x) sin(x) |. */ /* | | */ /* | 0 -sin(x) cos(x) | */ /* +- -+ */ /* Remember, this is a COORDINATE SYSTEM rotation by x radians; this */ /* matrix, when applied to a vector, rotates the vector by -x */ /* radians, not x radians. Applying the matrix to a vector yields */ /* the vector's representation relative to the rotated coordinate */ /* system. */ /* The analogous rotation about the second, or y-, axis is */ /* represented by */ /* [ x ] */ /* 2 */ /* which symbolizes the matrix */ /* +- -+ */ /* | cos(x) 0 -sin(x) | */ /* | | */ /* | 0 1 0 |, */ /* | | */ /* | sin(x) 0 cos(x) | */ /* +- -+ */ /* and the analogous rotation about the third, or z-, axis is */ /* represented by */ /* [ x ] */ /* 3 */ /* which symbolizes the matrix */ /* +- -+ */ /* | cos(x) sin(x) 0 | */ /* | | */ /* | -sin(x) cos(x) 0 |. */ /* | | */ /* | 0 0 1 | */ /* +- -+ */ /* The input matrix is assumed to be the product of three */ /* rotation matrices, each one of the form */ /* +- -+ */ /* | 1 0 0 | */ /* | | */ /* | 0 cos(r) sin(r) | (rotation of r radians about the */ /* | | x-axis), */ /* | 0 -sin(r) cos(r) | */ /* +- -+ */ /* +- -+ */ /* | cos(s) 0 -sin(s) | */ /* | | */ /* | 0 1 0 | (rotation of s radians about the */ /* | | y-axis), */ /* | sin(s) 0 cos(s) | */ /* +- -+ */ /* or */ /* +- -+ */ /* | cos(t) sin(t) 0 | */ /* | | */ /* | -sin(t) cos(t) 0 | (rotation of t radians about the */ /* | | z-axis), */ /* | 0 0 1 | */ /* +- -+ */ /* where the second rotation axis is not equal to the first or */ /* third. Any rotation matrix can be factored as a sequence of */ /* three such rotations, provided that this last criterion is met. */ /* This routine is related to the SPICELIB routine EUL2M, which */ /* produces a rotation matrix, given a sequence of Euler angles. */ /* This routine is a `right inverse' of EUL2M: the sequence of */ /* calls */ /* CALL M2EUL ( R, AXIS3, AXIS2, AXIS1, */ /* . ANGLE3, ANGLE2, ANGLE1 ) */ /* CALL EUL2M ( ANGLE3, ANGLE2, ANGLE1, */ /* . AXIS3, AXIS2, AXIS1, R ) */ /* preserves R, except for round-off error. */ /* On the other hand, the sequence of calls */ /* CALL EUL2M ( ANGLE3, ANGLE2, ANGLE1, */ /* . AXIS3, AXIS2, AXIS1, R ) */ /* CALL M2EUL ( R, AXIS3, AXIS2, AXIS1, */ /* . ANGLE3, ANGLE2, ANGLE1 ) */ /* preserve ANGLE3, ANGLE2, and ANGLE1 only if these angles start */ /* out in the ranges that M2EUL's outputs are restricted to. */ /* $ Examples */ /* 1) Conversion of instrument pointing from a matrix representation */ /* to Euler angles: */ /* Suppose we want to find camera pointing in alpha, delta, and */ /* kappa, given the inertial-to-camera coordinate transformation */ /* +- -+ */ /* | 0.49127379678135830 0.50872620321864170 0.70699908539882417 | */ /* | | */ /* | -0.50872620321864193 -0.49127379678135802 0.70699908539882428 | */ /* | | */ /* | 0.70699908539882406 -0.70699908539882439 0.01745240643728360 | */ /* +- -+ */ /* We want to find angles alpha, delta, kappa such that */ /* TICAM = [ kappa ] [ pi/2 - delta ] [ pi/2 + alpha ] . */ /* 3 1 3 */ /* We can use the following small program to do this computation: */ /* PROGRAM EX1 */ /* IMPLICIT NONE */ /* DOUBLE PRECISION DPR */ /* DOUBLE PRECISION HALFPI */ /* DOUBLE PRECISION TWOPI */ /* DOUBLE PRECISION ALPHA */ /* DOUBLE PRECISION ANG1 */ /* DOUBLE PRECISION ANG2 */ /* DOUBLE PRECISION DELTA */ /* DOUBLE PRECISION KAPPA */ /* DOUBLE PRECISION TICAM ( 3, 3 ) */ /* DATA TICAM / 0.49127379678135830D0, */ /* . -0.50872620321864193D0, */ /* . 0.70699908539882406D0, */ /* . 0.50872620321864170D0, */ /* . -0.49127379678135802D0, */ /* . -0.70699908539882439D0, */ /* . 0.70699908539882417D0, */ /* . 0.70699908539882428D0, */ /* . 0.01745240643728360D0 / */ /* CALL M2EUL ( TICAM, 3, 1, 3, KAPPA, ANG2, ANG1 ) */ /* DELTA = HALFPI() - ANG2 */ /* ALPHA = ANG1 - HALFPI() */ /* IF ( KAPPA .LT. 0.D0 ) THEN */ /* KAPPA = KAPPA + TWOPI() */ /* END IF */ /* IF ( ALPHA .LT. 0.D0 ) THEN */ /* ALPHA = ALPHA + TWOPI() */ /* END IF */ /* WRITE (*,'(1X,A,F24.14)') 'Alpha (deg): ', DPR() * ALPHA */ /* WRITE (*,'(1X,A,F24.14)') 'Delta (deg): ', DPR() * DELTA */ /* WRITE (*,'(1X,A,F24.14)') 'Kappa (deg): ', DPR() * KAPPA */ /* END */ /* The program's output should be something like */ /* Alpha (deg): 315.00000000000000 */ /* Delta (deg): 1.00000000000000 */ /* Kappa (deg): 45.00000000000000 */ /* possibly formatted a little differently, or degraded slightly */ /* by round-off. */ /* 2) Conversion of instrument pointing angles from a non-J2000, */ /* not necessarily inertial frame to J2000-relative RA, Dec, */ /* and Twist. */ /* Suppose that we have pointing for some instrument expressed as */ /* [ gamma ] [ beta ] [ alpha ] */ /* 3 2 3 */ /* with respect to some coordinate system S. For example, S */ /* could be a spacecraft-fixed system. */ /* We will suppose that the transformation from J2000 */ /* coordinates to system S coordinates is given by the rotation */ /* matrix J2S. */ /* The rows of J2S are the unit basis vectors of system S, given */ /* in J2000 coordinates. */ /* We want to express the pointing with respect to the J2000 */ /* system as the sequence of rotations */ /* [ kappa ] [ pi/2 - delta ] [ pi/2 + alpha ] . */ /* 3 1 3 */ /* First, we use subroutine EUL2M to form the transformation */ /* from system S to instrument coordinates S2INST. */ /* CALL EUL2M ( GAMMA, BETA, ALPHA, 3, 2, 3, S2INST ) */ /* Next, we form the transformation from J2000 to instrument */ /* coordinates J2INST. */ /* CALL MXM ( S2INST, J2S, J2INST ) */ /* Finally, we express J2INST using the desired Euler angles, as */ /* in the first example: */ /* CALL M2EUL ( J2INST, 3, 1, 3, TWIST, ANG2, ANG3 ) */ /* RA = ANG3 - HALFPI() */ /* DEC = HALFPI() - ANG2 */ /* If we wish to make sure that RA, DEC, and TWIST are in */ /* the ranges [0, 2pi), [-pi/2, pi/2], and [0, 2pi) */ /* respectively, we may add the code */ /* IF ( RA .LT. 0.D0 ) THEN */ /* RA = RA + TWOPI() */ /* END IF */ /* IF ( TWIST .LT. 0.D0 ) THEN */ /* TWIST = TWIST + TWOPI() */ /* END IF */ /* Note that DEC is already in the correct range, since ANG2 */ /* is in the range [0, pi] when the first and third input axes */ /* are equal. */ /* Now RA, DEC, and TWIST express the instrument pointing */ /* as RA, Dec, and Twist, relative to the J2000 system. */ /* A warning note: more than one definition of RA, Dec, and */ /* Twist is extant. Before using this example in an application, */ /* check that the definition given here is consistent with that */ /* used in your application. */ /* $ Restrictions */ /* None. */ /* $ Literature_References */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* $ Version */ /* - SPICELIB Version 1.2.1, 21-DEC-2006 (NJB) */ /* Error corrected in header example: input matrix */ /* previously did not match shown outputs. Offending */ /* example now includes complete program. */ /* - SPICELIB Version 1.2.0, 15-OCT-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in MXM and MTXM calls. A short error message cited in */ /* the Exceptions section of the header failed to match */ /* the actual short message used; this has been corrected. */ /* - SPICELIB Version 1.1.2, 13-OCT-2004 (NJB) */ /* Fixed header typo. */ /* - SPICELIB Version 1.1.1, 10-MAR-1992 (WLT) */ /* Comment section for permuted index source lines was added */ /* following the header. */ /* - SPICELIB Version 1.1.0, 02-NOV-1990 (NJB) */ /* Header upgraded to describe notation in more detail. Argument */ /* names were changed to describe the use of the arguments more */ /* accurately. No change in functionality was made; the operation */ /* of the routine is identical to that of the previous version. */ /* - SPICELIB Version 1.0.0, 03-SEP-1990 (NJB) */ /* -& */ /* $ Index_Entries */ /* matrix to euler angles */ /* -& */ /* $ Revisions */ /* - SPICELIB Version 1.2.0, 26-AUG-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in MXM and MTXM calls. A short error message cited in */ /* the Exceptions section of the header failed to match */ /* the actual short message used; this has been corrected. */ /* - SPICELIB Version 1.1.0, 02-NOV-1990 (NJB) */ /* Argument names were changed to describe the use of the */ /* arguments more accurately. The axis and angle numbers */ /* now decrease, rather than increase, from left to right. */ /* The current names reflect the order of operator application */ /* when the Euler angle rotations are applied to a vector: the */ /* rightmost matrix */ /* [ ANGLE1 ] */ /* AXIS1 */ /* is applied to the vector first, followed by */ /* [ ANGLE2 ] */ /* AXIS2 */ /* and then */ /* [ ANGLE3 ] */ /* AXIS3 */ /* Previously, the names reflected the order in which the Euler */ /* angle matrices appear on the page, from left to right. This */ /* naming convention was found to be a bit obtuse by a various */ /* users. */ /* No change in functionality was made; the operation of the */ /* routine is identical to that of the previous version. */ /* Also, the header was upgraded to describe the notation in more */ /* detail. The symbol */ /* [ x ] */ /* i */ /* is explained at mind-numbing length. An example was added */ /* that shows a specific set of inputs and the resulting output */ /* matrix. */ /* The angle sequence notation was changed to be consistent with */ /* Rotations required reading. */ /* 1-2-3 and a-b-c */ /* have been changed to */ /* 3-2-1 and c-b-a. */ /* Also, one `)' was changed to a `}'. */ /* The phrase `first and third' was changed to `first or third' */ /* in the $ Particulars section, where the criterion for the */ /* existence of an Euler angle factorization is stated. */ /* -& */ /* SPICELIB functions */ /* Local parameters */ /* NTOL and DETOL are used to determine whether R is a rotation */ /* matrix. */ /* NTOL is the tolerance for the norms of the columns of R. */ /* DTOL is the tolerance for the determinant of a matrix whose */ /* columns are the unitized columns of R. */ /* Local variables */ /* Saved variables */ /* Initial values */ /* Standard SPICE error handling. */ if (return_()) { return 0; } else { chkin_("M2EUL", (ftnlen)5); } /* The first order of business is to screen out the goofy cases. */ /* Make sure the axis numbers are all right: They must belong to */ /* the set {1, 2, 3}... */ if (*axis3 < 1 || *axis3 > 3 || (*axis2 < 1 || *axis2 > 3) || (*axis1 < 1 || *axis1 > 3)) { setmsg_("Axis numbers are #, #, #. ", (ftnlen)28); errint_("#", axis3, (ftnlen)1); errint_("#", axis2, (ftnlen)1); errint_("#", axis1, (ftnlen)1); sigerr_("SPICE(BADAXISNUMBERS)", (ftnlen)21); chkout_("M2EUL", (ftnlen)5); return 0; /* ...and the second axis number must differ from its neighbors. */ } else if (*axis3 == *axis2 || *axis1 == *axis2) { setmsg_("Middle axis matches neighbor: # # #.", (ftnlen)36); errint_("#", axis3, (ftnlen)1); errint_("#", axis2, (ftnlen)1); errint_("#", axis1, (ftnlen)1); sigerr_("SPICE(BADAXISNUMBERS)", (ftnlen)21); chkout_("M2EUL", (ftnlen)5); return 0; /* R must be a rotation matrix, or we may as well forget it. */ } else if (! isrot_(r__, &c_b15, &c_b15)) { setmsg_("Input matrix is not a rotation.", (ftnlen)31); sigerr_("SPICE(NOTAROTATION)", (ftnlen)19); chkout_("M2EUL", (ftnlen)5); return 0; } /* AXIS3, AXIS2, AXIS1 and R have passed their tests at this */ /* point. We take the liberty of working with TMPROT, a version */ /* of R that has unitized columns. */ for (i__ = 1; i__ <= 3; ++i__) { vhat_(&r__[(i__1 = i__ * 3 - 3) < 9 && 0 <= i__1 ? i__1 : s_rnge( "r", i__1, "m2eul_", (ftnlen)667)], &tmprot[(i__2 = i__ * 3 - 3) < 9 && 0 <= i__2 ? i__2 : s_rnge("tmprot", i__2, "m2eul_", (ftnlen)667)]); } /* We now proceed to recover the promised Euler angles from */ /* TMPROT. */ /* The ideas behind our method are explained in excruciating */ /* detail in the ROTATION required reading, so we'll be terse. */ /* Nonetheless, a word of explanation is in order. */ /* The sequence of rotation axes used for the factorization */ /* belongs to one of two categories: a-b-a or c-b-a. We */ /* wish to handle each of these cases in one shot, rather than */ /* using different formulas for each sequence to recover the */ /* Euler angles. */ /* What we're going to do is use the Euler angle formula for the */ /* 3-1-3 factorization for all of the a-b-a sequences, and the */ /* formula for the 3-2-1 factorization for all of the c-b-a */ /* sequences. */ /* How can we get away with this? The Euler angle formulas for */ /* each factorization are different! */ /* Our trick is to apply a change-of-basis transformation to the */ /* input matrix R. For the a-b-a factorizations, we choose a new */ /* basis such that a rotation of ANGLE3 radians about the basis */ /* vector indexed by AXIS3 becomes a rotation of ANGLE3 radians */ /* about the third coordinate axis, and such that a rotation of */ /* ANGLE2 radians about the basis vector indexed by AXIS2 becomes */ /* a rotation of ANGLE2 radians about the first coordinate axis. */ /* So R can be factored as a 3-1-3 rotation relative to the new */ /* basis, and the Euler angles we obtain are the exact ones we */ /* require. */ /* The c-b-a factorizations can be handled in an analogous */ /* fashion. We transform R to a basis where the original axis */ /* sequence becomes a 3-2-1 sequence. In some cases, the angles */ /* we obtain will be the negatives of the angles we require. This */ /* will happen if and only if the ordered basis (here the e's are */ /* the standard basis vectors) */ /* { e e e } */ /* AXIS3 AXIS2 AXIS1 */ /* is not right-handed. An easy test for this condition is that */ /* AXIS2 is not the successor of AXIS3, where the ordering is */ /* cyclic. */ if (*axis3 == *axis1) { /* The axis order is a-b-a. We're going to find a matrix CHANGE */ /* such that */ /* T */ /* CHANGE R CHANGE */ /* gives us R in the a useful basis, that is, a basis in which */ /* our original a-b-a rotation is a 3-1-3 rotation, but where the */ /* rotation angles are unchanged. To achieve this pleasant */ /* simplification, we set column 3 of CHANGE to to e(AXIS3), */ /* column 1 of CHANGE to e(AXIS2), and column 2 of CHANGE to */ /* (+/-) e(C), */ /* (C is the remaining index) depending on whether */ /* AXIS3-AXIS2-C is a right-handed sequence of axes: if it */ /* is, the sign is positive. (Here e(1), e(2), e(3) are the */ /* standard basis vectors.) */ /* Determine the sign of our third basis vector, so that we can */ /* ensure that our new basis is right-handed. The variable NEXT */ /* is just a little mapping that takes 1 to 2, 2 to 3, and 3 to */ /* 1. */ if (*axis2 == next[(i__1 = *axis3 - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("next", i__1, "m2eul_", (ftnlen)746)]) { sign = 1.; } else { sign = -1.; } /* Since the axis indices sum to 6, */ c__ = 6 - *axis3 - *axis2; /* Set up the entries of CHANGE: */ cleard_(&c__9, change); change[(i__1 = *axis3 + 5) < 9 && 0 <= i__1 ? i__1 : s_rnge("change", i__1, "m2eul_", (ftnlen)762)] = 1.; change[(i__1 = *axis2 - 1) < 9 && 0 <= i__1 ? i__1 : s_rnge("change", i__1, "m2eul_", (ftnlen)763)] = 1.; change[(i__1 = c__ + 2) < 9 && 0 <= i__1 ? i__1 : s_rnge("change", i__1, "m2eul_", (ftnlen)764)] = sign * 1.; /* Transform TMPROT. */ mxm_(tmprot, change, tmpmat); mtxm_(change, tmpmat, tmprot); /* Now we're ready to find the Euler angles, using a */ /* 3-1-3 factorization. In general, the matrix product */ /* [ a1 ] [ a2 ] [ a3 ] */ /* 3 1 3 */ /* has the form */ /* +- -+ */ /* | cos(a1)cos(a3) cos(a1)sin(a3) sin(a1)sin(a2) | */ /* | -sin(a1)cos(a2)sin(a3) +sin(a1)cos(a2)cos(a3) | */ /* | | */ /* | -sin(a1)cos(a3) -sin(a1)sin(a3) cos(a1)sin(a2) | */ /* | -cos(a1)cos(a2)sin(a3) +cos(a1)cos(a2)cos(a3) | */ /* | | */ /* | sin(a2)sin(a3) -sin(a2)cos(a3) cos(a2) | */ /* +- -+ */ /* but if a2 is 0 or pi, the product matrix reduces to */ /* +- -+ */ /* | cos(a1)cos(a3) cos(a1)sin(a3) 0 | */ /* | -sin(a1)cos(a2)sin(a3) +sin(a1)cos(a2)cos(a3) | */ /* | | */ /* | -sin(a1)cos(a3) -sin(a1)sin(a3) 0 | */ /* | -cos(a1)cos(a2)sin(a3) +cos(a1)cos(a2)cos(a3) | */ /* | | */ /* | 0 0 cos(a2) | */ /* +- -+ */ /* In this case, a1 and a3 are not uniquely determined. If we */ /* arbitrarily set a1 to zero, we arrive at the matrix */ /* +- -+ */ /* | cos(a3) sin(a3) 0 | */ /* | -cos(a2)sin(a3) cos(a2)cos(a3) 0 | */ /* | 0 0 cos(a2) | */ /* +- -+ */ /* We take care of this case first. We test three conditions */ /* that are mathematically equivalent, but may not be satisfied */ /* simultaneously because of round-off: */ degen = tmprot[6] == 0. && tmprot[7] == 0. || tmprot[2] == 0. && tmprot[5] == 0. || abs(tmprot[8]) == 1.; /* In the following block of code, we make use of the fact that */ /* SIN ( ANGLE2 ) > 0 */ /* - */ /* in choosing the signs of the ATAN2 arguments correctly. Note */ /* that ATAN2(x,y) = -ATAN2(-x,-y). */ if (degen) { *angle3 = 0.; *angle2 = acos(tmprot[8]); *angle1 = atan2(tmprot[3], tmprot[0]); } else { /* The normal case. */ *angle3 = atan2(tmprot[6], tmprot[7]); *angle2 = acos(tmprot[8]); *angle1 = atan2(tmprot[2], -tmprot[5]); } } else { /* The axis order is c-b-a. We're going to find a matrix CHANGE */ /* such that */ /* T */ /* CHANGE R CHANGE */ /* gives us R in the a useful basis, that is, a basis in which */ /* our original c-b-a rotation is a 3-2-1 rotation, but where the */ /* rotation angles are unchanged, or at worst negated. To */ /* achieve this pleasant simplification, we set column 1 of */ /* CHANGE to to e(AXIS3), column 2 of CHANGE to e(AXIS2), and */ /* column 3 of CHANGE to */ /* (+/-) e(AXIS1), */ /* depending on whether AXIS3-AXIS2-AXIS1 is a right-handed */ /* sequence of axes: if it is, the sign is positive. (Here */ /* e(1), e(2), e(3) are the standard basis vectors.) */ /* We must be cautious here, because if AXIS3-AXIS2-AXIS1 is a */ /* right-handed sequence of axes, all of the rotation angles will */ /* be the same in our new basis, but if it's a left-handed */ /* sequence, the third angle will be negated. Let's get this */ /* straightened out right now. The variable NEXT is just a */ /* little mapping that takes 1 to 2, 2 to 3, and 3 to 1. */ if (*axis2 == next[(i__1 = *axis3 - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("next", i__1, "m2eul_", (ftnlen)883)]) { sign = 1.; } else { sign = -1.; } /* Set up the entries of CHANGE: */ cleard_(&c__9, change); change[(i__1 = *axis3 - 1) < 9 && 0 <= i__1 ? i__1 : s_rnge("change", i__1, "m2eul_", (ftnlen)894)] = 1.; change[(i__1 = *axis2 + 2) < 9 && 0 <= i__1 ? i__1 : s_rnge("change", i__1, "m2eul_", (ftnlen)895)] = 1.; change[(i__1 = *axis1 + 5) < 9 && 0 <= i__1 ? i__1 : s_rnge("change", i__1, "m2eul_", (ftnlen)896)] = sign * 1.; /* Transform TMPROT. */ mxm_(tmprot, change, tmpmat); mtxm_(change, tmpmat, tmprot); /* Now we're ready to find the Euler angles, using a */ /* 3-2-1 factorization. In general, the matrix product */ /* [ a1 ] [ a2 ] [ a3 ] */ /* 1 2 3 */ /* has the form */ /* +- -+ */ /* | cos(a2)cos(a3) cos(a2)sin(a3) -sin(a2) | */ /* | | */ /* | -cos(a1)sin(a3) cos(a1)cos(a3) sin(a1)cos(a2) | */ /* | +sin(a1)sin(a2)cos(a3) +sin(a1)sin(a2)sin(a3) | */ /* | | */ /* | sin(a1)sin(a3) -sin(a1)cos(a3) cos(a1)cos(a2) | */ /* | +cos(a1)sin(a2)cos(a3) +cos(a1)sin(a2)sin(a3) | */ /* +- -+ */ /* but if a2 is -pi/2 or pi/2, the product matrix reduces to */ /* +- -+ */ /* | 0 0 -sin(a2) | */ /* | | */ /* | -cos(a1)sin(a3) cos(a1)cos(a3) 0 | */ /* | +sin(a1)sin(a2)cos(a3) +sin(a1)sin(a2)sin(a3) | */ /* | | */ /* | sin(a1)sin(a3) -sin(a1)cos(a3) 0 | */ /* | +cos(a1)sin(a2)cos(a3) +cos(a1)sin(a2)sin(a3) | */ /* +- -+ */ /* In this case, a1 and a3 are not uniquely determined. If we */ /* arbitrarily set a1 to zero, we arrive at the matrix */ /* +- -+ */ /* | 0 0 -sin(a2) | */ /* | -sin(a3) cos(a3) 0 |, */ /* | sin(a2)cos(a3) sin(a2)sin(a3) 0 | */ /* +- -+ */ /* We take care of this case first. We test three conditions */ /* that are mathematically equivalent, but may not be satisfied */ /* simultaneously because of round-off: */ degen = tmprot[0] == 0. && tmprot[3] == 0. || tmprot[7] == 0. && tmprot[8] == 0. || abs(tmprot[6]) == 1.; /* In the following block of code, we make use of the fact that */ /* COS ( ANGLE2 ) > 0 */ /* - */ /* in choosing the signs of the ATAN2 arguments correctly. Note */ /* that ATAN2(x,y) = -ATAN2(-x,-y). */ if (degen) { *angle3 = 0.; *angle2 = asin(-tmprot[6]); *angle1 = sign * atan2(-tmprot[1], tmprot[4]); } else { /* The normal case. */ *angle3 = atan2(tmprot[7], tmprot[8]); *angle2 = asin(-tmprot[6]); *angle1 = sign * atan2(tmprot[3], tmprot[0]); } } chkout_("M2EUL", (ftnlen)5); return 0; } /* m2eul_ */
/* $Procedure STELAB ( Stellar Aberration ) */ /* Subroutine */ int stelab_(doublereal *pobj, doublereal *vobs, doublereal * appobj) { /* Builtin functions */ double asin(doublereal); /* Local variables */ extern /* Subroutine */ int vhat_(doublereal *, doublereal *); doublereal vbyc[3]; extern /* Subroutine */ int vscl_(doublereal *, doublereal *, doublereal * ); extern doublereal vdot_(doublereal *, doublereal *); doublereal h__[3], u[3]; extern /* Subroutine */ int chkin_(char *, ftnlen), moved_(doublereal *, integer *, doublereal *), errdp_(char *, doublereal *, ftnlen), vcrss_(doublereal *, doublereal *, doublereal *); extern doublereal vnorm_(doublereal *); extern /* Subroutine */ int vrotv_(doublereal *, doublereal *, doublereal *, doublereal *); extern doublereal clight_(void); doublereal onebyc, sinphi; extern /* Subroutine */ int sigerr_(char *, ftnlen), chkout_(char *, ftnlen), setmsg_(char *, ftnlen); doublereal lensqr; extern logical return_(void); doublereal phi; /* $ Abstract */ /* Correct the apparent position of an object for stellar */ /* aberration. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* None. */ /* $ Keywords */ /* EPHEMERIS */ /* $ Declarations */ /* $ Brief_I/O */ /* VARIABLE I/O DESCRIPTION */ /* -------- --- -------------------------------------------------- */ /* POBJ I Position of an object with respect to the */ /* observer. */ /* VOBS I Velocity of the observer with respect to the */ /* Solar System barycenter. */ /* APPOBJ O Apparent position of the object with respect to */ /* the observer, corrected for stellar aberration. */ /* $ Detailed_Input */ /* POBJ is the position (x, y, z, km) of an object with */ /* respect to the observer, possibly corrected for */ /* light time. */ /* VOBS is the velocity (dx/dt, dy/dt, dz/dt, km/sec) */ /* of the observer with respect to the Solar System */ /* barycenter. */ /* $ Detailed_Output */ /* APPOBJ is the apparent position of the object relative */ /* to the observer, corrected for stellar aberration. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If the velocity of the observer is greater than or equal */ /* to the speed of light, the error SPICE(VALUEOUTOFRANGE) */ /* is signaled. */ /* $ Files */ /* None. */ /* $ Particulars */ /* Let r be the vector from the observer to the object, and v be */ /* - - */ /* the velocity of the observer with respect to the Solar System */ /* barycenter. Let w be the angle between them. The aberration */ /* angle phi is given by */ /* sin(phi) = v sin(w) / c */ /* Let h be the vector given by the cross product */ /* - */ /* h = r X v */ /* - - - */ /* Rotate r by phi radians about h to obtain the apparent position */ /* - - */ /* of the object. */ /* $ Examples */ /* In the following example, STELAB is used to correct the position */ /* of a target body for stellar aberration. */ /* (Previous subroutine calls have loaded the SPK file and */ /* the leapseconds kernel file.) */ /* C */ /* C Get the geometric state of the observer OBS relative to */ /* C the solar system barycenter. */ /* C */ /* CALL SPKSSB ( OBS, ET, 'J2000', SOBS ) */ /* C */ /* C Get the light-time corrected position TPOS of the target */ /* C body TARG as seen by the observer. Normally we would */ /* C call SPKPOS to obtain this vector, but we already have */ /* C the state of the observer relative to the solar system */ /* C barycenter, so we can avoid looking up that state twice */ /* C by calling SPKAPO. */ /* C */ /* CALL SPKAPO ( TARG, ET, 'J2000', SOBS, 'LT', TPOS, LT ) */ /* C */ /* C Apply the correction for stellar aberration to the */ /* C light-time corrected position of the target body. */ /* C The corrected position is returned in the argument */ /* C PCORR. */ /* C */ /* CALL STELAB ( TPOS, SOBS(4), PCORR ) */ /* Note that this example is somewhat contrived. The sequence */ /* of calls above could be replaced by a single call to SPKEZP, */ /* using the aberration correction flag 'LT+S'. */ /* For more information on aberration-corrected states or */ /* positions, see the headers of any of the routines */ /* SPKEZR */ /* SPKEZ */ /* SPKPOS */ /* SPKEZP */ /* $ Restrictions */ /* None. */ /* $ Literature_References */ /* 1) W.M. Owen, Jr., JPL IOM #314.8-524, "The Treatment of */ /* Aberration in Optical Navigation", 8 February 1985. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* H.A. Neilan (JPL) */ /* W.L. Taber (JPL) */ /* I.M. Underwood (JPL) */ /* $ Version */ /* - SPICELIB Version 1.1.1, 8-JAN-2008 (NJB) */ /* The header example was updated to remove references */ /* to SPKAPP. */ /* - SPICELIB Version 1.1.0, 8-FEB-1999 (WLT) */ /* The example was corrected so that SOBS(4) is passed */ /* into STELAB instead of STARG(4). */ /* - SPICELIB Version 1.0.2, 10-MAR-1992 (WLT) */ /* Comment section for permuted index source lines was added */ /* following the header. */ /* - SPICELIB Version 1.0.1, 8-AUG-1990 (HAN) */ /* Examples section of the header was updated to replace */ /* calls to the GEF ephemeris readers by calls to the */ /* new SPK ephemeris reader. */ /* - SPICELIB Version 1.0.0, 31-JAN-1990 (IMU) (WLT) */ /* -& */ /* $ Index_Entries */ /* stellar aberration */ /* -& */ /* $ Revisions */ /* - Beta Version 2.1.0, 9-MAR-1989 (HAN) */ /* Declaration of the variable LIGHT was removed from the code. */ /* The variable was declared but never used. */ /* - Beta Version 2.0.0, 28-DEC-1988 (HAN) */ /* Error handling was added to check the velocity of the */ /* observer. If the velocity of the observer is greater */ /* than or equal to the speed of light, the error */ /* SPICE(VALUEOUTOFRANGE) is signalled. */ /* -& */ /* SPICELIB functions */ /* Local variables */ /* Standard SPICE error handling. */ if (return_()) { return 0; } else { chkin_("STELAB", (ftnlen)6); } /* We are not going to compute the aberrated vector in exactly the */ /* way described in the particulars section. We can combine some */ /* steps and we take some precautions to prevent floating point */ /* overflows. */ /* Get a unit vector that points in the direction of the object */ /* ( u_obj ). */ vhat_(pobj, u); /* Get the velocity vector scaled with respect to the speed of light */ /* ( v/c ). */ onebyc = 1. / clight_(); vscl_(&onebyc, vobs, vbyc); /* If the square of the length of the velocity vector is greater than */ /* or equal to one, the speed of the observer is greater than or */ /* equal to the speed of light. The observer speed is definitely out */ /* of range. Signal an error and check out. */ lensqr = vdot_(vbyc, vbyc); if (lensqr >= 1.) { setmsg_("Velocity components of observer were: dx/dt = *, dy/dt = *" ", dz/dt = *.", (ftnlen)71); errdp_("*", vobs, (ftnlen)1); errdp_("*", &vobs[1], (ftnlen)1); errdp_("*", &vobs[2], (ftnlen)1); sigerr_("SPICE(VALUEOUTOFRANGE)", (ftnlen)22); chkout_("STELAB", (ftnlen)6); return 0; } /* Compute u_obj x (v/c) */ vcrss_(u, vbyc, h__); /* If the magnitude of the vector H is zero, the observer is moving */ /* along the line of sight to the object, and no correction is */ /* required. Otherwise, rotate the position of the object by phi */ /* radians about H to obtain the apparent position. */ sinphi = vnorm_(h__); if (sinphi != 0.) { phi = asin(sinphi); vrotv_(pobj, h__, &phi, appobj); } else { moved_(pobj, &c__3, appobj); } chkout_("STELAB", (ftnlen)6); return 0; } /* stelab_ */
/* $Procedure ZZHULLAX ( Pyramidal FOV convex hull to FOV axis ) */ /* Subroutine */ int zzhullax_(char *inst, integer *n, doublereal *bounds, doublereal *axis, ftnlen inst_len) { /* System generated locals */ integer bounds_dim2, i__1, i__2; doublereal d__1; /* Builtin functions */ integer s_rnge(char *, integer, char *, integer); /* Local variables */ extern /* Subroutine */ int vhat_(doublereal *, doublereal *); doublereal xvec[3], yvec[3], zvec[3]; integer xidx; extern doublereal vsep_(doublereal *, doublereal *); integer next; logical pass1; integer i__, m; doublereal r__, v[3], delta; extern /* Subroutine */ int chkin_(char *, ftnlen), errch_(char *, char *, ftnlen, ftnlen); logical found; extern /* Subroutine */ int errdp_(char *, doublereal *, ftnlen), vlcom_( doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); integer minix, maxix; doublereal trans[9] /* was [3][3] */; extern /* Subroutine */ int ucrss_(doublereal *, doublereal *, doublereal *), vcrss_(doublereal *, doublereal *, doublereal *); extern logical vzero_(doublereal *); extern /* Subroutine */ int vrotv_(doublereal *, doublereal *, doublereal *, doublereal *); doublereal cp[3]; extern doublereal pi_(void); logical ok; extern doublereal halfpi_(void); extern /* Subroutine */ int reclat_(doublereal *, doublereal *, doublereal *, doublereal *), sigerr_(char *, ftnlen); doublereal minlon; extern /* Subroutine */ int chkout_(char *, ftnlen); doublereal maxlon; extern /* Subroutine */ int vhatip_(doublereal *), vsclip_(doublereal *, doublereal *), setmsg_(char *, ftnlen), errint_(char *, integer *, ftnlen); extern logical return_(void); doublereal lat, sep, lon; extern /* Subroutine */ int mxv_(doublereal *, doublereal *, doublereal *) ; doublereal ray1[3], ray2[3]; /* $ Abstract */ /* SPICE Private routine intended solely for the support of SPICE */ /* routines. Users should not call this routine directly due */ /* to the volatile nature of this routine. */ /* Identify a face of the convex hull of an instrument's */ /* polygonal FOV, and use this face to generate an axis of the */ /* FOV. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* CK */ /* FRAMES */ /* GF */ /* IK */ /* KERNEL */ /* $ Keywords */ /* FOV */ /* GEOMETRY */ /* INSTRUMENT */ /* $ Declarations */ /* $ Brief_I/O */ /* VARIABLE I/O DESCRIPTION */ /* -------- --- -------------------------------------------------- */ /* MARGIN P Minimum complement of FOV cone angle. */ /* INST I Instrument name. */ /* N I Number of FOV boundary vectors. */ /* BOUNDS I FOV boundary vectors. */ /* AXIS O Instrument FOV axis vector. */ /* $ Detailed_Input */ /* INST is the name of an instrument with which the field of */ /* view (FOV) of interest is associated. This name is */ /* used only to generate long error messages. */ /* N is the number of boundary vectors in the array */ /* BOUNDS. */ /* BOUNDS is an array of N vectors emanating from a common */ /* vertex and defining the edges of a pyramidal region in */ /* three-dimensional space: this the region within the */ /* FOV of the instrument designated by INST. The Ith */ /* vector of BOUNDS resides in elements (1:3,I) of this */ /* array. */ /* The vectors contained in BOUNDS are called the */ /* "boundary vectors" of the FOV. */ /* The boundary vectors must satisfy the constraints: */ /* 1) The boundary vectors must be contained within */ /* a right circular cone of angular radius less */ /* than than (pi/2) - MARGIN radians; in other */ /* words, there must be a vector A such that all */ /* boundary vectors have angular separation from */ /* A of less than (pi/2)-MARGIN radians. */ /* 2) There must be a pair of vectors U, V in BOUNDS */ /* such that all other boundary vectors lie in */ /* the same half space bounded by the plane */ /* containing U and V. Furthermore, all other */ /* boundary vectors must have orthogonal */ /* projections onto a plane normal to this plane */ /* such that the projections have angular */ /* separation of at least 2*MARGIN radians from */ /* the plane spanned by U and V. */ /* Given the first constraint above, there is plane PL */ /* such that each of the set of rays extending the */ /* boundary vectors intersects PL. (In fact, there is an */ /* infinite set of such planes.) The boundary vectors */ /* must be ordered so that the set of line segments */ /* connecting the intercept on PL of the ray extending */ /* the Ith vector to that of the (I+1)st, with the Nth */ /* intercept connected to the first, form a polygon (the */ /* "FOV polygon") constituting the intersection of the */ /* FOV pyramid with PL. This polygon may wrap in either */ /* the positive or negative sense about a ray emanating */ /* from the FOV vertex and passing through the plane */ /* region bounded by the FOV polygon. */ /* The FOV polygon need not be convex; it may be */ /* self-intersecting as well. */ /* No pair of consecutive vectors in BOUNDS may be */ /* linearly dependent. */ /* The boundary vectors need not have unit length. */ /* $ Detailed_Output */ /* AXIS is a unit vector normal to a plane containing the */ /* FOV polygon. All boundary vectors have angular */ /* separation from AXIS of not more than */ /* ( pi/2 ) - MARGIN */ /* radians. */ /* This routine signals an error if it cannot find */ /* a satisfactory value of AXIS. */ /* $ Parameters */ /* MARGIN is a small positive number used to constrain the */ /* orientation of the boundary vectors. See the two */ /* constraints described in the Detailed_Input section */ /* above for specifics. */ /* $ Exceptions */ /* 1) In the input vector count N is not at least 3, the error */ /* SPICE(INVALIDCOUNT) is signaled. */ /* 2) If any pair of consecutive boundary vectors has cross */ /* product zero, the error SPICE(DEGENERATECASE) is signaled. */ /* For this test, the first vector is considered the successor */ /* of the Nth. */ /* 3) If this routine can't find a face of the convex hull of */ /* the set of boundary vectors such that this face satisfies */ /* constraint (2) of the Detailed_Input section above, the */ /* error SPICE(FACENOTFOUND) is signaled. */ /* 4) If any boundary vectors have longitude too close to 0 */ /* or too close to pi radians in the face frame (see discussion */ /* of the search algorithm's steps 3 and 4 in Particulars */ /* below), the respective errors SPICE(NOTSUPPORTED) or */ /* SPICE(FOVTOOWIDE) are signaled. */ /* 5) If any boundary vectors have angular separation of more than */ /* (pi/2)-MARGIN radians from the candidate FOV axis, the */ /* error SPICE(FOVTOOWIDE) is signaled. */ /* $ Files */ /* The boundary vectors input to this routine are typically */ /* obtained from an IK file. */ /* $ Particulars */ /* Normally implementation is not discussed in SPICE headers, but we */ /* make an exception here because this routine's implementation and */ /* specification are deeply intertwined. */ /* This routine produces an "axis" for a polygonal FOV using the */ /* following approach: */ /* 1) Test pairs of consecutive FOV boundary vectors to see */ /* whether there's a pair such that the plane region bounded */ /* by these vectors is */ /* a) part of the convex hull of the set of boundary vectors */ /* b) such that all other boundary vectors have angular */ /* separation of at least MARGIN from the plane */ /* containing these vectors */ /* This search has O(N**2) run time dependency on N. */ /* If this test produces a candidate face of the convex hull, */ /* proceed to step 3. */ /* 2) If step (1) fails, repeat the search for a candidate */ /* convex hull face, but this time search over every pair of */ /* distinct boundary vectors. */ /* This search has O(N**3) run time dependency on N. */ /* If this search fails, signal an error. */ /* 3) Produce a set of basis vectors for a reference frame, */ /* which we'll call the "face frame," using as the +X axis */ /* the angle bisector of the vectors bounding the candidate */ /* face, the +Y axis the inward normal vector to this face, */ /* and the +Z axis completing a right-handed basis. */ /* 4) Transform each boundary vector, other than the two vectors */ /* defining the selected convex hull face, to the face frame */ /* and compute the vector's longitude in that frame. Find the */ /* maximum and minimum longitudes of the vectors in the face */ /* frame. */ /* If any vector's longitude is less than 2*MARGIN or greater */ /* than pi - 2*MARGIN radians, signal an error. */ /* 5) Let DELTA be the difference between pi and the maximum */ /* longitude found in step (4). Rotate the +Y axis (which */ /* points in the inward normal direction relative to the */ /* selected face) by -DELTA/2 radians about the +Z axis of */ /* the face frame. This rotation aligns the +Y axis with the */ /* central longitude of the set of boundary vectors. The */ /* resulting vector is our candidate FOV axis. */ /* 6) Check the angular separation of the candidate FOV axis */ /* against each boundary vector. If any vector has angular */ /* separation of more than (pi/2)-MARGIN radians from the */ /* axis, signal an error. */ /* Note that there are reasonable FOVs that cannot be handled by the */ /* algorithm described here. For example, any FOV whose cross */ /* section is a regular convex polygon can be made unusable by */ /* adding boundary vectors aligned with the angle bisectors of each */ /* face of the pyramid defined by the FOV's boundary vectors. The */ /* resulting set of boundary vectors has no face in its convex hull */ /* such that all other boundary vectors have positive angular */ /* separation from that face. */ /* Because of this limitation, this algorithm should be used only */ /* after a simple FOV axis-finding approach, such as using as the */ /* FOV axis the average of the boundary vectors, has been tried */ /* unsuccessfully. */ /* Note that it's easy to construct FOVs where the average of the */ /* boundary vectors doesn't yield a viable axis: a FOV of angular */ /* width nearly equal to pi radians, with a sufficiently large */ /* number of boundary vectors on one side and few boundary vectors */ /* on the other, is one such example. This routine can find an */ /* axis for many such intractable FOVs---that's why this routine */ /* should be called after the simple approach fails. */ /* $ Examples */ /* See SPICELIB private routine ZZFOVAXI. */ /* $ Restrictions */ /* 1) This is a SPICE private routine. User applications should not */ /* call this routine. */ /* 2) There are "reasonable" polygonal FOVs that cannot be handled */ /* by this routine. See the discussion in Particulars above. */ /* $ Literature_References */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* $ Version */ /* - SPICELIB 1.0.0, 05-MAR-2009 (NJB) */ /* -& */ /* $ Index_Entries */ /* Create axis vector for polygonal FOV */ /* -& */ /* SPICELIB functions */ /* Local parameters */ /* Local variables */ /* Parameter adjustments */ bounds_dim2 = *n; /* Function Body */ if (return_()) { return 0; } chkin_("ZZHULLAX", (ftnlen)8); /* Nothing found yet. */ found = FALSE_; xidx = 0; /* We must have at least 3 boundary vectors. */ if (*n < 3) { setmsg_("Polygonal FOV requires at least 3 boundary vectors but numb" "er supplied for # was #.", (ftnlen)83); errch_("#", inst, (ftnlen)1, inst_len); errint_("#", n, (ftnlen)1); sigerr_("SPICE(INVALIDCOUNT)", (ftnlen)19); chkout_("ZZHULLAX", (ftnlen)8); return 0; } /* Find an exterior face of the pyramid defined by the */ /* input boundary vectors. Since most polygonal FOVs will have */ /* an exterior face bounded by two consecutive rays, we'll */ /* try pairs of consecutive rays first. If this fails, we'll */ /* try each pair of rays. */ i__ = 1; while(i__ <= *n && ! found) { /* Set the index of the next ray. When we get to the */ /* last boundary vector, the next ray is the first. */ if (i__ == *n) { next = 1; } else { next = i__ + 1; } /* Find the cross product of the first ray with the */ /* second. Depending on the ordering of the boundary */ /* vectors, this could be an inward or outward normal, */ /* in the case the current face is exterior. */ vcrss_(&bounds[(i__1 = i__ * 3 - 3) < bounds_dim2 * 3 && 0 <= i__1 ? i__1 : s_rnge("bounds", i__1, "zzhullax_", (ftnlen)408)], & bounds[(i__2 = next * 3 - 3) < bounds_dim2 * 3 && 0 <= i__2 ? i__2 : s_rnge("bounds", i__2, "zzhullax_", (ftnlen)408)], cp); /* We insist on consecutive boundary vectors being */ /* linearly independent. */ if (vzero_(cp)) { setmsg_("Polygonal FOV must have linearly independent consecutiv" "e boundary but vectors at indices # and # have cross pro" "duct equal to the zero vector. Instrument is #.", (ftnlen) 158); errint_("#", &i__, (ftnlen)1); errint_("#", &next, (ftnlen)1); errch_("#", inst, (ftnlen)1, inst_len); sigerr_("SPICE(DEGENERATECASE)", (ftnlen)21); chkout_("ZZHULLAX", (ftnlen)8); return 0; } /* See whether the other boundary vectors have angular */ /* separation of at least MARGIN from the plane containing */ /* the current face. */ pass1 = TRUE_; ok = TRUE_; m = 1; while(m <= *n && ok) { /* Find the angular separation of CP and the Mth vector if the */ /* latter is not an edge of the current face. */ if (m != i__ && m != next) { sep = vsep_(cp, &bounds[(i__1 = m * 3 - 3) < bounds_dim2 * 3 && 0 <= i__1 ? i__1 : s_rnge("bounds", i__1, "zzhull" "ax_", (ftnlen)446)]); if (pass1) { /* Adjust CP if necessary so that it points */ /* toward the interior of the pyramid. */ if (sep > halfpi_()) { /* Invert the cross product vector and adjust SEP */ /* accordingly. Within this "M" loop, all other */ /* angular separations will be computed using the new */ /* value of CP. */ vsclip_(&c_b20, cp); sep = pi_() - sep; } pass1 = FALSE_; } ok = sep < halfpi_() - 1e-12; } if (ok) { /* Consider the next boundary vector. */ ++m; } } /* We've tested each boundary vector against the current face, or */ /* else the loop terminated early because a vector with */ /* insufficient angular separation from the plane containing the */ /* face was found. */ if (ok) { /* The current face is exterior. It's bounded by rays I and */ /* NEXT. */ xidx = i__; found = TRUE_; } else { /* Look at the next face of the pyramid. */ ++i__; } } /* If we didn't find an exterior face, we'll have to look at each */ /* face bounded by a pair of rays, even if those rays are not */ /* adjacent. (This can be a very slow process is N is large.) */ if (! found) { i__ = 1; while(i__ <= *n && ! found) { /* Consider all ray pairs (I,NEXT) where NEXT > I. */ next = i__ + 1; while(next <= *n && ! found) { /* Find the cross product of the first ray with the second. */ /* If the current face is exterior, CP could be an inward */ /* or outward normal, depending on the ordering of the */ /* boundary vectors. */ vcrss_(&bounds[(i__1 = i__ * 3 - 3) < bounds_dim2 * 3 && 0 <= i__1 ? i__1 : s_rnge("bounds", i__1, "zzhullax_", ( ftnlen)530)], &bounds[(i__2 = next * 3 - 3) < bounds_dim2 * 3 && 0 <= i__2 ? i__2 : s_rnge("bounds", i__2, "zzhullax_", (ftnlen)530)], cp); /* It's allowable for non-consecutive boundary vectors to */ /* be linearly dependent, but if we have such a pair, */ /* it doesn't define an exterior face. */ if (! vzero_(cp)) { /* The rays having direction vectors indexed I and NEXT */ /* define a semi-infinite sector of a plane that might */ /* be of interest. */ /* Check whether all of the boundary vectors that are */ /* not edges of the current face have angular separation */ /* of at least MARGIN from the plane containing the */ /* current face. */ pass1 = TRUE_; ok = TRUE_; m = 1; while(m <= *n && ok) { /* Find the angular separation of CP and the Mth */ /* vector if the latter is not an edge of the current */ /* face. */ if (m != i__ && m != next) { sep = vsep_(cp, &bounds[(i__1 = m * 3 - 3) < bounds_dim2 * 3 && 0 <= i__1 ? i__1 : s_rnge("bounds", i__1, "zzhullax_", ( ftnlen)560)]); if (pass1) { /* Adjust CP if necessary so that it points */ /* toward the interior of the pyramid. */ if (sep > halfpi_()) { /* Invert the cross product vector and */ /* adjust SEP accordingly. Within this "M" */ /* loop, all other angular separations will */ /* be computed using the new value of CP. */ vsclip_(&c_b20, cp); sep = pi_() - sep; } pass1 = FALSE_; } ok = sep < halfpi_() - 1e-12; } if (ok) { /* Consider the next boundary vector. */ ++m; } } /* We've tested each boundary vector against the current */ /* face, or else the loop terminated early because a */ /* vector with insufficient angular separation from the */ /* plane containing the face was found. */ if (ok) { /* The current face is exterior. It's bounded by rays */ /* I and NEXT. */ xidx = i__; found = TRUE_; } /* End of angular separation test block. */ } /* End of non-zero cross product block. */ if (! found) { /* Look at the face bounded by the rays */ /* at indices I and NEXT+1. */ ++next; } } /* End of NEXT loop. */ if (! found) { /* Look at the face bounded by the pairs of rays */ /* including the ray at index I+1. */ ++i__; } } /* End of I loop. */ } /* End of search for exterior face using each pair of rays. */ /* If we still haven't found an exterior face, we can't continue. */ if (! found) { setmsg_("Unable to find face of convex hull of FOV of instrument #.", (ftnlen)58); errch_("#", inst, (ftnlen)1, inst_len); sigerr_("SPICE(FACENOTFOUND)", (ftnlen)19); chkout_("ZZHULLAX", (ftnlen)8); return 0; } /* Arrival at this point means that the rays at indices */ /* XIDX and NEXT define a plane such that all boundary */ /* vectors lie in a half-space bounded by that plane. */ /* We're now going to define a set of orthonormal basis vectors: */ /* +X points along the angle bisector of the bounding vectors */ /* of the exterior face. */ /* +Y points along CP. */ /* +Z is the cross product of +X and +Y. */ /* We'll call the reference frame having these basis vectors */ /* the "face frame." */ vhat_(&bounds[(i__1 = i__ * 3 - 3) < bounds_dim2 * 3 && 0 <= i__1 ? i__1 : s_rnge("bounds", i__1, "zzhullax_", (ftnlen)683)], ray1); vhat_(&bounds[(i__1 = next * 3 - 3) < bounds_dim2 * 3 && 0 <= i__1 ? i__1 : s_rnge("bounds", i__1, "zzhullax_", (ftnlen)684)], ray2); vlcom_(&c_b36, ray1, &c_b36, ray2, xvec); vhatip_(xvec); vhat_(cp, yvec); ucrss_(xvec, yvec, zvec); /* Create a transformation matrix to map the input boundary */ /* vectors into the face frame. */ for (i__ = 1; i__ <= 3; ++i__) { trans[(i__1 = i__ * 3 - 3) < 9 && 0 <= i__1 ? i__1 : s_rnge("trans", i__1, "zzhullax_", (ftnlen)698)] = xvec[(i__2 = i__ - 1) < 3 && 0 <= i__2 ? i__2 : s_rnge("xvec", i__2, "zzhullax_", ( ftnlen)698)]; trans[(i__1 = i__ * 3 - 2) < 9 && 0 <= i__1 ? i__1 : s_rnge("trans", i__1, "zzhullax_", (ftnlen)699)] = yvec[(i__2 = i__ - 1) < 3 && 0 <= i__2 ? i__2 : s_rnge("yvec", i__2, "zzhullax_", ( ftnlen)699)]; trans[(i__1 = i__ * 3 - 1) < 9 && 0 <= i__1 ? i__1 : s_rnge("trans", i__1, "zzhullax_", (ftnlen)700)] = zvec[(i__2 = i__ - 1) < 3 && 0 <= i__2 ? i__2 : s_rnge("zvec", i__2, "zzhullax_", ( ftnlen)700)]; } /* Now we're going to compute the longitude of each boundary in the */ /* face frame. The vectors with indices XIDX and NEXT are excluded. */ /* We expect all longitudes to be between MARGIN and pi - MARGIN. */ minlon = pi_(); maxlon = 0.; minix = 1; maxix = 1; i__1 = *n; for (i__ = 1; i__ <= i__1; ++i__) { if (i__ != xidx && i__ != next) { /* The current vector is not a boundary of our edge, */ /* so find its longitude. */ mxv_(trans, &bounds[(i__2 = i__ * 3 - 3) < bounds_dim2 * 3 && 0 <= i__2 ? i__2 : s_rnge("bounds", i__2, "zzhullax_", ( ftnlen)720)], v); reclat_(v, &r__, &lon, &lat); /* Update the longitude bounds. */ if (lon < minlon) { minix = i__; minlon = lon; } if (lon > maxlon) { maxix = i__; maxlon = lon; } } } /* If the longitude bounds are not as expected, don't try */ /* to continue. */ if (minlon < 2e-12) { setmsg_("Minimum boundary vector longitude in exterior face frame is" " # radians. Minimum occurs at index #. This FOV does not con" "form to the requirements of this routine. Instrument is #.", ( ftnlen)177); errdp_("#", &minlon, (ftnlen)1); errint_("#", &minix, (ftnlen)1); errch_("#", inst, (ftnlen)1, inst_len); sigerr_("SPICE(NOTSUPPORTED)", (ftnlen)19); chkout_("ZZHULLAX", (ftnlen)8); return 0; } else if (maxlon > pi_() - 2e-12) { setmsg_("Maximum boundary vector longitude in exterior face frame is" " # radians. Maximum occurs at index #. This FOV does not con" "form to the requirements of this routine. Instrument is #.", ( ftnlen)177); errdp_("#", &maxlon, (ftnlen)1); errint_("#", &maxix, (ftnlen)1); errch_("#", inst, (ftnlen)1, inst_len); sigerr_("SPICE(FOVTOOWIDE)", (ftnlen)17); chkout_("ZZHULLAX", (ftnlen)8); return 0; } /* Let delta represent the amount we can rotate the exterior */ /* face clockwise about +Z without contacting another boundary */ /* vector. */ delta = pi_() - maxlon; /* Rotate +Y by -DELTA/2 about +Z. The result is our candidate */ /* FOV axis. Make the axis vector unit length. */ d__1 = -delta / 2; vrotv_(yvec, zvec, &d__1, axis); vhatip_(axis); /* If we have a viable result, ALL boundary vectors have */ /* angular separation less than HALFPI-MARGIN from AXIS. */ i__1 = *n; for (i__ = 1; i__ <= i__1; ++i__) { sep = vsep_(&bounds[(i__2 = i__ * 3 - 3) < bounds_dim2 * 3 && 0 <= i__2 ? i__2 : s_rnge("bounds", i__2, "zzhullax_", (ftnlen)794) ], axis); if (sep > halfpi_() - 1e-12) { setmsg_("Boundary vector at index # has angular separation of # " "radians from candidate FOV axis. This FOV does not confo" "rm to the requirements of this routine. Instrument is #.", (ftnlen)167); errint_("#", &i__, (ftnlen)1); errdp_("#", &sep, (ftnlen)1); errch_("#", inst, (ftnlen)1, inst_len); sigerr_("SPICE(FOVTOOWIDE)", (ftnlen)17); chkout_("ZZHULLAX", (ftnlen)8); return 0; } } chkout_("ZZHULLAX", (ftnlen)8); return 0; } /* zzhullax_ */
/* $Procedure VROTV ( Vector rotation about an axis ) */ /* Subroutine */ int vrotv_(doublereal *v, doublereal *axis, doublereal * theta, doublereal *r__) { /* Builtin functions */ double cos(doublereal), sin(doublereal); /* Local variables */ extern /* Subroutine */ int vadd_(doublereal *, doublereal *, doublereal * ), vhat_(doublereal *, doublereal *), vsub_(doublereal *, doublereal *, doublereal *); doublereal c__, p[3], s, x[3]; extern /* Subroutine */ int moved_(doublereal *, integer *, doublereal *), vlcom_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *), vproj_(doublereal *, doublereal *, doublereal *); extern doublereal vnorm_(doublereal *); extern /* Subroutine */ int vcrss_(doublereal *, doublereal *, doublereal *); doublereal v1[3], v2[3], rplane[3]; /* $ Abstract */ /* Rotate a vector about a specified axis vector by a specified */ /* angle and return the rotated vector. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* ROTATION */ /* $ Keywords */ /* ROTATION, VECTOR */ /* $ Declarations */ /* $ Brief_I/O */ /* VARIABLE I/O DESCRIPTION */ /* -------- --- -------------------------------------------------- */ /* V I Vector to be rotated. */ /* AXIS I Axis of the rotation. */ /* THETA I Angle of rotation (radians). */ /* R O Result of rotating V about AXIS by THETA. */ /* $ Detailed_Input */ /* V is a 3-dimensional vector to be rotated. */ /* AXIS is the axis about which the rotation is to be */ /* performed. */ /* THETA is the angle through which V is to be rotated about */ /* AXIS. */ /* $ Detailed_Output */ /* R is the result of rotating V about AXIS by THETA. */ /* If AXIS is the zero vector, R = V. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* Error free. */ /* 1) If the input axis is the zero vector R will be returned */ /* as V. */ /* $ Files */ /* None. */ /* $ Particulars */ /* This routine computes the result of rotating (in a right handed */ /* sense) the vector V about the axis represented by AXIS through */ /* an angle of THETA radians. */ /* If W is a unit vector parallel to AXIS, then R is given by: */ /* R = V + ( 1 - cos(THETA) ) Wx(WxV) + sin(THETA) (WxV) */ /* where "x" above denotes the vector cross product. */ /* $ Examples */ /* If AXIS = ( 0, 0, 1 ) and THETA = PI/2 then the following results */ /* for R will be obtained */ /* V R */ /* ------------- ---------------- */ /* ( 1, 2, 3 ) ( -2, 1, 3 ) */ /* ( 1, 0, 0 ) ( 0, 1, 0 ) */ /* ( 0, 1, 0 ) ( -1, 0, 0 ) */ /* If AXIS = ( 0, 1, 0 ) and THETA = PI/2 then the following results */ /* for R will be obtained */ /* V R */ /* ------------- ---------------- */ /* ( 1, 2, 3 ) ( 3, 2, -1 ) */ /* ( 1, 0, 0 ) ( 0, 0, -1 ) */ /* ( 0, 1, 0 ) ( 0, 1, 0 ) */ /* If AXIS = ( 1, 1, 1 ) and THETA = PI/2 then the following results */ /* for R will be obtained */ /* V R */ /* ----------------------------- ----------------------------- */ /* ( 1.0, 2.0, 3.0 ) ( 2.577.., 0.845.., 2.577.. ) */ /* ( 2.577.., 0.845.., 2.577.. ) ( 3.0 2.0, 1.0 ) */ /* ( 3.0 2.0, 1.0 ) ( 1.422.., 3.154.., 1.422.. ) */ /* ( 1.422.., 3.154.., 1.422.. ) ( 1.0 2.0, 3.0 ) */ /* $ Restrictions */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* H.A. Neilan (JPL) */ /* W.L. Taber (JPL) */ /* $ Literature_References */ /* None. */ /* $ Version */ /* - SPICELIB Version 1.0.2, 5-FEB-2003 (NJB) */ /* Header examples were corrected. Exceptions section */ /* filled in. Miscellaneous header corrections were made. */ /* - SPICELIB Version 1.0.1, 10-MAR-1992 (WLT) */ /* Comment section for permuted index source lines was added */ /* following the header. */ /* - SPICELIB Version 1.0.0, 31-JAN-1990 (WLT) */ /* -& */ /* $ Index_Entries */ /* vector rotation about an axis */ /* -& */ /* $ Revisions */ /* - Beta Version 1.1.0, 17-FEB-1989 (HAN) (NJB) */ /* Contents of the Exceptions section was changed */ /* to "error free" to reflect the decision that the */ /* module will never participate in error handling. */ /* Also, the declarations of the unused variable I and the */ /* unused function VDOT were removed. */ /* -& */ /* SPICELIB functions */ /* Local Variables */ /* Just in case the user tries to rotate about the zero vector - */ /* check, and if so return the input vector */ if (vnorm_(axis) == 0.) { moved_(v, &c__3, r__); return 0; } /* Compute the unit vector that lies in the direction of the */ /* AXIS. Call it X. */ vhat_(axis, x); /* Compute the projection of V onto AXIS. Call it P. */ vproj_(v, x, p); /* Compute the component of V orthogonal to the AXIS. Call it V1. */ vsub_(v, p, v1); /* Rotate V1 by 90 degrees about the AXIS and call the result V2. */ vcrss_(x, v1, v2); /* Compute COS(THETA)*V1 + SIN(THETA)*V2. This is V1 rotated about */ /* the AXIS in the plane normal to the axis, call the result RPLANE */ c__ = cos(*theta); s = sin(*theta); vlcom_(&c__, v1, &s, v2, rplane); /* Add the rotated component in the normal plane to AXIS to the */ /* projection of V onto AXIS (P) to obtain R. */ vadd_(rplane, p, r__); return 0; } /* vrotv_ */
/* $Procedure TWOVEC ( Two vectors defining an orthonormal frame ) */ /* Subroutine */ int twovec_(doublereal *axdef, integer *indexa, doublereal * plndef, integer *indexp, doublereal *mout) { /* Initialized data */ static integer seqnce[5] = { 1,2,3,1,2 }; /* System generated locals */ integer i__1, i__2, i__3; /* Builtin functions */ integer s_rnge(char *, integer, char *, integer); /* Local variables */ extern /* Subroutine */ int vhat_(doublereal *, doublereal *), chkin_( char *, ftnlen), moved_(doublereal *, integer *, doublereal *); doublereal mtemp[9] /* was [3][3] */; integer i1, i2, i3; extern /* Subroutine */ int xpose_(doublereal *, doublereal *), ucrss_( doublereal *, doublereal *, doublereal *), sigerr_(char *, ftnlen) , chkout_(char *, ftnlen), setmsg_(char *, ftnlen), errint_(char * , integer *, ftnlen); extern logical return_(void); /* $ Abstract */ /* Find the transformation to the right-handed frame having a */ /* given vector as a specified axis and having a second given */ /* vector lying in a specified coordinate plane. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* None. */ /* $ Keywords */ /* AXES, FRAME, ROTATION, TRANSFORMATION */ /* $ Declarations */ /* $ Brief_I/O */ /* VARIABLE I/O DESCRIPTION */ /* -------- --- ------------------------------------------------- */ /* AXDEF I Vector defining a principal axis. */ /* INDEXA I Principal axis number of AXDEF (X=1, Y=2, Z=3). */ /* PLNDEF I Vector defining (with AXDEF) a principal plane. */ /* INDEXP I Second axis number (with INDEXA) of principal */ /* plane. */ /* MOUT O Output rotation matrix. */ /* $ Detailed_Input */ /* AXDEF is a vector defining one of the priciple axes of a */ /* coordinate frame. */ /* INDEXA is a number that determines which of the three */ /* coordinate axes contains AXDEF. */ /* If INDEXA is 1 then AXDEF defines the X axis of the */ /* coordinate frame. */ /* If INDEXA is 2 then AXDEF defines the Y axis of the */ /* coordinate frame. */ /* If INDEXA is 3 then AXDEF defines the Z axis of the */ /* coordinate frame */ /* PLNDEF is a vector defining (with AXDEF) a principal plane of */ /* the coordinate frame. AXDEF and PLNDEF must be */ /* linearly independent. */ /* INDEXP is the second axis of the principal frame determined */ /* by AXDEF and PLNDEF. INDEXA, INDEXP must be different */ /* and be integers from 1 to 3. */ /* If INDEXP is 1, the second axis of the principal */ /* plane is the X-axis. */ /* If INDEXP is 2, the second axis of the principal */ /* plane is the Y-axis. */ /* If INDEXP is 3, the second axis of the principal plane */ /* is the Z-axis. */ /* $ Detailed_Output */ /* MOUT is a rotation matrix that transforms coordinates given */ /* in the input frame to the frame determined by AXDEF, */ /* PLNDEF, INDEXA and INDEXP. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If INDEXA or INDEXP is not in the set {1,2,3} the error */ /* SPICE(BADINDEX) will be signaled. */ /* 2) If INDEXA and INDEXP are the same the error */ /* SPICE(UNDEFINEDFRAME) will be signaled. */ /* 3) If the cross product of the vectors AXDEF and PLNDEF is zero, */ /* the error SPICE(DEPENDENTVECTORS) will be signaled. */ /* $ Files */ /* None. */ /* $ Particulars */ /* Given two linearly independent vectors there is a unique */ /* right-handed coordinate frame having: */ /* AXDEF lying along the INDEXA axis. */ /* PLNDEF lying in the INDEXA-INDEXP coordinate plane. */ /* This routine determines the transformation matrix that transforms */ /* from coordinates used to represent the input vectors to the */ /* the system determined by AXDEF and PLNDEF. Thus a vector */ /* (x,y,z) in the input coordinate system will have coordinates */ /* t */ /* MOUT* (x,y,z) */ /* in the frame determined by AXDEF and PLNDEF. */ /* $ Examples */ /* The rotation matrix TICC from inertial to Sun-Canopus */ /* (celestial) coordinates is found by the call */ /* CALL TWOVEC (Sun vector, 3, Canopus vector, 1, TICC) */ /* $ Restrictions */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* W.M. Owen (JPL) */ /* W.L. Taber (JPL) */ /* $ Literature_References */ /* None. */ /* $ Version */ /* - SPICELIB Version 1.1.0, 31-AUG-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VSCL call. */ /* - SPICELIB Version 1.0.1, 10-MAR-1992 (WLT) */ /* Comment section for permuted index source lines was added */ /* following the header. */ /* - SPICELIB Version 1.0.0, 31-JAN-1990 (WMO) */ /* -& */ /* $ Index_Entries */ /* define an orthonormal frame from two vectors */ /* -& */ /* $ Revisions */ /* - SPICELIB Version 1.1.0, 31-AUG-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VSCL call. */ /* - Beta Version 2.0.0, 10-JAN-1989 (WLT) */ /* Error checking was added and the algorithm somewhat redesigned. */ /* -& */ /* SPICELIB functions */ /* Local variables */ /* Saved variables */ /* Initial values */ /* Standard SPICE error handling */ if (return_()) { return 0; } else { chkin_("TWOVEC", (ftnlen)6); } /* Check for obvious bad inputs. */ if (max(*indexp,*indexa) > 3 || min(*indexp,*indexa) < 1) { setmsg_("The definition indexs must lie in the range from 1 to 3. T" "he value of INDEXA was #. The value of INDEXP was #. ", ( ftnlen)112); errint_("#", indexa, (ftnlen)1); errint_("#", indexp, (ftnlen)1); sigerr_("SPICE(BADINDEX)", (ftnlen)15); chkout_("TWOVEC", (ftnlen)6); return 0; } else if (*indexa == *indexp) { setmsg_("The values of INDEXA and INDEXP were the same, namely #. T" "hey are required to be different.", (ftnlen)92); errint_("#", indexa, (ftnlen)1); sigerr_("SPICE(UNDEFINEDFRAME)", (ftnlen)21); chkout_("TWOVEC", (ftnlen)6); return 0; } /* Get indices for right-handed axes */ /* First AXDEF ... */ i1 = *indexa; /* ... then the other two. */ i2 = seqnce[(i__1 = *indexa) < 5 && 0 <= i__1 ? i__1 : s_rnge("seqnce", i__1, "twovec_", (ftnlen)270)]; i3 = seqnce[(i__1 = *indexa + 1) < 5 && 0 <= i__1 ? i__1 : s_rnge("seqnce" , i__1, "twovec_", (ftnlen)271)]; /* Row I1 contains normalized AXDEF (store in columns for now) */ vhat_(axdef, &mout[(i__1 = i1 * 3 - 3) < 9 && 0 <= i__1 ? i__1 : s_rnge( "mout", i__1, "twovec_", (ftnlen)276)]); /* Obtain rows I2 and I3 using cross products. Which order to use */ /* depends on whether INDEXP = I2 (next axis in right-handed order) */ /* or INDEXP = I3 (previous axis in right-handed order). */ if (*indexp == i2) { ucrss_(axdef, plndef, &mout[(i__1 = i3 * 3 - 3) < 9 && 0 <= i__1 ? i__1 : s_rnge("mout", i__1, "twovec_", (ftnlen)285)]); ucrss_(&mout[(i__1 = i3 * 3 - 3) < 9 && 0 <= i__1 ? i__1 : s_rnge( "mout", i__1, "twovec_", (ftnlen)286)], axdef, &mout[(i__2 = i2 * 3 - 3) < 9 && 0 <= i__2 ? i__2 : s_rnge("mout", i__2, "twovec_", (ftnlen)286)]); } else { ucrss_(plndef, axdef, &mout[(i__1 = i2 * 3 - 3) < 9 && 0 <= i__1 ? i__1 : s_rnge("mout", i__1, "twovec_", (ftnlen)290)]); ucrss_(axdef, &mout[(i__1 = i2 * 3 - 3) < 9 && 0 <= i__1 ? i__1 : s_rnge("mout", i__1, "twovec_", (ftnlen)291)], &mout[(i__2 = i3 * 3 - 3) < 9 && 0 <= i__2 ? i__2 : s_rnge("mout", i__2, "twovec_", (ftnlen)291)]); } /* Finally, check to see that we actually got something non-zero */ /* in one of the one columns of MOUT(1,I2) and MOUT(1,I3) (we need */ /* only check one of them since they are related by a cross product). */ if (mout[(i__1 = i2 * 3 - 3) < 9 && 0 <= i__1 ? i__1 : s_rnge("mout", i__1, "twovec_", (ftnlen)300)] == 0. && mout[(i__2 = i2 * 3 - 2) < 9 && 0 <= i__2 ? i__2 : s_rnge("mout", i__2, "twovec_", (ftnlen) 300)] == 0. && mout[(i__3 = i2 * 3 - 1) < 9 && 0 <= i__3 ? i__3 : s_rnge("mout", i__3, "twovec_", (ftnlen)300)] == 0.) { setmsg_("The input vectors AXDEF and PLNDEF are linearly dependent.", (ftnlen)58); sigerr_("SPICE(DEPENDENTVECTORS)", (ftnlen)23); } /* Transpose MOUT. */ xpose_(mout, mtemp); moved_(mtemp, &c__9, mout); chkout_("TWOVEC", (ftnlen)6); return 0; } /* twovec_ */
/* $Procedure ZZGFSSOB ( GF, state of sub-observer point ) */ /* Subroutine */ int zzgfssob_(char *method, integer *trgid, doublereal *et, char *fixref, char *abcorr, integer *obsid, doublereal *radii, doublereal *state, ftnlen method_len, ftnlen fixref_len, ftnlen abcorr_len) { /* Initialized data */ static logical first = TRUE_; static integer prvobs = 0; static integer prvtrg = 0; static char svobs[36] = " "; static char svtarg[36] = " "; /* System generated locals */ integer i__1; /* Builtin functions */ integer s_rnge(char *, integer, char *, integer); /* Local variables */ doublereal dalt[2]; logical near__, geom; extern /* Subroutine */ int vhat_(doublereal *, doublereal *), vscl_( doublereal *, doublereal *, doublereal *); extern doublereal vdot_(doublereal *, doublereal *); logical xmit; extern /* Subroutine */ int mxvg_(doublereal *, doublereal *, integer *, integer *, doublereal *); doublereal upos[3]; extern /* Subroutine */ int zzstelab_(logical *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *), zzcorsxf_(logical *, doublereal *, doublereal *, doublereal *); integer i__; extern /* Subroutine */ int zzprscor_(char *, logical *, ftnlen); doublereal t; extern /* Subroutine */ int vaddg_(doublereal *, doublereal *, integer *, doublereal *); doublereal scale; extern /* Subroutine */ int chkin_(char *, ftnlen), errch_(char *, char *, ftnlen, ftnlen); doublereal savel[3]; logical found; extern /* Subroutine */ int moved_(doublereal *, integer *, doublereal *), vsubg_(doublereal *, doublereal *, integer *, doublereal *); doublereal stemp[6]; extern logical eqstr_(char *, char *, ftnlen, ftnlen); doublereal xform[36] /* was [6][6] */; logical uselt; extern /* Subroutine */ int bodc2s_(integer *, char *, ftnlen); doublereal ssbtg0[6]; extern logical failed_(void); doublereal sa[3]; extern /* Subroutine */ int cleard_(integer *, doublereal *); doublereal lt; integer frcode; extern doublereal clight_(void); extern logical return_(void); doublereal corxfi[36] /* was [6][6] */, corxfm[36] /* was [6][6] */, fxosta[6], fxpsta[6], fxpvel[3], fxtsta[6], obspnt[6], obssta[ 12] /* was [6][2] */, obstrg[6], acc[3], pntsta[6], raysta[6], sastat[6], spoint[3], srfvec[3], ssbobs[6], ssbtrg[6], trgepc; integer center, clssid, frclss; logical attblk[6], usestl; extern /* Subroutine */ int setmsg_(char *, ftnlen); logical fnd; extern /* Subroutine */ int sigerr_(char *, ftnlen), chkout_(char *, ftnlen), namfrm_(char *, integer *, ftnlen), frinfo_(integer *, integer *, integer *, integer *, logical *), errint_(char *, integer *, ftnlen), spkgeo_(integer *, doublereal *, char *, integer *, doublereal *, doublereal *, ftnlen), vminug_( doublereal *, integer *, doublereal *), dnearp_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, logical *), surfpv_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, logical *) , subpnt_(char *, char *, doublereal *, char *, char *, char *, doublereal *, doublereal *, doublereal *, ftnlen, ftnlen, ftnlen, ftnlen, ftnlen), spkssb_(integer *, doublereal *, char *, doublereal *, ftnlen); doublereal dlt; extern /* Subroutine */ int sxform_(char *, char *, doublereal *, doublereal *, ftnlen, ftnlen), qderiv_(integer *, doublereal *, doublereal *, doublereal *, doublereal *), invstm_(doublereal *, doublereal *); /* $ Abstract */ /* SPICE private routine intended solely for the support of SPICE */ /* routines. Users should not call this routine directly due to the */ /* volatile nature of this routine. */ /* Return the state of a sub-observer point used to define */ /* coordinates referenced in a GF search. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* GF */ /* SPK */ /* TIME */ /* NAIF_IDS */ /* FRAMES */ /* $ Keywords */ /* GEOMETRY */ /* PRIVATE */ /* SEARCH */ /* $ Declarations */ /* $ Abstract */ /* This file contains public, global parameter declarations */ /* for the SPICELIB Geometry Finder (GF) subsystem. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* GF */ /* $ Keywords */ /* GEOMETRY */ /* ROOT */ /* $ Restrictions */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* L.E. Elson (JPL) */ /* E.D. Wright (JPL) */ /* $ Literature_References */ /* None. */ /* $ Version */ /* - SPICELIB Version 1.3.0, 01-OCT-2011 (NJB) */ /* Added NWILUM parameter. */ /* - SPICELIB Version 1.2.0, 14-SEP-2010 (EDW) */ /* Added NWPA parameter. */ /* - SPICELIB Version 1.1.0, 08-SEP-2009 (EDW) */ /* Added NWRR parameter. */ /* Added NWUDS parameter. */ /* - SPICELIB Version 1.0.0, 21-FEB-2009 (NJB) (LSE) (EDW) */ /* -& */ /* Root finding parameters: */ /* CNVTOL is the default convergence tolerance used by the */ /* high-level GF search API routines. This tolerance is */ /* used to terminate searches for binary state transitions: */ /* when the time at which a transition occurs is bracketed */ /* by two times that differ by no more than CNVTOL, the */ /* transition time is considered to have been found. */ /* Units are TDB seconds. */ /* NWMAX is the maximum number of windows allowed for user-defined */ /* workspace array. */ /* DOUBLE PRECISION WORK ( LBCELL : MW, NWMAX ) */ /* Currently no more than twelve windows are required; the three */ /* extra windows are spares. */ /* Callers of GFEVNT can include this file and use the parameter */ /* NWMAX to declare the second dimension of the workspace array */ /* if necessary. */ /* Callers of GFIDST should declare their workspace window */ /* count using NWDIST. */ /* Callers of GFSEP should declare their workspace window */ /* count using NWSEP. */ /* Callers of GFRR should declare their workspace window */ /* count using NWRR. */ /* Callers of GFUDS should declare their workspace window */ /* count using NWUDS. */ /* Callers of GFPA should declare their workspace window */ /* count using NWPA. */ /* Callers of GFILUM should declare their workspace window */ /* count using NWILUM. */ /* ADDWIN is a parameter used to expand each interval of the search */ /* (confinement) window by a small amount at both ends in order to */ /* accommodate searches using equality constraints. The loaded */ /* kernel files must accommodate these expanded time intervals. */ /* FRMNLN is a string length for frame names. */ /* NVRMAX is the maximum number of vertices if FOV type is "POLYGON" */ /* FOVTLN -- maximum length for FOV string. */ /* Specify the character strings that are allowed in the */ /* specification of field of view shapes. */ /* Character strings that are allowed in the */ /* specification of occultation types: */ /* Occultation target shape specifications: */ /* Specify the number of supported occultation types and occultation */ /* type string length: */ /* Instrument field-of-view (FOV) parameters */ /* Maximum number of FOV boundary vectors: */ /* FOV shape parameters: */ /* circle */ /* ellipse */ /* polygon */ /* rectangle */ /* End of file gf.inc. */ /* $ Abstract */ /* SPICE private include file intended solely for the support of */ /* SPICE routines. Users should not include this routine in their */ /* source code due to the volatile nature of this file. */ /* This file contains private, global parameter declarations */ /* for the SPICELIB Geometry Finder (GF) subsystem. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* GF */ /* $ Keywords */ /* GEOMETRY */ /* ROOT */ /* $ Restrictions */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* E.D. Wright (JPL) */ /* $ Literature_References */ /* None. */ /* $ Version */ /* - SPICELIB Version 1.0.0, 17-FEB-2009 (NJB) (EDW) */ /* -& */ /* The set of supported coordinate systems */ /* System Coordinates */ /* ---------- ----------- */ /* Rectangular X, Y, Z */ /* Latitudinal Radius, Longitude, Latitude */ /* Spherical Radius, Colatitude, Longitude */ /* RA/Dec Range, Right Ascension, Declination */ /* Cylindrical Radius, Longitude, Z */ /* Geodetic Longitude, Latitude, Altitude */ /* Planetographic Longitude, Latitude, Altitude */ /* Below we declare parameters for naming coordinate systems. */ /* User inputs naming coordinate systems must match these */ /* when compared using EQSTR. That is, user inputs must */ /* match after being left justified, converted to upper case, */ /* and having all embedded blanks removed. */ /* Below we declare names for coordinates. Again, user */ /* inputs naming coordinates must match these when */ /* compared using EQSTR. */ /* Note that the RA parameter value below matches */ /* 'RIGHT ASCENSION' */ /* when extra blanks are compressed out of the above value. */ /* Parameters specifying types of vector definitions */ /* used for GF coordinate searches: */ /* All string parameter values are left justified, upper */ /* case, with extra blanks compressed out. */ /* POSDEF indicates the vector is defined by the */ /* position of a target relative to an observer. */ /* SOBDEF indicates the vector points from the center */ /* of a target body to the sub-observer point on */ /* that body, for a given observer and target. */ /* SOBDEF indicates the vector points from the center */ /* of a target body to the surface intercept point on */ /* that body, for a given observer, ray, and target. */ /* Number of workspace windows used by ZZGFREL: */ /* Number of additional workspace windows used by ZZGFLONG: */ /* Index of "existence window" used by ZZGFCSLV: */ /* Progress report parameters: */ /* MXBEGM, */ /* MXENDM are, respectively, the maximum lengths of the progress */ /* report message prefix and suffix. */ /* Note: the sum of these lengths, plus the length of the */ /* "percent complete" substring, should not be long enough */ /* to cause wrap-around on any platform's terminal window. */ /* Total progress report message length upper bound: */ /* End of file zzgf.inc. */ /* $ Abstract */ /* Include file zzabcorr.inc */ /* SPICE private file intended solely for the support of SPICE */ /* routines. Users should not include this file directly due */ /* to the volatile nature of this file */ /* The parameters below define the structure of an aberration */ /* correction attribute block. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Parameters */ /* An aberration correction attribute block is an array of logical */ /* flags indicating the attributes of the aberration correction */ /* specified by an aberration correction string. The attributes */ /* are: */ /* - Is the correction "geometric"? */ /* - Is light time correction indicated? */ /* - Is stellar aberration correction indicated? */ /* - Is the light time correction of the "converged */ /* Newtonian" variety? */ /* - Is the correction for the transmission case? */ /* - Is the correction relativistic? */ /* The parameters defining the structure of the block are as */ /* follows: */ /* NABCOR Number of aberration correction choices. */ /* ABATSZ Number of elements in the aberration correction */ /* block. */ /* GEOIDX Index in block of geometric correction flag. */ /* LTIDX Index of light time flag. */ /* STLIDX Index of stellar aberration flag. */ /* CNVIDX Index of converged Newtonian flag. */ /* XMTIDX Index of transmission flag. */ /* RELIDX Index of relativistic flag. */ /* The following parameter is not required to define the block */ /* structure, but it is convenient to include it here: */ /* CORLEN The maximum string length required by any aberration */ /* correction string */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* $ Literature_References */ /* None. */ /* $ Version */ /* - SPICELIB Version 1.0.0, 18-DEC-2004 (NJB) */ /* -& */ /* Number of aberration correction choices: */ /* Aberration correction attribute block size */ /* (number of aberration correction attributes): */ /* Indices of attributes within an aberration correction */ /* attribute block: */ /* Maximum length of an aberration correction string: */ /* End of include file zzabcorr.inc */ /* $ Brief_I/O */ /* VARIABLE I/O DESCRIPTION */ /* -------- --- -------------------------------------------------- */ /* METHOD I Computation method. */ /* TRGID I Target ID code. */ /* ET I Computation epoch. */ /* FIXREF I Reference frame name. */ /* ABCORR I Aberration correction. */ /* OBSID I Observer ID code. */ /* RADII I Target radii. */ /* STATE O State used to define coordinates. */ /* $ Detailed_Input */ /* METHOD is a short string providing parameters defining */ /* the computation method to be used. Any value */ /* supported by SUBPNT may be used. */ /* TRGID is the NAIF ID code of the target object. */ /* *This routine assumes that the target is modeled */ /* as a tri-axial ellipsoid.* */ /* ET is the time, expressed as ephemeris seconds past J2000 */ /* TDB, at which the specified state is to be computed. */ /* FIXREF is the name of the reference frame relative to which */ /* the state of interest is specified. */ /* FIXREF must be centered on the target body. */ /* Case, leading and trailing blanks are not significant */ /* in the string FIXREF. */ /* ABCORR indicates the aberration corrections to be applied to */ /* the state of the target body to account for one-way */ /* light time and stellar aberration. The orientation */ /* of the target body will also be corrected for one-way */ /* light time when light time corrections are requested. */ /* Supported aberration correction options for */ /* observation (case where radiation is received by */ /* observer at ET) are: */ /* NONE No correction. */ /* LT Light time only. */ /* LT+S Light time and stellar aberration. */ /* CN Converged Newtonian (CN) light time. */ /* CN+S CN light time and stellar aberration. */ /* Supported aberration correction options for */ /* transmission (case where radiation is emitted from */ /* observer at ET) are: */ /* XLT Light time only. */ /* XLT+S Light time and stellar aberration. */ /* XCN Converged Newtonian (CN) light time. */ /* XCN+S CN light time and stellar aberration. */ /* For detailed information, see the geometry finder */ /* required reading, gf.req. Also see the header of */ /* SPKEZR, which contains a detailed discussion of */ /* aberration corrections. */ /* Case, leading and trailing blanks are not significant */ /* in the string ABCORR. */ /* OBSID is the NAIF ID code of the observer. */ /* RADII is an array containing three radii defining */ /* a reference ellipsoid for the target body. */ /* $ Detailed_Output */ /* STATE is the state of the sub-observer point at ET. */ /* The first three components of STATE contain the */ /* sub-observer point itself; the last three */ /* components contain the derivative with respect to */ /* time of the position. The state is expressed */ /* relative to the body-fixed frame designated by */ /* FIXREF. */ /* Units are km and km/s. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If the aberration correction ABCORR is not recognized, */ /* the error will be diagnosed by routines in the call tree */ /* of this routine. */ /* 2) If the frame FIXREF is not recognized by the frames */ /* subsystem, the error will be diagnosed by routines in the */ /* call tree of this routine. */ /* 3) FIXREF must be centered on the target body; if it isn't, */ /* the error will be diagnosed by routines in the call tree */ /* of this routine. */ /* 4) Any error that occurs while look up the state of the target */ /* or observer will be diagnosed by routines in the call tree of */ /* this routine. */ /* 5) Any error that occurs while look up the orientation of */ /* the target will be diagnosed by routines in the call tree of */ /* this routine. */ /* 6) If the input method is not recognized, the error */ /* SPICE(NOTSUPPORTED) will be signaled. */ /* $ Files */ /* Appropriate kernels must be loaded by the calling program before */ /* this routine is called. */ /* The following data are required: */ /* - SPK data: ephemeris data for target and observer must be */ /* loaded. If aberration corrections are used, the states of */ /* target and observer relative to the solar system barycenter */ /* must be calculable from the available ephemeris data. */ /* Typically ephemeris data are made available by loading one */ /* or more SPK files via FURNSH. */ /* - PCK data: if the target body shape is modeled as an */ /* ellipsoid, triaxial radii for the target body must be loaded */ /* into the kernel pool. Typically this is done by loading a */ /* text PCK file via FURNSH. */ /* - Further PCK data: rotation data for the target body must be */ /* loaded. These may be provided in a text or binary PCK file. */ /* - Frame data: if a frame definition is required to convert the */ /* observer and target states to the body-fixed frame of the */ /* target, that definition must be available in the kernel */ /* pool. Typically the definition is supplied by loading a */ /* frame kernel via FURNSH. */ /* In all cases, kernel data are normally loaded once per program */ /* run, NOT every time this routine is called. */ /* $ Particulars */ /* This routine isolates the computation of the sub-observer state */ /* (that is, the sub-observer point and its derivative with respect */ /* to time). */ /* This routine is used by the GF coordinate utility routines in */ /* order to solve for time windows on which specified mathematical */ /* conditions involving coordinates are satisfied. The role of */ /* this routine is to provide Cartesian state vectors enabling */ /* the GF coordinate utilities to determine the signs of the */ /* derivatives with respect to time of coordinates of interest. */ /* $ Examples */ /* See ZZGFCOST. */ /* $ Restrictions */ /* 1) This routine is restricted to use with ellipsoidal target */ /* shape models. */ /* 2) The computations performed by this routine are intended */ /* to be compatible with those performed by the SPICE */ /* routine SUBPNT. If that routine changes, this routine */ /* may need to be updated. */ /* 3) This routine presumes that error checking of inputs */ /* has, where possible, already been performed by the */ /* GF coordinate utility initialization routine. */ /* 4) The interface and functionality of this set of routines may */ /* change without notice. These routines should be called only */ /* by SPICELIB routines. */ /* $ Literature_References */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* $ Version */ /* - SPICELIB Version 2.0.0 12-MAY-2009 (NJB) */ /* Upgraded to support targets and observers having */ /* no names associated with their ID codes. */ /* - SPICELIB Version 1.0.0 05-MAR-2009 (NJB) */ /* -& */ /* $ Index_Entries */ /* sub-observer state */ /* -& */ /* SPICELIB functions */ /* Local parameters */ /* Local variables */ /* Saved variables */ /* Initial values */ /* Standard SPICE error handling. */ if (return_()) { return 0; } chkin_("ZZGFSSOB", (ftnlen)8); if (first || *trgid != prvtrg) { bodc2s_(trgid, svtarg, (ftnlen)36); prvtrg = *trgid; } if (first || *obsid != prvobs) { bodc2s_(obsid, svobs, (ftnlen)36); prvobs = *obsid; } first = FALSE_; /* Parse the aberration correction specifier. */ zzprscor_(abcorr, attblk, abcorr_len); geom = attblk[0]; uselt = attblk[1]; usestl = attblk[2]; xmit = attblk[4]; /* Decide whether the sub-observer point is computed using */ /* the "near point" or "surface intercept" method. Only */ /* ellipsoids may be used a shape models for this computation. */ if (eqstr_(method, "Near point: ellipsoid", method_len, (ftnlen)21)) { near__ = TRUE_; } else if (eqstr_(method, "Intercept: ellipsoid", method_len, (ftnlen)20)) { near__ = FALSE_; } else { setmsg_("Sub-observer point computation method # is not supported by" " this routine.", (ftnlen)73); errch_("#", method, (ftnlen)1, method_len); sigerr_("SPICE(NOTSUPPORTED)", (ftnlen)19); chkout_("ZZGFSSOB", (ftnlen)8); return 0; } if (geom) { /* This is the geometric case. */ /* We need to check the body-fixed reference frame here. */ namfrm_(fixref, &frcode, fixref_len); frinfo_(&frcode, ¢er, &frclss, &clssid, &fnd); if (failed_()) { chkout_("ZZGFSSOB", (ftnlen)8); return 0; } if (! fnd) { setmsg_("Input reference frame # was not recognized.", (ftnlen)43) ; errch_("#", fixref, (ftnlen)1, fixref_len); sigerr_("SPICE(NOFRAME)", (ftnlen)14); chkout_("ZZGFSSOB", (ftnlen)8); return 0; } if (center != *trgid) { setmsg_("Input reference frame # is centered on body # instead o" "f body #.", (ftnlen)64); errch_("#", fixref, (ftnlen)1, fixref_len); errint_("#", ¢er, (ftnlen)1); errint_("#", trgid, (ftnlen)1); sigerr_("SPICE(INVALIDFRAME)", (ftnlen)19); chkout_("ZZGFSSOB", (ftnlen)8); return 0; } /* Get the state of the target with respect to the observer, */ /* expressed relative to the target body-fixed frame. We don't */ /* need to propagate states to the solar system barycenter in */ /* this case. */ spkgeo_(trgid, et, fixref, obsid, fxtsta, <, fixref_len); if (failed_()) { chkout_("ZZGFSSOB", (ftnlen)8); return 0; } /* Compute the state of the observer with respect to the target */ /* in the body-fixed frame. */ vminug_(fxtsta, &c__6, fxosta); /* Now we can obtain the surface velocity of the sub-observer */ /* point. */ if (near__) { /* The sub-observer point method is "near point." */ dnearp_(fxosta, radii, &radii[1], &radii[2], fxpsta, dalt, &found) ; if (! found) { setmsg_("The sub-observer state could could not be computed " "because the velocity was not well defined. DNEARP re" "turned \"not found.\"", (ftnlen)122); sigerr_("SPICE(DEGENERATECASE)", (ftnlen)21); chkout_("ZZGFSSOB", (ftnlen)8); return 0; } } else { /* The sub-observer point method is "surface */ /* intercept point." The ray direction is simply */ /* the negative of the observer's position relative */ /* to the target center. */ vminug_(fxosta, &c__6, raysta); surfpv_(fxosta, raysta, radii, &radii[1], &radii[2], fxpsta, & found); /* Although in general it's not an error for SURFPV to */ /* be unable to compute an intercept state, it *is* */ /* an error in this case, since the ray points toward */ /* the center of the target. */ if (! found) { setmsg_("The sub-observer state could could not be computed " "because the velocity was not well defined. SURFPV re" "turned \"not found.\"", (ftnlen)122); sigerr_("SPICE(DEGENERATECASE)", (ftnlen)21); chkout_("ZZGFSSOB", (ftnlen)8); return 0; } } } else if (uselt) { /* Light time and possibly stellar aberration corrections are */ /* applied. */ /* Most our work consists of getting ready to call either of the */ /* SPICELIB routines DNEARP or SURFPV. In order to make this */ /* call, we'll need the velocity of the observer relative to the */ /* target body's center in the target body-fixed frame. We must */ /* evaluate the rotation state of the target at the correct */ /* epoch, and account for the rate of change of light time, if */ /* light time corrections are used. The algorithm we use depends */ /* on the algorithm used in SUBPNT, since we're computing the */ /* derivative with respect to time of the solution found by that */ /* routine. */ /* In this algorithm, we must take into account the fact that */ /* SUBPNT performs light time and stellar aberration corrections */ /* for the sub-observer point, not for the center of the target */ /* body. */ /* If light time and stellar aberration corrections are used, */ /* - Find the aberration corrected sub-observer point and the */ /* light time-corrected epoch TRGEPC associated with the */ /* sub-observer point. */ /* - Use TRGEPC to find the position of the target relative to */ /* the solar system barycenter. */ /* - Use TRGEPC to find the orientation of the target relative */ /* to the J2000 reference frame. */ /* - Find the light-time corrected position of the */ /* sub-observer point; use this to compute the stellar */ /* aberration offset that applies to the sub-observer point, */ /* as well as the velocity of this offset. */ /* - Find the corrected state of the target center as seen */ /* from the observer, where the corrections are those */ /* applicable to the sub-observer point. */ /* - Negate the corrected target center state to obtain the */ /* state of the observer relative to the target. */ /* - Express the state of the observer relative to the target */ /* in the target body fixed frame at TRGEPC. */ /* Below, we'll use the convention that vectors expressed */ /* relative to the body-fixed frame have names of the form */ /* FX* */ /* Note that SUBPNT will signal an error if FIXREF is not */ /* actually centered on the target body. */ subpnt_(method, svtarg, et, fixref, abcorr, svobs, spoint, &trgepc, srfvec, method_len, (ftnlen)36, fixref_len, abcorr_len, ( ftnlen)36); /* Get J2000-relative states of observer and target with respect */ /* to the solar system barycenter at their respective epochs of */ /* participation. */ spkssb_(obsid, et, "J2000", ssbobs, (ftnlen)5); spkssb_(trgid, &trgepc, "J2000", ssbtg0, (ftnlen)5); /* Get the uncorrected J2000 to body-fixed to state */ /* transformation at TRGEPC. */ sxform_("J2000", fixref, &trgepc, xform, (ftnlen)5, fixref_len); if (failed_()) { chkout_("ZZGFSSOB", (ftnlen)8); return 0; } /* Initialize the state of the sub-observer point in the */ /* body-fixed frame. At this point we don't know the */ /* point's velocity; set it to zero. */ moved_(spoint, &c__3, fxpsta); cleard_(&c__3, &fxpsta[3]); if (usestl) { /* We're going to need the acceleration of the observer */ /* relative to the SSB. Compute this now. */ for (i__ = 1; i__ <= 2; ++i__) { /* The epoch is ET -/+ TDELTA. */ t = *et + ((i__ << 1) - 3) * 1.; spkssb_(obsid, &t, "J2000", &obssta[(i__1 = i__ * 6 - 6) < 12 && 0 <= i__1 ? i__1 : s_rnge("obssta", i__1, "zzgfss" "ob_", (ftnlen)652)], (ftnlen)5); } if (failed_()) { chkout_("ZZGFSSOB", (ftnlen)8); return 0; } /* Compute the observer's acceleration using a quadratic */ /* approximation. */ qderiv_(&c__3, &obssta[3], &obssta[9], &c_b40, acc); } /* The rest of the algorithm is iterative. On the first */ /* iteration, we don't have a good estimate of the velocity */ /* of the sub-observer point relative to the body-fixed */ /* frame. Since we're using this velocity as an input */ /* to the aberration velocity computations, we */ /* expect that treating this velocity as zero on the first */ /* pass yields a reasonable estimate. On the second pass, */ /* we'll use the velocity derived on the first pass. */ cleard_(&c__3, fxpvel); /* We'll also estimate the rate of change of light time */ /* as zero on the first pass. */ dlt = 0.; for (i__ = 1; i__ <= 2; ++i__) { /* Correct the target's velocity for the rate of */ /* change of light time. */ if (xmit) { scale = dlt + 1.; } else { scale = 1. - dlt; } /* Scale the velocity portion of the target state to */ /* correct the velocity for the rate of change of light */ /* time. */ moved_(ssbtg0, &c__3, ssbtrg); vscl_(&scale, &ssbtg0[3], &ssbtrg[3]); /* Get the state of the target with respect to the observer. */ vsubg_(ssbtrg, ssbobs, &c__6, obstrg); /* Correct the J2000 to body-fixed state transformation matrix */ /* for the rate of change of light time. */ zzcorsxf_(&xmit, &dlt, xform, corxfm); /* Invert CORXFM to obtain the corrected */ /* body-fixed to J2000 state transformation. */ invstm_(corxfm, corxfi); /* Convert the sub-observer point state to the J2000 frame. */ mxvg_(corxfi, fxpsta, &c__6, &c__6, pntsta); /* Find the J2000-relative state of the sub-observer */ /* point with respect to the target. */ vaddg_(obstrg, pntsta, &c__6, obspnt); if (usestl) { /* Now compute the stellar aberration correction */ /* applicable to OBSPNT. We need the velocity of */ /* this correction as well. */ zzstelab_(&xmit, acc, &ssbobs[3], obspnt, sa, savel); moved_(sa, &c__3, sastat); moved_(savel, &c__3, &sastat[3]); /* Adding the stellar aberration state to the target center */ /* state gives us the state of the target center with */ /* respect to the observer, corrected for the aberrations */ /* applicable to the sub-observer point. */ vaddg_(obstrg, sastat, &c__6, stemp); } else { moved_(obstrg, &c__6, stemp); } /* Convert STEMP to the body-fixed reference frame. */ mxvg_(corxfm, stemp, &c__6, &c__6, fxtsta); /* At long last, compute the state of the observer */ /* with respect to the target in the body-fixed frame. */ vminug_(fxtsta, &c__6, fxosta); /* Now we can obtain the surface velocity of the */ /* sub-observer point. */ if (near__) { /* The sub-observer point method is "near point." */ dnearp_(fxosta, radii, &radii[1], &radii[2], fxpsta, dalt, & found); if (! found) { setmsg_("The sub-observer state could could not be compu" "ted because the velocity was not well defined. " "DNEARP returned \"not found.\"", (ftnlen)123); sigerr_("SPICE(DEGENERATECASE)", (ftnlen)21); chkout_("ZZGFSSOB", (ftnlen)8); return 0; } } else { /* The sub-observer point method is "surface intercept */ /* point." The ray direction is simply the negative of the */ /* observer's position relative to the target center. */ vminug_(fxosta, &c__6, raysta); surfpv_(fxosta, raysta, radii, &radii[1], &radii[2], fxpsta, & found); /* Although in general it's not an error for SURFPV to be */ /* unable to compute an intercept state, it *is* an error */ /* in this case, since the ray points toward the center of */ /* the target. */ if (! found) { setmsg_("The sub-observer state could could not be compu" "ted because the velocity was not well defined. S" "URFPV returned \"not found.\"", (ftnlen)122); sigerr_("SPICE(DEGENERATECASE)", (ftnlen)21); chkout_("ZZGFSSOB", (ftnlen)8); return 0; } } /* At this point we can update the surface point */ /* velocity and light time derivative estimates. */ /* In order to compute the light time rate, we'll */ /* need the J2000-relative velocity of the sub-observer */ /* point with respect to the observer. First convert */ /* the sub-observer state to the J2000 frame, then */ /* add the result to the state of the target center */ /* with respect to the observer. */ mxvg_(corxfi, fxpsta, &c__6, &c__6, pntsta); vaddg_(obstrg, pntsta, &c__6, obspnt); /* Now that we have an improved estimate of the */ /* sub-observer state, we can estimate the rate of */ /* change of light time as */ /* range rate */ /* ---------- */ /* c */ /* If we're correcting for stellar aberration, *ideally* we */ /* should remove that correction now, since the light time */ /* rate is based on light time between the observer and the */ /* light-time corrected sub-observer point. But the error made */ /* by including stellar aberration is too small to make it */ /* worthwhile to make this adjustment. */ vhat_(obspnt, upos); dlt = vdot_(&obspnt[3], upos) / clight_(); /* With FXPVEL and DLT updated, we'll repeat our */ /* computations. */ } } else { /* We should never get here. */ setmsg_("Aberration correction # was not recognized.", (ftnlen)43); errch_("#", abcorr, (ftnlen)1, abcorr_len); sigerr_("SPICE(NOTSUPPORTED)", (ftnlen)19); chkout_("ZZGFSSOB", (ftnlen)8); return 0; } /* Copy the computed state to the output argument STATE. */ moved_(fxpsta, &c__6, state); chkout_("ZZGFSSOB", (ftnlen)8); return 0; } /* zzgfssob_ */
/* $Procedure ZZSTELAB ( Private --- stellar aberration correction ) */ /* Subroutine */ int zzstelab_(logical *xmit, doublereal *accobs, doublereal * vobs, doublereal *starg, doublereal *scorr, doublereal *dscorr) { /* System generated locals */ integer i__1; doublereal d__1, d__2; /* Builtin functions */ double sqrt(doublereal); integer s_rnge(char *, integer, char *, integer); /* Local variables */ extern /* Subroutine */ int vadd_(doublereal *, doublereal *, doublereal * ); doublereal dphi, rhat[3]; extern /* Subroutine */ int vhat_(doublereal *, doublereal *); extern doublereal vdot_(doublereal *, doublereal *); extern /* Subroutine */ int vequ_(doublereal *, doublereal *); doublereal term1[3], term2[3], term3[3], c__, lcacc[3]; integer i__; doublereal s; extern /* Subroutine */ int chkin_(char *, ftnlen); doublereal saoff[6] /* was [3][2] */, drhat[3]; extern /* Subroutine */ int dvhat_(doublereal *, doublereal *); doublereal ptarg[3], evobs[3], srhat[6], vphat[3], vtarg[3]; extern /* Subroutine */ int vlcom_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *), vperp_(doublereal *, doublereal *, doublereal *); extern doublereal vnorm_(doublereal *); extern logical vzero_(doublereal *); extern /* Subroutine */ int vlcom3_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *, doublereal *), cleard_(integer *, doublereal *); doublereal vp[3]; extern doublereal clight_(void); doublereal dptmag, ptgmag, eptarg[3], dvphat[3], lcvobs[3]; extern /* Subroutine */ int qderiv_(integer *, doublereal *, doublereal *, doublereal *, doublereal *), sigerr_(char *, ftnlen), chkout_( char *, ftnlen), setmsg_(char *, ftnlen); doublereal svphat[6]; extern logical return_(void); extern /* Subroutine */ int vminus_(doublereal *, doublereal *); doublereal sgn, dvp[3], svp[6]; /* $ Abstract */ /* SPICE Private routine intended solely for the support of SPICE */ /* routines. Users should not call this routine directly due */ /* to the volatile nature of this routine. */ /* Return the state (position and velocity) of a target body */ /* relative to an observing body, optionally corrected for light */ /* time (planetary aberration) and stellar aberration. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* SPK */ /* $ Keywords */ /* EPHEMERIS */ /* $ Declarations */ /* $ Brief_I/O */ /* Variable I/O Description */ /* -------- --- -------------------------------------------------- */ /* XMIT I Reception/transmission flag. */ /* ACCOBS I Observer acceleration relative to SSB. */ /* VOBS I Observer velocity relative to to SSB. */ /* STARG I State of target relative to observer. */ /* SCORR O Stellar aberration correction for position. */ /* DSCORR O Stellar aberration correction for velocity. */ /* $ Detailed_Input */ /* XMIT is a logical flag which is set to .TRUE. for the */ /* "transmission" case in which photons *depart* from */ /* the observer's location at an observation epoch ET */ /* and arrive at the target's location at the light-time */ /* corrected epoch ET+LT, where LT is the one-way light */ /* time between observer and target; XMIT is set to */ /* .FALSE. for "reception" case in which photons depart */ /* from the target's location at the light-time */ /* corrected epoch ET-LT and *arrive* at the observer's */ /* location at ET. */ /* Note that the observation epoch is not used in this */ /* routine. */ /* XMIT must be consistent with any light time */ /* corrections used for the input state STARG: if that */ /* state has been corrected for "reception" light time; */ /* XMIT must be .FALSE.; otherwise XMIT must be .TRUE. */ /* ACCOBS is the geometric acceleration of the observer */ /* relative to the solar system barycenter. Units are */ /* km/sec**2. ACCOBS must be expressed relative to */ /* an inertial reference frame. */ /* VOBS is the geometric velocity of the observer relative to */ /* the solar system barycenter. VOBS must be expressed */ /* relative to the same inertial reference frame as */ /* ACCOBS. Units are km/sec. */ /* STARG is the Cartesian state of the target relative to the */ /* observer. Normally STARG has been corrected for */ /* one-way light time, but this is not required. STARG */ /* must be expressed relative to the same inertial */ /* reference frame as ACCOBS. Components are */ /* (x, y, z, dx, dy, dz). Units are km and km/sec. */ /* $ Detailed_Output */ /* SCORR is the stellar aberration correction for the position */ /* component of STARG. Adding SCORR to this position */ /* vector produces the input observer-target position, */ /* corrected for stellar aberration. */ /* The reference frame of SCORR is the common frame */ /* relative to which the inputs ACCOBS, VOBS, and STARG */ /* are expressed. Units are km. */ /* DSCORR is the stellar aberration correction for the velocity */ /* component of STARG. Adding DSCORR to this velocity */ /* vector produces the input observer-target velocity, */ /* corrected for stellar aberration. */ /* The reference frame of DSCORR is the common frame */ /* relative to which the inputs ACCOBS, VOBS, and STARG */ /* are expressed. Units are km/s. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If attempt to divide by zero occurs, the error */ /* SPICE(DIVIDEBYZERO) will be signaled. This case may occur */ /* due to uninitialized inputs. */ /* 2) Loss of precision will occur for geometric cases in which */ /* VOBS is nearly parallel to the position component of STARG. */ /* $ Files */ /* None. */ /* $ Particulars */ /* This routine computes a Newtonian estimate of the stellar */ /* aberration correction of an input state. Normally the input state */ /* has already been corrected for one-way light time. */ /* Since stellar aberration corrections are typically "small" */ /* relative to the magnitude of the input observer-target position */ /* and velocity, this routine avoids loss of precision by returning */ /* the corrections themselves rather than the corrected state */ /* vector. This allows the caller to manipulate (for example, */ /* interpolate) the corrections with greater accuracy. */ /* $ Examples */ /* See SPICELIB routine SPKACS. */ /* $ Restrictions */ /* None. */ /* $ Literature_References */ /* SPK Required Reading. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* $ Version */ /* - SPICELIB Version 2.0.0, 15-APR-2014 (NJB) */ /* Added RETURN test and discovery check-in. */ /* Check for division by zero was added. This */ /* case might occur due to uninitialized inputs. */ /* - SPICELIB Version 1.0.1, 12-FEB-2009 (NJB) */ /* Minor updates were made to the inline documentation. */ /* - SPICELIB Version 1.0.0, 17-JAN-2008 (NJB) */ /* -& */ /* Note for the maintenance programmer */ /* =================================== */ /* The source code of the test utility T_ZZSTLABN must be */ /* kept in sync with the source code of this routine. That */ /* routine uses a value of SEPLIM that forces the numeric */ /* branch of the velocity computation to be taken in all */ /* cases. See the documentation of that routine for details. */ /* SPICELIB functions */ /* Local parameters */ /* Let PHI be the (non-negative) rotation angle of the stellar */ /* aberration correction; then SEPLIM is a limit on how close PHI */ /* may be to zero radians while stellar aberration velocity is */ /* computed analytically. When sin(PHI) is less than SEPLIM, the */ /* velocity must be computed numerically. */ /* Let TDELTA be the time interval, measured in seconds, */ /* used for numerical differentiation of the stellar */ /* aberration correction, when this is necessary. */ /* Local variables */ /* Use discovery check-in. */ if (return_()) { return 0; } /* In the discussion below, the dot product of vectors X and Y */ /* is denoted by */ /* <X,Y> */ /* The speed of light is denoted by the lower case letter "c." BTW, */ /* variable names used here are case-sensitive: upper case "C" */ /* represents a different quantity which is unrelated to the speed */ /* of light. */ /* Variable names ending in "HAT" denote unit vectors. Variable */ /* names starting with "D" denote derivatives with respect to time. */ /* We'll compute the correction SCORR and its derivative with */ /* respect to time DSCORR for the reception case. In the */ /* transmission case, we perform the same computation with the */ /* negatives of the observer velocity and acceleration. */ /* In the code below, we'll store the position and velocity portions */ /* of the input observer-target state STARG in the variables PTARG */ /* and VTARG, respectively. */ /* Let VP be the component of VOBS orthogonal to PTARG. VP */ /* is defined as */ /* VOBS - < VOBS, RHAT > RHAT (1) */ /* where RHAT is the unit vector */ /* PTARG/||PTARG|| */ /* Then */ /* ||VP||/c (2) */ /* is the magnitude of */ /* s = sin( phi ) (3) */ /* where phi is the stellar aberration correction angle. We'll */ /* need the derivative with respect to time of (2). */ /* Differentiating (1) with respect to time yields the */ /* velocity DVP, where, letting */ /* DRHAT = d(RHAT) / dt */ /* VPHAT = VP / ||VP|| */ /* DVPMAG = d( ||VP|| ) / dt */ /* we have */ /* DVP = d(VP)/dt */ /* = ACCOBS - ( ( <VOBS,DRHAT> + <ACCOBS, RHAT> )*RHAT */ /* + <VOBS,RHAT> * DRHAT ) (4) */ /* and */ /* DVPMAG = < DVP, VPHAT > (5) */ /* Now we can find the derivative with respect to time of */ /* the stellar aberration angle phi: */ /* ds/dt = d(sin(phi))/dt = d(phi)/dt * cos(phi) (6) */ /* Using (2) and (5), we have for positive phi, */ /* ds/dt = (1/c)*DVPMAG = (1/c)*<DVP, VPHAT> (7) */ /* Then for positive phi */ /* d(phi)/dt = (1/cos(phi)) * (1/c) * <DVP, VPHAT> (8) */ /* Equation (8) is well-defined as along as VP is non-zero: */ /* if VP is the zero vector, VPHAT is undefined. We'll treat */ /* the singular and near-singular cases separately. */ /* The aberration correction itself is a rotation by angle phi */ /* from RHAT towards VP, so the corrected vector is */ /* ( sin(phi)*VPHAT + cos(phi)*RHAT ) * ||PTARG|| */ /* and we can express the offset of the corrected vector from */ /* PTARG, which is the output SCORR, as */ /* SCORR = */ /* ( sin(phi)*VPHAT + (cos(phi)-1)*RHAT ) * ||PTARG|| (9) */ /* Let DPTMAG be defined as */ /* DPTMAG = d ( ||PTARG|| ) / dt (10) */ /* Then the derivative with respect to time of SCORR is */ /* DSCORR = */ /* ( sin(phi)*DVPHAT */ /* + cos(phi)*d(phi)/dt * VPHAT */ /* + (cos(phi) - 1) * DRHAT */ /* + ( -sin(phi)*d(phi)/dt ) * RHAT ) * ||PTARG|| */ /* + ( sin(phi)*VPHAT + (cos(phi)-1)*RHAT ) * DPTMAG (11) */ /* Computations begin here: */ /* Split STARG into position and velocity components. Compute */ /* RHAT */ /* DRHAT */ /* VP */ /* DPTMAG */ if (*xmit) { vminus_(vobs, lcvobs); vminus_(accobs, lcacc); } else { vequ_(vobs, lcvobs); vequ_(accobs, lcacc); } vequ_(starg, ptarg); vequ_(&starg[3], vtarg); dvhat_(starg, srhat); vequ_(srhat, rhat); vequ_(&srhat[3], drhat); vperp_(lcvobs, rhat, vp); dptmag = vdot_(vtarg, rhat); /* Compute sin(phi) and cos(phi), which we'll call S and C */ /* respectively. Note that phi is always close to zero for */ /* realistic inputs (for which ||VOBS|| << CLIGHT), so the */ /* cosine term is positive. */ s = vnorm_(vp) / clight_(); /* Computing MAX */ d__1 = 0., d__2 = 1 - s * s; c__ = sqrt((max(d__1,d__2))); if (c__ == 0.) { /* C will be used as a divisor later (in the computation */ /* of DPHI), so we'll put a stop to the problem here. */ chkin_("ZZSTELAB", (ftnlen)8); setmsg_("Cosine of the aberration angle is 0; this cannot occur for " "realistic observer velocities. This case can arise due to un" "initialized inputs. This cosine value is used as a divisor i" "n a later computation, so it must not be equal to zero.", ( ftnlen)234); sigerr_("SPICE(DIVIDEBYZERO)", (ftnlen)19); chkout_("ZZSTELAB", (ftnlen)8); return 0; } /* Compute the unit vector VPHAT and the stellar */ /* aberration correction. We avoid relying on */ /* VHAT's exception handling for the zero vector. */ if (vzero_(vp)) { cleard_(&c__3, vphat); } else { vhat_(vp, vphat); } /* Now we can use equation (9) to obtain the stellar */ /* aberration correction SCORR: */ /* SCORR = */ /* ( sin(phi)*VPHAT + (cos(phi)-1)*RHAT ) * ||PTARG|| */ ptgmag = vnorm_(ptarg); d__1 = ptgmag * s; d__2 = ptgmag * (c__ - 1.); vlcom_(&d__1, vphat, &d__2, rhat, scorr); /* Now we use S as an estimate of PHI to decide if we're */ /* going to differentiate the stellar aberration correction */ /* analytically or numerically. */ /* Note that S is non-negative by construction, so we don't */ /* need to use the absolute value of S here. */ if (s >= 1e-6) { /* This is the analytic case. */ /* Compute DVP---the derivative of VP with respect to time. */ /* Recall equation (4): */ /* DVP = d(VP)/dt */ /* = ACCOBS - ( ( <VOBS,DRHAT> + <ACCOBS, RHAT> )*RHAT */ /* + <VOBS,RHAT> * DRHAT ) */ d__1 = -vdot_(lcvobs, drhat) - vdot_(lcacc, rhat); d__2 = -vdot_(lcvobs, rhat); vlcom3_(&c_b7, lcacc, &d__1, rhat, &d__2, drhat, dvp); vhat_(vp, vphat); /* Now we can compute DVPHAT, the derivative of VPHAT: */ vequ_(vp, svp); vequ_(dvp, &svp[3]); dvhat_(svp, svphat); vequ_(&svphat[3], dvphat); /* Compute the DPHI, the time derivative of PHI, using equation 8: */ /* d(phi)/dt = (1/cos(phi)) * (1/c) * <DVP, VPHAT> */ dphi = 1. / (c__ * clight_()) * vdot_(dvp, vphat); /* At long last we've assembled all of the "ingredients" required */ /* to compute DSCORR: */ /* DSCORR = */ /* ( sin(phi)*DVPHAT */ /* + cos(phi)*d(phi)/dt * VPHAT */ /* + (cos(phi) - 1) * DRHAT */ /* + ( -sin(phi)*d(phi)/dt ) * RHAT ) * ||PTARG|| */ /* + ( sin(phi)*VPHAT + (cos(phi)-1)*RHAT ) * DPTMAG */ d__1 = c__ * dphi; vlcom_(&s, dvphat, &d__1, vphat, term1); d__1 = c__ - 1.; d__2 = -s * dphi; vlcom_(&d__1, drhat, &d__2, rhat, term2); vadd_(term1, term2, term3); d__1 = dptmag * s; d__2 = dptmag * (c__ - 1.); vlcom3_(&ptgmag, term3, &d__1, vphat, &d__2, rhat, dscorr); } else { /* This is the numeric case. We're going to differentiate */ /* the stellar aberration correction offset vector using */ /* a quadratic estimate. */ for (i__ = 1; i__ <= 2; ++i__) { /* Set the sign of the time offset. */ if (i__ == 1) { sgn = -1.; } else { sgn = 1.; } /* Estimate the observer's velocity relative to the */ /* solar system barycenter at the current epoch. We use */ /* the local copies of the input velocity and acceleration */ /* to make a linear estimate. */ d__1 = sgn * 1.; vlcom_(&c_b7, lcvobs, &d__1, lcacc, evobs); /* Estimate the observer-target vector. We use the */ /* observer-target state velocity to make a linear estimate. */ d__1 = sgn * 1.; vlcom_(&c_b7, starg, &d__1, &starg[3], eptarg); /* Let RHAT be the unit observer-target position. */ /* Compute the component of the observer's velocity */ /* that is perpendicular to the target position; call */ /* this vector VP. Also compute the unit vector in */ /* the direction of VP. */ vhat_(eptarg, rhat); vperp_(evobs, rhat, vp); if (vzero_(vp)) { cleard_(&c__3, vphat); } else { vhat_(vp, vphat); } /* Compute the sine and cosine of the correction */ /* angle. */ s = vnorm_(vp) / clight_(); /* Computing MAX */ d__1 = 0., d__2 = 1 - s * s; c__ = sqrt((max(d__1,d__2))); /* Compute the vector offset of the correction. */ ptgmag = vnorm_(eptarg); d__1 = ptgmag * s; d__2 = ptgmag * (c__ - 1.); vlcom_(&d__1, vphat, &d__2, rhat, &saoff[(i__1 = i__ * 3 - 3) < 6 && 0 <= i__1 ? i__1 : s_rnge("saoff", i__1, "zzstelab_", ( ftnlen)597)]); } /* Now compute the derivative. */ qderiv_(&c__3, saoff, &saoff[3], &c_b7, dscorr); } /* At this point the correction offset SCORR and its derivative */ /* with respect to time DSCORR are both set. */ return 0; } /* zzstelab_ */
/* $Procedure ZZFOVAXI ( Generate an axis vector for polygonal FOV ) */ /* Subroutine */ int zzfovaxi_(char *inst, integer *n, doublereal *bounds, doublereal *axis, ftnlen inst_len) { /* System generated locals */ integer bounds_dim2, i__1, i__2, i__3; doublereal d__1; /* Builtin functions */ integer s_rnge(char *, integer, char *, integer); /* Local variables */ extern /* Subroutine */ int vadd_(doublereal *, doublereal *, doublereal * ); doublereal uvec[3]; extern /* Subroutine */ int vhat_(doublereal *, doublereal *); extern doublereal vsep_(doublereal *, doublereal *); integer next; extern /* Subroutine */ int vequ_(doublereal *, doublereal *), zzhullax_( char *, integer *, doublereal *, doublereal *, ftnlen); integer i__; doublereal v[3]; extern /* Subroutine */ int chkin_(char *, ftnlen), errch_(char *, char *, ftnlen, ftnlen); doublereal limit; extern /* Subroutine */ int vcrss_(doublereal *, doublereal *, doublereal *); extern logical vzero_(doublereal *); doublereal cp[3]; extern logical failed_(void); logical ok; extern /* Subroutine */ int cleard_(integer *, doublereal *); extern doublereal halfpi_(void); extern /* Subroutine */ int sigerr_(char *, ftnlen), vhatip_(doublereal *) , chkout_(char *, ftnlen), vsclip_(doublereal *, doublereal *), setmsg_(char *, ftnlen), errint_(char *, integer *, ftnlen); extern logical return_(void); doublereal sep; /* $ Abstract */ /* SPICE Private routine intended solely for the support of SPICE */ /* routines. Users should not call this routine directly due */ /* to the volatile nature of this routine. */ /* Generate an axis of an instrument's polygonal FOV such that all */ /* of the FOV's boundary vectors have angular separation of strictly */ /* less than pi/2 radians from this axis. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* CK */ /* FRAMES */ /* GF */ /* IK */ /* KERNEL */ /* $ Keywords */ /* FOV */ /* GEOMETRY */ /* INSTRUMENT */ /* $ Declarations */ /* $ Brief_I/O */ /* VARIABLE I/O DESCRIPTION */ /* -------- --- -------------------------------------------------- */ /* MARGIN P Minimum complement of FOV cone angle. */ /* INST I Instrument name. */ /* N I Number of FOV boundary vectors. */ /* BOUNDS I FOV boundary vectors. */ /* AXIS O Instrument FOV axis vector. */ /* $ Detailed_Input */ /* INST is the name of an instrument with which the field of */ /* view (FOV) of interest is associated. This name is */ /* used only to generate long error messages. */ /* N is the number of boundary vectors in the array */ /* BOUNDS. */ /* BOUNDS is an array of N vectors emanating from a common */ /* vertex and defining the edges of a pyramidal region in */ /* three-dimensional space: this the region within the */ /* FOV of the instrument designated by INST. The Ith */ /* vector of BOUNDS resides in elements (1:3,I) of this */ /* array. */ /* The vectors contained in BOUNDS are called the */ /* "boundary vectors" of the FOV. */ /* The boundary vectors must satisfy the constraints: */ /* 1) The boundary vectors must be contained within */ /* a right circular cone of angular radius less */ /* than than (pi/2) - MARGIN radians; in other */ /* words, there must be a vector A such that all */ /* boundary vectors have angular separation from */ /* A of less than (pi/2)-MARGIN radians. */ /* 2) There must be a pair of vectors U, V in BOUNDS */ /* such that all other boundary vectors lie in */ /* the same half space bounded by the plane */ /* containing U and V. Furthermore, all other */ /* boundary vectors must have orthogonal */ /* projections onto a plane normal to this plane */ /* such that the projections have angular */ /* separation of at least 2*MARGIN radians from */ /* the plane spanned by U and V. */ /* Given the first constraint above, there is plane PL */ /* such that each of the set of rays extending the */ /* boundary vectors intersects PL. (In fact, there is an */ /* infinite set of such planes.) The boundary vectors */ /* must be ordered so that the set of line segments */ /* connecting the intercept on PL of the ray extending */ /* the Ith vector to that of the (I+1)st, with the Nth */ /* intercept connected to the first, form a polygon (the */ /* "FOV polygon") constituting the intersection of the */ /* FOV pyramid with PL. This polygon may wrap in either */ /* the positive or negative sense about a ray emanating */ /* from the FOV vertex and passing through the plane */ /* region bounded by the FOV polygon. */ /* The FOV polygon need not be convex; it may be */ /* self-intersecting as well. */ /* No pair of consecutive vectors in BOUNDS may be */ /* linearly dependent. */ /* The boundary vectors need not have unit length. */ /* $ Detailed_Output */ /* AXIS is a unit vector normal to a plane containing the */ /* FOV polygon. All boundary vectors have angular */ /* separation from AXIS of not more than */ /* ( pi/2 ) - MARGIN */ /* radians. */ /* This routine signals an error if it cannot find */ /* a satisfactory value of AXIS. */ /* $ Parameters */ /* MARGIN is a small positive number used to constrain the */ /* orientation of the boundary vectors. See the two */ /* constraints described in the Detailed_Input section */ /* above for specifics. */ /* $ Exceptions */ /* 1) In the input vector count N is not at least 3, the error */ /* SPICE(INVALIDCOUNT) is signaled. */ /* 2) If any pair of consecutive boundary vectors has cross */ /* product zero, the error SPICE(DEGENERATECASE) is signaled. */ /* For this test, the first vector is considered the successor */ /* of the Nth. */ /* 3) If this routine can't find a face of the convex hull of */ /* the set of boundary vectors such that this face satisfies */ /* constraint (2) of the Detailed_Input section above, the */ /* error SPICE(FACENOTFOUND) is signaled. */ /* 4) If any boundary vectors have longitude too close to 0 */ /* or too close to pi radians in the face frame (see discussion */ /* of the search algorithm's steps 3 and 4 in Particulars */ /* below), the respective errors SPICE(NOTSUPPORTED) or */ /* SPICE(FOVTOOWIDE) are signaled. */ /* 5) If any boundary vectors have angular separation of more than */ /* (pi/2)-MARGIN radians from the candidate FOV axis, the */ /* error SPICE(FOVTOOWIDE) is signaled. */ /* $ Files */ /* The boundary vectors input to this routine are typically */ /* obtained from an IK file. */ /* $ Particulars */ /* Normally implementation is not discussed in SPICE headers, but we */ /* make an exception here because this routine's implementation and */ /* specification are deeply intertwined. */ /* This routine first computes the average of the unitized input */ /* boundary vectors; if this vector satisfies the angular separation */ /* constraint (1) in Detailed_Input, a unit length copy of this */ /* vector is returned as the FOV axis. */ /* If the procedure above fails, an algorithm based on selection */ /* of a suitable face of the boundary vector's convex hull is tried. */ /* See the routine ZZHULLAX for details. */ /* If the second approach fails, an error is signaled. */ /* Note that it's easy to construct FOVs where the average of the */ /* boundary vectors doesn't yield a viable axis: a FOV of angular */ /* width nearly equal to pi radians, with a sufficiently large */ /* number of boundary vectors on one side and few boundary vectors */ /* on the other, is one such example. This routine can find an */ /* axis for many such intractable FOVs---that's why ZZHULLAX */ /* is called after the simple approach fails. */ /* $ Examples */ /* See SPICELIB private routine ZZGFFVIN. */ /* $ Restrictions */ /* 1) This is a SPICE private routine. User applications should not */ /* call this routine. */ /* 2) There may "reasonable" polygonal FOVs that cannot be handled */ /* by this routine. See the discussions in Detailed_Input, */ /* Exceptions, and Particulars above for restrictions on the */ /* input set of FOV boundary vectors. */ /* $ Literature_References */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* $ Version */ /* - SPICELIB Version 1.0.0, 05-MAR-2009 (NJB) */ /* -& */ /* SPICELIB functions */ /* Local parameters */ /* Local variables */ /* Parameter adjustments */ bounds_dim2 = *n; /* Function Body */ if (return_()) { return 0; } chkin_("ZZFOVAXI", (ftnlen)8); /* We must have at least 3 boundary vectors. */ if (*n < 3) { setmsg_("Polygonal FOV requires at least 3 boundary vectors but numb" "er supplied for # was #.", (ftnlen)83); errch_("#", inst, (ftnlen)1, inst_len); errint_("#", n, (ftnlen)1); sigerr_("SPICE(INVALIDCOUNT)", (ftnlen)19); chkout_("ZZFOVAXI", (ftnlen)8); return 0; } /* Check for linearly dependent consecutive boundary vectors. */ i__1 = *n; for (i__ = 1; i__ <= i__1; ++i__) { /* Set the index of the next ray. When we get to the */ /* last boundary vector, the next ray is the first. */ if (i__ == *n) { next = 1; } else { next = i__ + 1; } /* Find the cross product of the first ray with the */ /* second. Depending on the ordering of the boundary */ /* vectors, this could be an inward or outward normal, */ /* in the case the current face is is exterior. */ vcrss_(&bounds[(i__2 = i__ * 3 - 3) < bounds_dim2 * 3 && 0 <= i__2 ? i__2 : s_rnge("bounds", i__2, "zzfovaxi_", (ftnlen)313)], & bounds[(i__3 = next * 3 - 3) < bounds_dim2 * 3 && 0 <= i__3 ? i__3 : s_rnge("bounds", i__3, "zzfovaxi_", (ftnlen)313)], cp); /* We insist on consecutive boundary vectors being */ /* linearly independent. */ if (vzero_(cp)) { setmsg_("Polygonal FOV must have linearly independent consecutiv" "e boundary but vectors at indices # and # have cross pro" "duct equal to the zero vector. Instrument is #.", (ftnlen) 158); errint_("#", &i__, (ftnlen)1); errint_("#", &next, (ftnlen)1); errch_("#", inst, (ftnlen)1, inst_len); sigerr_("SPICE(DEGENERATECASE)", (ftnlen)21); chkout_("ZZFOVAXI", (ftnlen)8); return 0; } } /* First try the average of the FOV unit boundary vectors as */ /* a candidate axis. In many cases, this simple approach */ /* does the trick. */ cleard_(&c__3, axis); i__1 = *n; for (i__ = 1; i__ <= i__1; ++i__) { vhat_(&bounds[(i__2 = i__ * 3 - 3) < bounds_dim2 * 3 && 0 <= i__2 ? i__2 : s_rnge("bounds", i__2, "zzfovaxi_", (ftnlen)346)], uvec); vadd_(uvec, axis, v); vequ_(v, axis); } d__1 = 1. / *n; vsclip_(&d__1, axis); /* If each boundary vector has sufficiently small */ /* angular separation from AXIS, we're done. */ limit = halfpi_() - 1e-12; ok = TRUE_; i__ = 1; while(i__ <= *n && ok) { sep = vsep_(&bounds[(i__1 = i__ * 3 - 3) < bounds_dim2 * 3 && 0 <= i__1 ? i__1 : s_rnge("bounds", i__1, "zzfovaxi_", (ftnlen)365) ], axis); if (sep > limit) { ok = FALSE_; } else { ++i__; } } if (! ok) { /* See whether we can find an axis using a */ /* method based on finding a face of the convex */ /* hull of the FOV. ZZHULLAX signals an error */ /* if it doesn't succeed. */ zzhullax_(inst, n, bounds, axis, inst_len); if (failed_()) { chkout_("ZZFOVAXI", (ftnlen)8); return 0; } } /* At this point AXIS is valid. Make the axis vector unit length. */ vhatip_(axis); chkout_("ZZFOVAXI", (ftnlen)8); return 0; } /* zzfovaxi_ */
/* $Procedure INRYPL ( Intersection of ray and plane ) */ /* Subroutine */ int inrypl_(doublereal *vertex, doublereal *dir, doublereal * plane, integer *nxpts, doublereal *xpt) { /* System generated locals */ doublereal d__1, d__2; /* Local variables */ doublereal udir[3]; extern /* Subroutine */ int vhat_(doublereal *, doublereal *), vscl_( doublereal *, doublereal *, doublereal *); extern doublereal vdot_(doublereal *, doublereal *); extern /* Subroutine */ int vequ_(doublereal *, doublereal *); doublereal scale; extern /* Subroutine */ int chkin_(char *, ftnlen); extern doublereal dpmax_(void); extern /* Subroutine */ int vlcom_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); doublereal const__, prjvn; extern doublereal vnorm_(doublereal *); extern logical vzero_(doublereal *); extern /* Subroutine */ int pl2nvc_(doublereal *, doublereal *, doublereal *), cleard_(integer *, doublereal *); doublereal mscale, prjdif, sclcon, toobig, normal[3], prjdir; extern logical smsgnd_(doublereal *, doublereal *); extern /* Subroutine */ int sigerr_(char *, ftnlen), chkout_(char *, ftnlen), vsclip_(doublereal *, doublereal *), setmsg_(char *, ftnlen); extern logical return_(void); doublereal sclvtx[3]; /* $ Abstract */ /* Find the intersection of a ray and a plane. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* PLANES */ /* $ Keywords */ /* GEOMETRY */ /* $ Declarations */ /* $ Brief_I/O */ /* Variable I/O Description */ /* -------- --- -------------------------------------------------- */ /* VERTEX, */ /* DIR I Vertex and direction vector of ray. */ /* PLANE I A SPICELIB plane. */ /* NXPTS O Number of intersection points of ray and plane. */ /* XPT O Intersection point, if NXPTS = 1. */ /* $ Detailed_Input */ /* VERTEX, */ /* DIR are a point and direction vector that define a */ /* ray in three-dimensional space. */ /* PLANE is a SPICELIB plane. */ /* $ Detailed_Output */ /* NXPTS is the number of points of intersection of the */ /* input ray and plane. Values and meanings of */ /* NXPTS are: */ /* 0 No intersection. */ /* 1 One point of intersection. Note that */ /* this case may occur when the ray's */ /* vertex is in the plane. */ /* -1 An infinite number of points of */ /* intersection; the ray lies in the plane. */ /* XPT is the point of intersection of the input ray */ /* and plane, when there is exactly one point of */ /* intersection. Otherwise, XPT is the zero vector. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If the ray's direction vector is the zero vector, the error */ /* SPICE(ZEROVECTOR) is signaled. NXPTS and XPT are not */ /* modified. */ /* 2) If the ray's vertex is further than DPMAX() / 3 from the */ /* origin, the error SPICE(VECTORTOOBIG) is signaled. NXPTS */ /* and XPT are not modified. */ /* 3) If the input plane is s further than DPMAX() / 3 from the */ /* origin, the error SPICE(VECTORTOOBIG) is signaled. NXPTS */ /* and XPT are not modified. */ /* 4) The input plane should be created by one of the SPICELIB */ /* routines */ /* NVC2PL */ /* NVP2PL */ /* PSV2PL */ /* Invalid input planes will cause unpredictable results. */ /* 5) In the interest of good numerical behavior, in the case */ /* where the ray's vertex is not in the plane, this routine */ /* considers that an intersection of the ray and plane occurs */ /* only if the distance between the ray's vertex and the */ /* intersection point is less than DPMAX() / 3. */ /* If VERTEX is not in the plane and this condition is not */ /* met, then NXPTS is set to 0 and XPT is set to the zero */ /* vector. */ /* $ Files */ /* None. */ /* $ Particulars */ /* The intersection of a ray and plane in three-dimensional space */ /* can be a the empty set, a single point, or the ray itself. */ /* $ Examples */ /* 1) Find the camera projection of the center of an extended */ /* body. For simplicity, we assume: */ /* -- The camera has no distortion; the image of a point */ /* is determined by the intersection of the focal plane */ /* and the line determined by the point and the camera's */ /* focal point. */ /* -- The camera's pointing matrix (C-matrix) is available */ /* in a C-kernel. */ /* C */ /* C Load Leapseconds and SCLK kernels to support time */ /* C conversion. */ /* C */ /* CALL FURNSH ( 'LEAP.KER' ) */ /* CALL FURNSH ( 'SCLK.KER' ) */ /* C */ /* C Load an SPK file containing ephemeris data for */ /* C observer (a spacecraft, whose NAIF integer code */ /* C is SC) and target at the UTC epoch of observation. */ /* C */ /* CALL FURNSH ( 'SPK.BSP' ) */ /* C */ /* C Load a C-kernel containing camera pointing for */ /* C the UTC epoch of observation. */ /* C */ /* CALL FURNSH ( 'CK.BC' ) */ /* C */ /* C Find the ephemeris time (barycentric dynamical time) */ /* C and encoded spacecraft clock times corresponding to */ /* C the UTC epoch of observation. */ /* C */ /* CALL UTC2ET ( UTC, ET ) */ /* CALL SCE2C ( SC, ET, SCLKDP ) */ /* C */ /* C Encode the pointing lookup tolerance. */ /* C */ /* CALL SCTIKS ( SC, TOLCH, TOLDP ) */ /* C */ /* C Find the observer-target vector at the observation */ /* C epoch. In this example, we'll use a light-time */ /* C corrected state vector. */ /* C */ /* CALL SPKEZ ( TARGET, ET, 'J2000', 'LT', SC, */ /* . STATE, LT ) */ /* C */ /* C Look up camera pointing. */ /* C */ /* CALL CKGP ( CAMERA, SCLKDP, TOLDP, 'J2000', CMAT, */ /* . CLKOUT, FOUND ) */ /* IF ( .NOT. FOUND ) THEN */ /* [Handle this case...] */ /* END IF */ /* C */ /* C Negate the spacecraft-to-target body vector and */ /* C convert it to camera coordinates. */ /* C */ /* CALL VMINUS ( STATE, DIR ) */ /* CALL MXV ( CMAT, DIR, DIR ) */ /* C */ /* C If FL is the camera's focal length, the effective */ /* C focal point is */ /* C */ /* C FL * ( 0, 0, 1 ) */ /* C */ /* CALL VSCL ( FL, ZVEC, FOCUS ) */ /* C */ /* C The camera's focal plane contains the origin in */ /* C camera coordinates, and the z-vector is orthogonal */ /* C to the plane. Make a SPICELIB plane representing */ /* C the focal plane. */ /* C */ /* CALL NVC2PL ( ZVEC, 0.D0, FPLANE ) */ /* C */ /* C The image of the target body's center in the focal */ /* C plane is defined by the intersection with the focal */ /* C plane of the ray whose vertex is the focal point and */ /* C whose direction is DIR. */ /* C */ /* CALL INRYPL ( FOCUS, DIR, FPLANE, NXPTS, IMAGE ) */ /* IF ( NXPTS .EQ. 1 ) THEN */ /* C */ /* C The body center does project to the focal plane. */ /* C Check whether the image is actually in the */ /* C camera's field of view... */ /* C */ /* . */ /* . */ /* . */ /* ELSE */ /* C */ /* C The body center does not map to the focal plane. */ /* C Handle this case... */ /* C */ /* . */ /* . */ /* . */ /* END IF */ /* 2) Find the Saturn ring plane intercept of a spacecraft-mounted */ /* instrument's boresight vector. We want the find the point */ /* in the ring plane that will be observed by an instrument */ /* with a give boresight direction at a specified time. We */ /* must account for light time and stellar aberration in order */ /* to find this point. The intercept point will be expressed */ /* in Saturn body-fixed coordinates. */ /* In this example, we assume */ /* -- The ring plane is equatorial. */ /* -- Light travels in a straight line. */ /* -- The light time correction for the ring plane intercept */ /* can be obtained by performing three light-time */ /* correction iterations. If this assumption does not */ /* lead to a sufficiently accurate result, additional */ /* iterations can be performed. */ /* -- A Newtonian approximation of stellar aberration */ /* suffices. */ /* -- The boresight vector is given in J2000 coordinates. */ /* -- The observation epoch is ET ephemeris seconds past */ /* J2000. */ /* -- The boresight vector, spacecraft and planetary */ /* ephemerides, and ring plane orientation are all known */ /* with sufficient accuracy for the application. */ /* -- All necessary kernels are loaded by the caller of */ /* this example routine. */ /* SUBROUTINE RING_XPT ( SC, ET, BORVEC, SBFXPT, FOUND ) */ /* IMPLICIT NONE */ /* CHARACTER*(*) SC */ /* DOUBLE PRECISION ET */ /* DOUBLE PRECISION BORVEC ( 3 ) */ /* DOUBLE PRECISION SBFXPT ( 3 ) */ /* LOGICAL FOUND */ /* C */ /* C SPICELIB functions */ /* C */ /* DOUBLE PRECISION CLIGHT */ /* DOUBLE PRECISION VDIST */ /* C */ /* C Local parameters */ /* C */ /* INTEGER UBPL */ /* PARAMETER ( UBPL = 4 ) */ /* INTEGER SATURN */ /* PARAMETER ( SATURN = 699 ) */ /* C */ /* C Local variables */ /* C */ /* DOUBLE PRECISION BORV2 ( 3 ) */ /* DOUBLE PRECISION CORVEC ( 3 ) */ /* DOUBLE PRECISION LT */ /* DOUBLE PRECISION PLANE ( UBPL ) */ /* DOUBLE PRECISION SATSSB ( 6 ) */ /* DOUBLE PRECISION SCPOS ( 3 ) */ /* DOUBLE PRECISION SCSSB ( 6 ) */ /* DOUBLE PRECISION STATE ( 6 ) */ /* DOUBLE PRECISION STCORR ( 3 ) */ /* DOUBLE PRECISION TAU */ /* DOUBLE PRECISION TPMI ( 3, 3 ) */ /* DOUBLE PRECISION XPT ( 3 ) */ /* DOUBLE PRECISION ZVEC ( 3 ) */ /* INTEGER I */ /* INTEGER NXPTS */ /* INTEGER SCID */ /* LOGICAL FND */ /* C */ /* C First step: account for stellar aberration. Since the */ /* C instrument pointing is given, we need to find the intercept */ /* C point such that, when the stellar aberration correction is */ /* C applied to the vector from the spacecraft to that point, */ /* C the resulting vector is parallel to BORVEC. An easy */ /* C solution is to apply the inverse of the normal stellar */ /* C aberration correction to BORVEC, and then solve the */ /* C intercept problem with this corrected boresight vector. */ /* C */ /* C Find the position of the observer relative */ /* C to the solar system barycenter at ET. */ /* C */ /* CALL BODN2C ( SC, SCID, FND ) */ /* IF ( .NOT. FND ) THEN */ /* CALL SETMSG ( 'ID code for body # was not found.' ) */ /* CALL ERRCH ( '#', SC ) */ /* CALL SIGERR ( 'SPICE(NOTRANSLATION' ) */ /* RETURN */ /* END IF */ /* CALL SPKSSB ( SCID, ET, 'J2000', SCSSB ) */ /* C */ /* C We now wish to find the vector CORVEC that, when */ /* C corrected for stellar aberration, yields BORVEC. */ /* C A good first approximation is obtained by applying */ /* C the stellar aberration correction for transmission */ /* C to BORVEC. */ /* C */ /* CALL STLABX ( BORVEC, SCSSB(4), CORVEC ) */ /* C */ /* C The inverse of the stellar aberration correction */ /* C applicable to CORVEC should be a very good estimate of */ /* C the correction we need to apply to BORVEC. Apply */ /* C this correction to BORVEC to obtain an improved estimate */ /* C of CORVEC. */ /* C */ /* CALL STELAB ( CORVEC, SCSSB(4), BORV2 ) */ /* CALL VSUB ( BORV2, CORVEC, STCORR ) */ /* CALL VSUB ( BORVEC, STCORR, CORVEC ) */ /* C */ /* C Because the ring plane intercept may be quite far from */ /* C Saturn's center, we cannot assume light time from the */ /* C intercept to the observer is well approximated by */ /* C light time from Saturn's center to the observer. */ /* C We compute the light time explicitly using an iterative */ /* C approach. */ /* C */ /* C We can however use the light time from Saturn's center to */ /* C the observer to obtain a first estimate of the actual light */ /* C time. */ /* C */ /* CALL SPKEZR ( 'SATURN', ET, 'J2000', 'LT', SC, */ /* . STATE, LT ) */ /* TAU = LT */ /* C */ /* C Find the ring plane intercept and calculate the */ /* C light time from it to the spacecraft. */ /* C Perform three iterations. */ /* C */ /* I = 1 */ /* FOUND = .TRUE. */ /* DO WHILE ( ( I .LE. 3 ) .AND. ( FOUND ) ) */ /* C */ /* C Find the position of Saturn relative */ /* C to the solar system barycenter at ET-TAU. */ /* C */ /* CALL SPKSSB ( SATURN, ET-TAU, 'J2000', SATSSB ) */ /* C */ /* C Find the Saturn-to-observer vector defined by these */ /* C two position vectors. */ /* C */ /* CALL VSUB ( SCSSB, SATSSB, SCPOS ) */ /* C */ /* C Look up Saturn's pole at ET-TAU; this is the third */ /* C column of the matrix that transforms Saturn body-fixed */ /* C coordinates to J2000 coordinates. */ /* C */ /* CALL PXFORM ( 'IAU_SATURN', 'J2000', ET-TAU, TPMI ) */ /* CALL MOVED ( TPMI(1,3), 3, ZVEC ) */ /* C */ /* C Make a SPICELIB plane representing the ring plane. */ /* C We're treating Saturn's center as the origin, so */ /* C the plane constant is 0. */ /* C */ /* CALL NVC2PL ( ZVEC, 0.D0, PLANE ) */ /* C */ /* C Find the intersection of the ring plane and the */ /* C ray having vertex SCPOS and direction vector */ /* C CORVEC. */ /* C */ /* CALL INRYPL ( SCPOS, CORVEC, PLANE, NXPTS, XPT ) */ /* C */ /* C If the number of intersection points is 1, */ /* C find the next light time estimate. */ /* C */ /* IF ( NXPTS .EQ. 1 ) THEN */ /* C */ /* C Find the light time (zero-order) from the */ /* C intercept point to the spacecraft. */ /* C */ /* TAU = VDIST ( SCPOS, XPT ) / CLIGHT() */ /* I = I + 1 */ /* ELSE */ /* FOUND = .FALSE. */ /* END IF */ /* END DO */ /* C */ /* C At this point, if FOUND is .TRUE., we iterated */ /* C 3 times, and XPT is our estimate of the */ /* C position of the ring plane intercept point */ /* C relative to Saturn in the J2000 frame. This is the */ /* C point observed by an instrument pointed in direction */ /* C BORVEC at ET at mounted on the spacecraft SC. */ /* C */ /* C If FOUND is .FALSE., the boresight ray does not */ /* C intersect the ring plane. */ /* C */ /* C As a final step, transform XPT to Saturn body-fixed */ /* C coordinates. */ /* C */ /* IF ( FOUND ) THEN */ /* CALL MTXV ( TPMI, XPT, SBFXPT ) */ /* END IF */ /* END */ /* $ Restrictions */ /* None. */ /* $ Literature_References */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* W.L. Taber (JPL) */ /* $ Version */ /* - SPICELIB Version 1.1.1, 07-FEB-2008 (BVS) */ /* Fixed a few typos in the header. */ /* - SPICELIB Version 1.1.0, 02-SEP-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VSCL call. */ /* - SPICELIB Version 1.0.3, 12-DEC-2002 (NJB) */ /* Header fix: ring plane intercept algorithm was corrected. */ /* Now light time is computed accurately, and stellar aberration */ /* is accounted for. Example was turned into a complete */ /* subroutine. */ /* - SPICELIB Version 1.0.2, 09-MAR-1999 (NJB) */ /* Reference to SCE2T replaced by reference to SCE2C. An */ /* occurrence of ENDIF was replaced by END IF. */ /* - SPICELIB Version 1.0.1, 10-MAR-1992 (WLT) */ /* Comment section for permuted index source lines was added */ /* following the header. */ /* - SPICELIB Version 1.0.0, 01-APR-1991 (NJB) (WLT) */ /* -& */ /* $ Index_Entries */ /* intersection of ray and plane */ /* -& */ /* $ Revisions */ /* - SPICELIB Version 1.1.0, 02-SEP-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VSCL call. */ /* -& */ /* SPICELIB functions */ /* Local parameters */ /* Local variables */ /* Standard SPICE error handling. */ if (return_()) { return 0; } else { chkin_("INRYPL", (ftnlen)6); } /* We'll give the name TOOBIG to the bound DPMAX() / MARGIN. */ /* If we let VTXPRJ be the orthogonal projection of VERTEX onto */ /* PLANE, and let DIFF be the vector VTXPRJ - VERTEX, then */ /* we know that */ /* || DIFF || < 2 * TOOBIG */ /* Check the distance of the ray's vertex from the origin. */ toobig = dpmax_() / 3.; if (vnorm_(vertex) >= toobig) { setmsg_("Ray's vertex is too far from the origin.", (ftnlen)40); sigerr_("SPICE(VECTORTOOBIG)", (ftnlen)19); chkout_("INRYPL", (ftnlen)6); return 0; } /* Check the distance of the plane from the origin. (The returned */ /* plane constant IS this distance.) */ pl2nvc_(plane, normal, &const__); if (const__ >= toobig) { setmsg_("Plane is too far from the origin.", (ftnlen)33); sigerr_("SPICE(VECTORTOOBIG)", (ftnlen)19); chkout_("INRYPL", (ftnlen)6); return 0; } /* Check the ray's direction vector. */ vhat_(dir, udir); if (vzero_(udir)) { setmsg_("Ray's direction vector is the zero vector.", (ftnlen)42); sigerr_("SPICE(ZEROVECTOR)", (ftnlen)17); chkout_("INRYPL", (ftnlen)6); return 0; } /* That takes care of the error cases. Now scale the input vertex */ /* and plane to improve numerical behavior. */ /* Computing MAX */ d__1 = const__, d__2 = vnorm_(vertex); mscale = max(d__1,d__2); if (mscale != 0.) { d__1 = 1. / mscale; vscl_(&d__1, vertex, sclvtx); sclcon = const__ / mscale; } else { vequ_(vertex, sclvtx); sclcon = const__; } if (mscale > 1.) { toobig /= mscale; } /* Find the projection (coefficient) of the ray's vertex along the */ /* plane's normal direction. */ prjvn = vdot_(sclvtx, normal); /* If this projection is the plane constant, the ray's vertex lies in */ /* the plane. We have one intersection or an infinite number of */ /* intersections. It all depends on whether the ray actually lies */ /* in the plane. */ /* The absolute value of PRJDIF is the distance of the ray's vertex */ /* from the plane. */ prjdif = sclcon - prjvn; if (prjdif == 0.) { /* XPT is the original, unscaled vertex. */ vequ_(vertex, xpt); if (vdot_(normal, udir) == 0.) { /* The ray's in the plane. */ *nxpts = -1; } else { *nxpts = 1; } chkout_("INRYPL", (ftnlen)6); return 0; } /* Ok, the ray's vertex is not in the plane. The ray may still be */ /* parallel to or may point away from the plane. If the ray does */ /* point towards the plane, mathematicians would say that the */ /* ray does intersect the plane, but the computer may disagree. */ /* For this routine to find an intersection, both of the following */ /* conditions must be met: */ /* -- The ray must point toward the plane; this happens when */ /* PRJDIF has the same sign as < UDIR, NORMAL >. */ /* -- The vector difference XPT - SCLVTX must not overflow. */ /* Qualitatively, the case of interest looks something like the */ /* picture below: */ /* * SCLVTX */ /* |\ */ /* | \ <-- UDIR */ /* | \ */ /* length of this | \| */ /* segment is | -* */ /* | */ /* | PRJDIF | --> | ___________________________ */ /* |/ / */ /* | * / <-- PLANE */ /* /| XPT / */ /* / ^ / */ /* / | NORMAL / */ /* / | . / */ /* / |/| / */ /* / .---| / / */ /* / | |/ / */ /* / `---* / */ /* / Projection of SCLVTX onto the plane */ /* / / */ /* / / */ /* ---------------------------- */ /* Find the projection of the direction vector along the plane's */ /* normal vector. */ prjdir = vdot_(udir, normal); /* We're done if the ray doesn't point toward the plane. PRJDIF */ /* has already been found to be non-zero at this point; PRJDIR is */ /* zero if the ray and plane are parallel. The SPICELIB routine */ /* SMSGND will return a value of .FALSE. if PRJDIR is zero. */ if (! smsgnd_(&prjdir, &prjdif)) { /* The ray is parallel to or points away from the plane. */ *nxpts = 0; cleard_(&c__3, xpt); chkout_("INRYPL", (ftnlen)6); return 0; } /* The difference XPT - SCLVTX is the hypotenuse of a right triangle */ /* formed by SCLVTX, XPT, and the orthogonal projection of SCLVTX */ /* onto the plane. We'll obtain the hypotenuse by scaling UDIR. */ /* We must make sure that this hypotenuse does not overflow. The */ /* scale factor has magnitude */ /* | PRJDIF | */ /* -------------- */ /* | PRJDIR | */ /* and UDIR is a unit vector, so as long as */ /* | PRJDIF | < | PRJDIR | * TOOBIG */ /* the hypotenuse is no longer than TOOBIG. The product can be */ /* computed safely since PRJDIR has magnitude 1 or less. */ if (abs(prjdif) >= abs(prjdir) * toobig) { /* If the hypotenuse is too long, we say that no intersection */ /* exists. */ *nxpts = 0; cleard_(&c__3, xpt); chkout_("INRYPL", (ftnlen)6); return 0; } /* We conclude that it's safe to compute XPT. Scale UDIR and add */ /* the result to SCLVTX. The addition is safe because both addends */ /* have magnitude no larger than TOOBIG. The vector thus obtained */ /* is the intersection point. */ *nxpts = 1; scale = abs(prjdif) / abs(prjdir); vlcom_(&c_b17, sclvtx, &scale, udir, xpt); /* Re-scale XPT. This is safe, since TOOBIG has already been */ /* scaled to allow for any growth of XPT at this step. */ vsclip_(&mscale, xpt); chkout_("INRYPL", (ftnlen)6); return 0; } /* inrypl_ */
/* $Procedure DVNORM ( Derivative of vector norm ) */ doublereal dvnorm_(doublereal *state) { /* System generated locals */ doublereal ret_val; /* Local variables */ extern /* Subroutine */ int vhat_(doublereal *, doublereal *); doublereal xhat[3]; extern doublereal vdot_(doublereal *, doublereal *), vnorm_(doublereal *); /* $ Abstract */ /* Function to calculate the derivative of the norm of a 3-vector. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* None. */ /* $ Keywords */ /* DERIVATIVE */ /* MATH */ /* VECTOR */ /* $ Declarations */ /* $ Brief_I/O */ /* VARIABLE I/O DESCRIPTION */ /* -------- --- -------------------------------------------------- */ /* STATE I A 6-vector composed of three coordinates and their */ /* derivatives. */ /* $ Detailed_Input */ /* STATE A double precision 6-vector, the second three */ /* components being the derivatives of the first three */ /* with respect to some scalar. */ /* STATE = ( x, dx ) */ /* -- */ /* ds */ /* A common form for STATE would contain position and */ /* velocity. */ /* $ Detailed_Output */ /* DVNORM The value of d||x|| corresponding to STATE. */ /* ------ */ /* ds */ /* 1/2 2 2 2 1/2 */ /* where ||x|| = < x, x > = ( x1 + x2 + x3 ) */ /* v = ( dx1, dx2, dx3 ) */ /* --- --- --- */ /* ds ds ds */ /* d||x|| < x, v > */ /* ------ = ------ = < xhat, v > */ /* ds 1/2 */ /* < x, x > */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* None. */ /* $ Files */ /* None. */ /* $ Particulars */ /* A common use for this routine is to calculate the time derivative */ /* of the radius corresponding to a state vector. */ /* $ Examples */ /* Any numerical results shown for this example may differ between */ /* platforms as the results depend on the SPICE kernels used as input */ /* and the machine specific arithmetic implementation. */ /* PROGRAM DVNORM_T */ /* IMPLICIT NONE */ /* DOUBLE PRECISION X (3) */ /* DOUBLE PRECISION MAG (3) */ /* DOUBLE PRECISION DVMAG (3) */ /* DOUBLE PRECISION Y (6) */ /* DOUBLE PRECISION DVNORM */ /* C */ /* C Create several 6-vectors (6x1 arrays) with the structure */ /* C */ /* C s = | x | */ /* C | | */ /* C | dx | */ /* C | -- | */ /* C | ds | */ /* C */ /* C where 'x' is a 3-vector (3x1 array). */ /* C */ /* C */ /* C Create 's' with 'x' of varying magnitudes. Use 'x' */ /* C and '-x' to define the derivative as parallel and */ /* C anti-parallel. */ /* C */ /* MAG(1) = -4.D0 */ /* MAG(2) = 4.D0 */ /* MAG(3) = 12.D0 */ /* X(1) = 1.D0 */ /* X(2) = DSQRT( 2.D0 ) */ /* X(3) = DSQRT( 3.D0 ) */ /* C */ /* C Parallel... */ /* C */ /* Y(1) = X(1) * 10.D0**MAG(1) */ /* Y(2) = X(2) * 10.D0**MAG(1) */ /* Y(3) = X(3) * 10.D0**MAG(1) */ /* Y(4) = X(1) */ /* Y(5) = X(2) */ /* Y(6) = X(3) */ /* WRITE(*,*) 'Parallel x, dx/ds : ', DVNORM( Y ) */ /* C */ /* C ... anti-parallel... */ /* C */ /* Y(1) = X(1) * 10.D0**MAG(2) */ /* Y(2) = X(2) * 10.D0**MAG(2) */ /* Y(3) = X(3) * 10.D0**MAG(2) */ /* Y(4) = -X(1) */ /* Y(5) = -X(2) */ /* Y(6) = -X(3) */ /* WRITE(*,*) 'Anti-parallel x, dx/ds : ', DVNORM( Y ) */ /* C */ /* C ... 'x' zero vector */ /* C */ /* Y(1) = 0.D0 */ /* Y(2) = 0.D0 */ /* Y(3) = 0.D0 */ /* Y(4) = X(1) * 10.D0**MAG(3) */ /* Y(5) = X(2) * 10.D0**MAG(3) */ /* Y(6) = X(3) * 10.D0**MAG(3) */ /* WRITE(*,*) 'Zero vector x, large dx/ds: ', DVNORM( Y ) */ /* END */ /* The program outputs: */ /* Parallel x, dx/ds : 2.44948974 */ /* Anti-parallel x, dx/ds : -2.44948974 */ /* Zero vector x, large dx/ds: 0. */ /* $ Restrictions */ /* Error free. */ /* 1) If the first three components of STATE ("x") describes the */ /* origin (zero vector) the routine returns zero as the */ /* derivative of the vector norm. */ /* $ Literature_References */ /* None. */ /* $ Author_and_Institution */ /* Ed Wright (JPL) */ /* $ Version */ /* - SPICELIB Version 1.0.0, 03-MAY-2010 (EDW) */ /* -& */ /* $ Index_Entries */ /* derivative of 3-vector norm */ /* -& */ /* SPICELIB functions. */ /* Local Variables. */ /* If "x" describes the zero vector, return zero as the derivative */ /* of the vector norm. */ if (vnorm_(state) == 0.) { ret_val = 0.; return ret_val; } /* Construct a unit vector from the x vector data */ /* in STATE. */ vhat_(state, xhat); /* Project the velocity components onto the XHAT vector. */ /* d ||x|| x */ /* ------- = v . ----- */ /* ds ||x|| */ ret_val = vdot_(&state[3], xhat); return ret_val; } /* dvnorm_ */
/* $Procedure SPKW15 ( SPK, write a type 15 segment ) */ /* Subroutine */ int spkw15_(integer *handle, integer *body, integer *center, char *frame, doublereal *first, doublereal *last, char *segid, doublereal *epoch, doublereal *tp, doublereal *pa, doublereal *p, doublereal *ecc, doublereal *j2flg, doublereal *pv, doublereal *gm, doublereal *j2, doublereal *radius, ftnlen frame_len, ftnlen segid_len) { /* System generated locals */ integer i__1; /* Local variables */ extern /* Subroutine */ int vhat_(doublereal *, doublereal *); doublereal mypa[3]; extern doublereal vdot_(doublereal *, doublereal *), vsep_(doublereal *, doublereal *); extern /* Subroutine */ int vequ_(doublereal *, doublereal *); doublereal mytp[3]; integer i__; doublereal angle; extern /* Subroutine */ int chkin_(char *, ftnlen); doublereal descr[5]; integer value; extern /* Subroutine */ int errdp_(char *, doublereal *, ftnlen); extern logical vzero_(doublereal *); extern /* Subroutine */ int dafada_(doublereal *, integer *), dafbna_( integer *, doublereal *, char *, ftnlen), dafena_(void); extern logical failed_(void); doublereal record[16]; extern integer lastnb_(char *, ftnlen); extern /* Subroutine */ int sigerr_(char *, ftnlen), chkout_(char *, ftnlen), setmsg_(char *, ftnlen), errint_(char *, integer *, ftnlen), spkpds_(integer *, integer *, char *, integer *, doublereal *, doublereal *, doublereal *, ftnlen); extern logical return_(void); extern doublereal dpr_(void); doublereal dot; /* $ Abstract */ /* Write an SPK segment of type 15 given a type 15 data record. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* SPK */ /* $ Keywords */ /* EPHEMERIS */ /* $ Declarations */ /* $ Brief_I/O */ /* Variable I/O Description */ /* -------- --- -------------------------------------------------- */ /* HANDLE I Handle of an SPK file open for writing. */ /* BODY I Body code for ephemeris object. */ /* CENTER I Body code for the center of motion of the body. */ /* FRAME I The reference frame of the states. */ /* FIRST I First valid time for which states can be computed. */ /* LAST I Last valid time for which states can be computed. */ /* SEGID I Segment identifier. */ /* EPOCH I Epoch of the periapse. */ /* TP I Trajectory pole vector. */ /* PA I Periapsis vector. */ /* P I Semi-latus rectum. */ /* ECC I Eccentricity. */ /* J2FLG I J2 processing flag. */ /* PV I Central body pole vector. */ /* GM I Central body GM. */ /* J2 I Central body J2. */ /* RADIUS I Equatorial radius of central body. */ /* $ Detailed_Input */ /* HANDLE is the file handle of an SPK file that has been */ /* opened for writing. */ /* BODY is the NAIF ID for the body whose states are */ /* to be recorded in an SPK file. */ /* CENTER is the NAIF ID for the center of motion associated */ /* with BODY. */ /* FRAME is the reference frame that states are referenced to, */ /* for example 'J2000'. */ /* FIRST are the bounds on the ephemeris times, expressed as */ /* LAST seconds past J2000. */ /* SEGID is the segment identifier. An SPK segment identifier */ /* may contain up to 40 characters. */ /* EPOCH is the epoch of the orbit elements at periapse */ /* in ephemeris seconds past J2000. */ /* TP is a vector parallel to the angular momentum vector */ /* of the orbit at epoch expressed relative to FRAME. A */ /* unit vector parallel to TP will be stored in the */ /* output segment. */ /* PA is a vector parallel to the position vector of the */ /* trajectory at periapsis of EPOCH expressed relative */ /* to FRAME. A unit vector parallel to PA will be */ /* stored in the output segment. */ /* P is the semi-latus rectum--- p in the equation: */ /* r = p/(1 + ECC*COS(Nu)) */ /* ECC is the eccentricity. */ /* J2FLG is the J2 processing flag describing what J2 */ /* corrections are to be applied when the orbit is */ /* propagated. */ /* All J2 corrections are applied if the value of J2FLG */ /* is not 1, 2 or 3. */ /* If the value of the flag is 3 no corrections are */ /* done. */ /* If the value of the flag is 1 no corrections are */ /* computed for the precession of the line of apsides. */ /* However, regression of the line of nodes is */ /* performed. */ /* If the value of the flag is 2 no corrections are */ /* done for the regression of the line of nodes. */ /* However, precession of the line of apsides is */ /* performed. */ /* Note that J2 effects are computed only if the orbit */ /* is elliptic and does not intersect the central body. */ /* PV is a vector parallel to the north pole vector of the */ /* central body expressed relative to FRAME. A unit */ /* vector parallel to PV will be stored in the output */ /* segment. */ /* GM is the central body GM. */ /* J2 is the central body J2 (dimensionless). */ /* RADIUS is the equatorial radius of the central body. */ /* Units are radians, km, seconds. */ /* $ Detailed_Output */ /* None. A type 15 segment is written to the file attached */ /* to HANDLE. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If the eccentricity is less than zero, the error */ /* 'SPICE(BADECCENTRICITY)' will be signaled. */ /* 2) If the semi-latus rectum is 0, the error */ /* 'SPICE(BADLATUSRECTUM)' is signaled. */ /* 3) If the pole vector, trajectory pole vector or periapsis vector */ /* have zero length, the error 'SPICE(BADVECTOR)' is signaled. */ /* 4) If the trajectory pole vector and the periapsis vector are */ /* not orthogonal, the error 'SPICE(BADINITSTATE)' is signaled. */ /* The test for orthogonality is very crude. The routine simply */ /* checks that the dot product of the unit vectors parallel */ /* to the trajectory pole and periapse vectors is less than */ /* 0.00001. This check is intended to catch blunders, not to */ /* enforce orthogonality to double precision capacity. */ /* 5) If the mass of the central body is non-positive, the error */ /* 'SPICE(NONPOSITIVEMASS)' is signaled. */ /* 6) If the radius of the central body is negative, the error */ /* 'SPICE(BADRADIUS)' is signaled. */ /* 7) If the segment identifier has more than 40 non-blank characters */ /* the error 'SPICE(SEGIDTOOLONG)' is signaled. */ /* 8) If the segment identifier contains non-printing characters */ /* the error 'SPICE(NONPRINTABLECHARS)' is signaled. */ /* 9) If there are inconsistencies in the BODY, CENTER, FRAME or */ /* FIRST and LAST times, the problem will be diagnosed by */ /* a routine in the call tree of this routine. */ /* $ Files */ /* A new type 15 SPK segment is written to the SPK file attached */ /* to HANDLE. */ /* $ Particulars */ /* This routine writes an SPK type 15 data segment to the open SPK */ /* file according to the format described in the type 15 section of */ /* the SPK Required Reading. The SPK file must have been opened with */ /* write access. */ /* This routine is provided to provide direct support for the MASL */ /* precessing orbit formulation. */ /* $ Examples */ /* Suppose that at time EPOCH you have the J2000 periapsis */ /* state of some object relative to some central body and would */ /* like to create a type 15 SPK segment to model the motion of */ /* the object using simple regression and precession of the */ /* line of nodes and apsides. The following code fragment */ /* illustrates how you can prepare such a segment. We shall */ /* assume that you have in hand the J2000 direction of the */ /* central body's pole vector, its GM, J2 and equatorial */ /* radius. In addition we assume that you have opened an SPK */ /* file for write access and that it is attached to HANDLE. */ /* (If your state is at an epoch other than periapse the */ /* fragment below will NOT produce a "correct" type 15 segment */ /* for modeling the motion of your object.) */ /* C */ /* C First we get the osculating elements. */ /* C */ /* CALL OSCELT ( STATE, EPOCH, GM, ELTS ) */ /* C */ /* C From these collect the eccentricity and semi-latus rectum. */ /* C */ /* ECC = ELTS ( 2 ) */ /* P = ELTS ( 1 ) * ( 1.0D0 + ECC ) */ /* C */ /* C Next get the trajectory pole vector and the */ /* C periapsis vector. */ /* C */ /* CALL UCRSS ( STATE(1), STATE(4), TP ) */ /* CALL VHAT ( STATE(1), PA ) */ /* C */ /* C Enable both J2 corrections. */ /* C */ /* J2FLG = 0.0D0 */ /* C */ /* C Now add the segment. */ /* C */ /* CALL SPKW15 ( HANDLE, BODY, CENTER, FRAME, FIRST, LAST, */ /* . SEGID, EPOCH, TP, PA, P, ECC, */ /* . J2FLG, PV, GM, J2, RADIUS ) */ /* $ Restrictions */ /* None. */ /* $ Literature_References */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* W.L. Taber (JPL) */ /* $ Version */ /* - SPICELIB Version 2.0.0, 29-MAY-2012 (NJB) */ /* Input vectors that nominally have unit length */ /* are mapped to local copies that actually do */ /* have unit length. The applicable inputs are TP, PA, */ /* and PV. The Detailed Input header section was updated */ /* to reflect the change. */ /* Some typos in error messages were corrected. */ /* - SPICELIB Version 1.0.0, 28-NOV-1994 (WLT) */ /* -& */ /* $ Index_Entries */ /* Write a type 15 spk segment */ /* -& */ /* SPICELIB Functions */ /* Local Variables */ /* Segment descriptor size */ /* Segment identifier size */ /* SPK data type */ /* Range of printing characters */ /* Number of items in a segment */ /* Standard SPICE error handling. */ if (return_()) { return 0; } chkin_("SPKW15", (ftnlen)6); /* Fetch the various entities from the inputs and put them into */ /* the data record, first the epoch. */ record[0] = *epoch; /* Convert TP and PA to unit vectors. */ vhat_(pa, mypa); vhat_(tp, mytp); /* The trajectory pole vector. */ vequ_(mytp, &record[1]); /* The periapsis vector. */ vequ_(mypa, &record[4]); /* Semi-latus rectum ( P in the P/(1 + ECC*COS(Nu) ), */ /* and eccentricity. */ record[7] = *p; record[8] = *ecc; /* J2 processing flag. */ record[9] = *j2flg; /* Central body pole vector. */ vhat_(pv, &record[10]); /* The central mass, J2 and radius of the central body. */ record[13] = *gm; record[14] = *j2; record[15] = *radius; /* Check all the inputs here for obvious failures. It's much */ /* better to check them now and quit than it is to get a bogus */ /* segment into an SPK file and diagnose it later. */ if (*p <= 0.) { setmsg_("The semi-latus rectum supplied to the SPK type 15 evaluator" " was non-positive. This value must be positive. The value s" "upplied was #.", (ftnlen)133); errdp_("#", p, (ftnlen)1); sigerr_("SPICE(BADLATUSRECTUM)", (ftnlen)21); chkout_("SPKW15", (ftnlen)6); return 0; } else if (*ecc < 0.) { setmsg_("The eccentricity supplied for a type 15 segment is negative" ". It must be non-negative. The value supplied to the type 1" "5 evaluator was #. ", (ftnlen)138); errdp_("#", ecc, (ftnlen)1); sigerr_("SPICE(BADECCENTRICITY)", (ftnlen)22); chkout_("SPKW15", (ftnlen)6); return 0; } else if (*gm <= 0.) { setmsg_("The mass supplied for the central body of a type 15 segment" " was non-positive. Masses must be positive. The value suppl" "ied was #. ", (ftnlen)130); errdp_("#", gm, (ftnlen)1); sigerr_("SPICE(NONPOSITIVEMASS)", (ftnlen)22); chkout_("SPKW15", (ftnlen)6); return 0; } else if (vzero_(tp)) { setmsg_("The trajectory pole vector supplied to SPKW15 had length ze" "ro. The most likely cause of this problem is an uninitialize" "d vector.", (ftnlen)128); sigerr_("SPICE(BADVECTOR)", (ftnlen)16); chkout_("SPKW15", (ftnlen)6); return 0; } else if (vzero_(pa)) { setmsg_("The periapse vector supplied to SPKW15 had length zero. The" " most likely cause of this problem is an uninitialized vecto" "r.", (ftnlen)121); sigerr_("SPICE(BADVECTOR)", (ftnlen)16); chkout_("SPKW15", (ftnlen)6); return 0; } else if (vzero_(pv)) { setmsg_("The central pole vector supplied to SPKW15 had length zero." " The most likely cause of this problem is an uninitialized v" "ector. ", (ftnlen)126); sigerr_("SPICE(BADVECTOR)", (ftnlen)16); chkout_("SPKW15", (ftnlen)6); return 0; } else if (*radius < 0.) { setmsg_("The central body radius was negative. It must be zero or po" "sitive. The value supplied was #. ", (ftnlen)94); errdp_("#", radius, (ftnlen)1); sigerr_("SPICE(BADRADIUS)", (ftnlen)16); chkout_("SPKW15", (ftnlen)6); return 0; } /* One final check. Make sure the pole and periapse vectors are */ /* orthogonal. (We will use a very crude check but this should */ /* rule out any obvious errors.) */ dot = vdot_(mypa, mytp); if (abs(dot) > 1e-5) { angle = vsep_(pa, tp) * dpr_(); setmsg_("The periapsis and trajectory pole vectors are not orthogona" "l. The angle between them is # degrees. ", (ftnlen)99); errdp_("#", &angle, (ftnlen)1); sigerr_("SPICE(BADINITSTATE)", (ftnlen)19); chkout_("SPKW15", (ftnlen)6); return 0; } /* Make sure the segment identifier is not too long. */ if (lastnb_(segid, segid_len) > 40) { setmsg_("Segment identifier contains more than 40 characters.", ( ftnlen)52); sigerr_("SPICE(SEGIDTOOLONG)", (ftnlen)19); chkout_("SPKW15", (ftnlen)6); return 0; } /* Make sure it has only printing characters. */ i__1 = lastnb_(segid, segid_len); for (i__ = 1; i__ <= i__1; ++i__) { value = *(unsigned char *)&segid[i__ - 1]; if (value < 32 || value > 126) { setmsg_("The segment identifier contains the nonprintable charac" "ter having ascii code #.", (ftnlen)79); errint_("#", &value, (ftnlen)1); sigerr_("SPICE(NONPRINTABLECHARS)", (ftnlen)24); chkout_("SPKW15", (ftnlen)6); return 0; } } /* All of the obvious checks have been performed on the input */ /* record. Create the segment descriptor. (FIRST and LAST are */ /* checked by SPKPDS as well as consistency between BODY and CENTER). */ spkpds_(body, center, frame, &c__15, first, last, descr, frame_len); if (failed_()) { chkout_("SPKW15", (ftnlen)6); return 0; } /* Begin a new segment. */ dafbna_(handle, descr, segid, segid_len); if (failed_()) { chkout_("SPKW15", (ftnlen)6); return 0; } dafada_(record, &c__16); if (! failed_()) { dafena_(); } chkout_("SPKW15", (ftnlen)6); return 0; } /* spkw15_ */