/* $Procedure ZZSPKZP0 ( S/P Kernel, easy position ) */ /* Subroutine */ int zzspkzp0_(integer *targ, doublereal *et, char *ref, char *abcorr, integer *obs, doublereal *ptarg, doublereal *lt, ftnlen ref_len, ftnlen abcorr_len) { /* Initialized data */ static logical first = TRUE_; /* System generated locals */ doublereal d__1; /* Local variables */ static integer fj2000; extern /* Subroutine */ int zzrefch0_(integer *, integer *, doublereal *, doublereal *), zzspkpa0_(integer *, doublereal *, char *, doublereal *, char *, doublereal *, doublereal *, ftnlen, ftnlen); static doublereal temp[3], sobs[6]; extern /* Subroutine */ int zzspkgp0_(integer *, doublereal *, char *, integer *, doublereal *, doublereal *, ftnlen), zzspksb0_(integer *, doublereal *, char *, doublereal *, ftnlen); static integer type__; static logical xmit; static integer i__; extern /* Subroutine */ int chkin_(char *, ftnlen); extern logical eqchr_(char *, char *, ftnlen, ftnlen); extern /* Subroutine */ int errch_(char *, char *, ftnlen, ftnlen); static logical found; extern integer ltrim_(char *, ftnlen); static doublereal xform[9] /* was [3][3] */; extern logical eqstr_(char *, char *, ftnlen, ftnlen); static doublereal postn[3]; extern logical failed_(void); static integer center; extern /* Subroutine */ int namfrm_(char *, integer *, ftnlen), frinfo_( integer *, integer *, integer *, integer *, logical *); static doublereal ltcent; extern /* Subroutine */ int sigerr_(char *, ftnlen); static integer reqfrm, typeid; extern /* Subroutine */ int chkout_(char *, ftnlen), setmsg_(char *, ftnlen); extern logical return_(void); extern /* Subroutine */ int mxv_(doublereal *, 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 position 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 */ /* NAIF_IDS */ /* FRAMES */ /* TIME */ /* $ Keywords */ /* EPHEMERIS */ /* $ Declarations */ /* $ Abstract */ /* The parameters below form an enumerated list of the recognized */ /* frame types. They are: INERTL, PCK, CK, TK, DYN. The meanings */ /* are outlined below. */ /* $ 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 */ /* INERTL an inertial frame that is listed in the routine */ /* CHGIRF and that requires no external file to */ /* compute the transformation from or to any other */ /* inertial frame. */ /* PCK is a frame that is specified relative to some */ /* INERTL frame and that has an IAU model that */ /* may be retrieved from the PCK system via a call */ /* to the routine TISBOD. */ /* CK is a frame defined by a C-kernel. */ /* TK is a "text kernel" frame. These frames are offset */ /* from their associated "relative" frames by a */ /* constant rotation. */ /* DYN is a "dynamic" frame. These currently are */ /* parameterized, built-in frames where the full frame */ /* definition depends on parameters supplied via a */ /* frame kernel. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* W.L. Taber (JPL) */ /* $ Literature_References */ /* None. */ /* $ Version */ /* - SPICELIB Version 3.0.0, 28-MAY-2004 (NJB) */ /* The parameter DYN was added to support the dynamic frame class. */ /* - SPICELIB Version 2.0.0, 12-DEC-1996 (WLT) */ /* Various unused frames types were removed and the */ /* frame time TK was added. */ /* - SPICELIB Version 1.0.0, 10-DEC-1995 (WLT) */ /* -& */ /* $ Brief_I/O */ /* Variable I/O Description */ /* -------- --- -------------------------------------------------- */ /* TARG I Target body NAIF ID code. */ /* ET I Observer epoch. */ /* REF I Reference frame of output position vector. */ /* ABCORR I Aberration correction flag. */ /* OBS I Observing body NAIF ID code. */ /* PTARG O Position of target. */ /* LT O One way light time between observer and target. */ /* $ Detailed_Input */ /* TARG is the NAIF ID code for a target body. The target */ /* and observer define a position vector which points */ /* from the observer to the target. */ /* ET is the ephemeris time, expressed as seconds past */ /* J2000 TDB, at which the position of the target body */ /* relative to the observer is to be computed. ET */ /* refers to time at the observer's location. */ /* REF is the name of the reference frame relative to which */ /* the output position vector should be expressed. This */ /* may be any frame supported by the SPICE system, */ /* including built-in frames (documented in the Frames */ /* Required Reading) and frames defined by a loaded */ /* frame kernel (FK). */ /* When REF designates a non-inertial frame, the */ /* orientation of the frame is evaluated at an epoch */ /* dependent on the selected aberration correction. See */ /* the description of the output position vector PTARG */ /* for details. */ /* ABCORR indicates the aberration corrections to be applied to */ /* the position of the target body to account for */ /* one-way light time and stellar aberration. See the */ /* discussion in the Particulars section for */ /* recommendations on how to choose aberration */ /* corrections. */ /* ABCORR may be any of the following: */ /* 'NONE' Apply no correction. Return the */ /* geometric position of the target body */ /* relative to the observer. */ /* The following values of ABCORR apply to the */ /* "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: */ /* 'LT' Correct for one-way light time (also */ /* called "planetary aberration") using a */ /* Newtonian formulation. This correction */ /* yields the position of the target at */ /* the moment it emitted photons arriving */ /* at the observer at ET. */ /* The light time correction uses an */ /* iterative solution of the light time */ /* equation (see Particulars for details). */ /* The solution invoked by the 'LT' option */ /* uses one iteration. */ /* 'LT+S' Correct for one-way light time and */ /* stellar aberration using a Newtonian */ /* formulation. This option modifies the */ /* position obtained with the 'LT' option */ /* to account for the observer's velocity */ /* relative to the solar system */ /* barycenter. The result is the apparent */ /* position of the target---the position */ /* as seen by the observer. */ /* 'CN' Converged Newtonian light time */ /* correction. In solving the light time */ /* equation, the 'CN' correction iterates */ /* until the solution converges (three */ /* iterations on all supported platforms). */ /* The 'CN' correction typically does not */ /* substantially improve accuracy because */ /* the errors made by ignoring */ /* relativistic effects may be larger than */ /* the improvement afforded by obtaining */ /* convergence of the light time solution. */ /* The 'CN' correction computation also */ /* requires a significantly greater number */ /* of CPU cycles than does the */ /* one-iteration light time correction. */ /* 'CN+S' Converged Newtonian light time */ /* and stellar aberration corrections. */ /* The following values of ABCORR apply to the */ /* "transmission" case in which photons *depart* from */ /* the observer's location at ET and arrive at the */ /* target's location at the light-time corrected epoch */ /* ET+LT: */ /* 'XLT' "Transmission" case: correct for */ /* one-way light time using a Newtonian */ /* formulation. This correction yields the */ /* position of the target at the moment it */ /* receives photons emitted from the */ /* observer's location at ET. */ /* 'XLT+S' "Transmission" case: correct for */ /* one-way light time and stellar */ /* aberration using a Newtonian */ /* formulation This option modifies the */ /* position obtained with the 'XLT' option */ /* to account for the observer's velocity */ /* relative to the solar system */ /* barycenter. The position component of */ /* the computed target position indicates */ /* the direction that photons emitted from */ /* the observer's location must be "aimed" */ /* to hit the target. */ /* 'XCN' "Transmission" case: converged */ /* Newtonian light time correction. */ /* 'XCN+S' "Transmission" case: converged */ /* Newtonian light time and stellar */ /* aberration corrections. */ /* Neither special nor general relativistic effects are */ /* accounted for in the aberration corrections applied */ /* by this routine. */ /* Case and blanks are not significant in the string */ /* ABCORR. */ /* OBS is the NAIF ID code for the observing body. */ /* $ Detailed_Output */ /* PTARG is a Cartesian 3-vector representing the position of */ /* the target body relative to the specified observer. */ /* PTARG is corrected for the specified aberrations, and */ /* is expressed with respect to the reference frame */ /* specified by REF. The three components of PTARG */ /* represent the x-, y- and z-components of the target's */ /* position. */ /* PTARG points from the observer's location at ET to */ /* the aberration-corrected location of the target. */ /* Note that the sense of this position vector is */ /* independent of the direction of radiation travel */ /* implied by the aberration correction. */ /* Units are always km. */ /* Non-inertial frames are treated as follows: letting */ /* LTCENT be the one-way light time between the observer */ /* and the central body associated with the frame, the */ /* orientation of the frame is evaluated at ET-LTCENT, */ /* ET+LTCENT, or ET depending on whether the requested */ /* aberration correction is, respectively, for received */ /* radiation, transmitted radiation, or is omitted. */ /* LTCENT is computed using the method indicated by */ /* ABCORR. */ /* LT is the one-way light time between the observer and */ /* target in seconds. If the target position is */ /* corrected for aberrations, then LT is the one-way */ /* light time between the observer and the light time */ /* corrected target location. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If name of target or observer cannot be translated to its */ /* NAIF ID code, the error SPICE(IDCODENOTFOUND) is signaled. */ /* 2) If the reference frame REF is not a recognized reference */ /* frame the error 'SPICE(UNKNOWNFRAME)' is signaled. */ /* 3) If the loaded kernels provide insufficient data to */ /* compute the requested position vector, the deficiency will */ /* be diagnosed by a routine in the call tree of this routine. */ /* 4) If an error occurs while reading an SPK or other kernel file, */ /* the error will be diagnosed by a routine in the call tree */ /* of this routine. */ /* $ Files */ /* This routine computes positions using SPK files that have been */ /* loaded into the SPICE system, normally via the kernel loading */ /* interface routine FURNSH. See the routine FURNSH and the SPK */ /* and KERNEL Required Reading for further information on loading */ /* (and unloading) kernels. */ /* If the output position PTARG is to be expressed relative to a */ /* non-inertial frame, or if any of the ephemeris data used to */ /* compute PTARG are expressed relative to a non-inertial frame in */ /* the SPK files providing those data, additional kernels may be */ /* needed to enable the reference frame transformations required to */ /* compute the position. Normally these additional kernels are PCK */ /* files or frame kernels. Any such kernels must already be loaded */ /* at the time this routine is called. */ /* $ Particulars */ /* This routine is part of the user interface to the SPICE ephemeris */ /* system. It allows you to retrieve position information for any */ /* ephemeris object relative to any other in a reference frame that */ /* is convenient for further computations. */ /* Aberration corrections */ /* ====================== */ /* In space science or engineering applications one frequently */ /* wishes to know where to point a remote sensing instrument, such */ /* as an optical camera or radio antenna, in order to observe or */ /* otherwise receive radiation from a target. This pointing problem */ /* is complicated by the finite speed of light: one needs to point */ /* to where the target appears to be as opposed to where it actually */ /* is at the epoch of observation. We use the adjectives */ /* "geometric," "uncorrected," or "true" to refer to an actual */ /* position or state of a target at a specified epoch. When a */ /* geometric position or state vector is modified to reflect how it */ /* appears to an observer, we describe that vector by any of the */ /* terms "apparent," "corrected," "aberration corrected," or "light */ /* time and stellar aberration corrected." The SPICE Toolkit can */ /* correct for two phenomena affecting the apparent location of an */ /* object: one-way light time (also called "planetary aberration") */ /* and stellar aberration. */ /* One-way light time */ /* ------------------ */ /* Correcting for one-way light time is done by computing, given an */ /* observer and observation epoch, where a target was when the */ /* observed photons departed the target's location. The vector from */ /* the observer to this computed target location is called a "light */ /* time corrected" vector. The light time correction depends on the */ /* motion of the target relative to the solar system barycenter, but */ /* it is independent of the velocity of the observer relative to the */ /* solar system barycenter. Relativistic effects such as light */ /* bending and gravitational delay are not accounted for in the */ /* light time correction performed by this routine. */ /* Stellar aberration */ /* ------------------ */ /* The velocity of the observer also affects the apparent location */ /* of a target: photons arriving at the observer are subject to a */ /* "raindrop effect" whereby their velocity relative to the observer */ /* is, using a Newtonian approximation, the photons' velocity */ /* relative to the solar system barycenter minus the velocity of the */ /* observer relative to the solar system barycenter. This effect is */ /* called "stellar aberration." Stellar aberration is independent */ /* of the velocity of the target. The stellar aberration formula */ /* used by this routine does not include (the much smaller) */ /* relativistic effects. */ /* Stellar aberration corrections are applied after light time */ /* corrections: the light time corrected target position vector is */ /* used as an input to the stellar aberration correction. */ /* When light time and stellar aberration corrections are both */ /* applied to a geometric position vector, the resulting position */ /* vector indicates where the target "appears to be" from the */ /* observer's location. */ /* As opposed to computing the apparent position of a target, one */ /* may wish to compute the pointing direction required for */ /* transmission of photons to the target. This also requires */ /* correction of the geometric target position for the effects of */ /* light time and stellar aberration, but in this case the */ /* corrections are computed for radiation traveling *from* the */ /* observer to the target. */ /* The "transmission" light time correction yields the target's */ /* location as it will be when photons emitted from the observer's */ /* location at ET arrive at the target. The transmission stellar */ /* aberration correction is the inverse of the traditional stellar */ /* aberration correction: it indicates the direction in which */ /* radiation should be emitted so that, using a Newtonian */ /* approximation, the sum of the velocity of the radiation relative */ /* to the observer and of the observer's velocity, relative to the */ /* solar system barycenter, yields a velocity vector that points in */ /* the direction of the light time corrected position of the target. */ /* One may object to using the term "observer" in the transmission */ /* case, in which radiation is emitted from the observer's location. */ /* The terminology was retained for consistency with earlier */ /* documentation. */ /* Below, we indicate the aberration corrections to use for some */ /* common applications: */ /* 1) Find the apparent direction of a target for a remote-sensing */ /* observation. */ /* Use 'LT+S': apply both light time and stellar */ /* aberration corrections. */ /* Note that using light time corrections alone ('LT') is */ /* generally not a good way to obtain an approximation to an */ /* apparent target vector: since light time and stellar */ /* aberration corrections often partially cancel each other, */ /* it may be more accurate to use no correction at all than to */ /* use light time alone. */ /* 2) Find the corrected pointing direction to radiate a signal */ /* to a target. This computation is often applicable for */ /* implementing communications sessions. */ /* Use 'XLT+S': apply both light time and stellar */ /* aberration corrections for transmission. */ /* 3) Compute the apparent position of a target body relative */ /* to a star or other distant object. */ /* Use 'LT' or 'LT+S' as needed to match the correction */ /* applied to the position of the distant object. For */ /* example, if a star position is obtained from a catalog, */ /* the position vector may not be corrected for stellar */ /* aberration. In this case, to find the angular */ /* separation of the star and the limb of a planet, the */ /* vector from the observer to the planet should be */ /* corrected for light time but not stellar aberration. */ /* 4) Obtain an uncorrected position vector derived directly from */ /* data in an SPK file. */ /* Use 'NONE'. */ /* 5) Use a geometric position vector as a low-accuracy estimate */ /* of the apparent position for an application where execution */ /* speed is critical. */ /* Use 'NONE'. */ /* 6) While this routine cannot perform the relativistic */ /* aberration corrections required to compute positions */ /* with the highest possible accuracy, it can supply the */ /* geometric positions required as inputs to these */ /* computations. */ /* Use 'NONE', then apply high-accuracy aberration */ /* corrections (not available in the SPICE Toolkit). */ /* Below, we discuss in more detail how the aberration corrections */ /* applied by this routine are computed. */ /* Geometric case */ /* ============== */ /* ZZSPKZP0 begins by computing the geometric position T(ET) of */ /* the target body relative to the solar system barycenter (SSB). */ /* Subtracting the geometric position of the observer O(ET) gives */ /* the geometric position of the target body relative to the */ /* observer. The one-way light time, LT, is given by */ /* | T(ET) - O(ET) | */ /* LT = ------------------- */ /* c */ /* The geometric relationship between the observer, target, and */ /* solar system barycenter is as shown: */ /* SSB ---> O(ET) */ /* | / */ /* | / */ /* | / */ /* | / T(ET) - O(ET) */ /* V V */ /* T(ET) */ /* The returned position vector is */ /* T(ET) - O(ET) */ /* Reception case */ /* ============== */ /* When any of the options 'LT', 'CN', 'LT+S', 'CN+S' is selected */ /* for ABCORR, ZZSPKZP0 computes the position of the target body */ /* at epoch ET-LT, where LT is the one-way light time. Let T(t) */ /* and O(t) represent the positions of the target and observer */ /* relative to the solar system barycenter at time t; then LT is */ /* the solution of the light-time equation */ /* | T(ET-LT) - O(ET) | */ /* LT = ------------------------ (1) */ /* c */ /* The ratio */ /* | T(ET) - O(ET) | */ /* --------------------- (2) */ /* c */ /* is used as a first approximation to LT; inserting (2) into the */ /* right hand side of the light-time equation (1) yields the */ /* "one-iteration" estimate of the one-way light time ("LT"). */ /* Repeating the process until the estimates of LT converge */ /* yields the "converged Newtonian" light time estimate ("CN"). */ /* Subtracting the geometric position of the observer O(ET) gives */ /* the position of the target body relative to the observer: */ /* T(ET-LT) - O(ET). */ /* SSB ---> O(ET) */ /* | \ | */ /* | \ | */ /* | \ | T(ET-LT) - O(ET) */ /* | \ | */ /* V V V */ /* T(ET) T(ET-LT) */ /* The light time corrected position vector is */ /* T(ET-LT) - O(ET) */ /* If correction for stellar aberration is requested, the target */ /* position is rotated toward the solar system barycenter- */ /* relative velocity vector of the observer. The rotation is */ /* computed as follows: */ /* Let r be the light time corrected 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. */ /* Transmission case */ /* ================== */ /* When any of the options 'XLT', 'XCN', 'XLT+S', 'XCN+S' is */ /* selected, ZZSPKZP0 computes the position of the target body T */ /* at epoch ET+LT, where LT is the one-way light time. LT is the */ /* solution of the light-time equation */ /* | T(ET+LT) - O(ET) | */ /* LT = ------------------------ (3) */ /* c */ /* Subtracting the geometric position of the observer, O(ET), */ /* gives the position of the target body relative to the */ /* observer: T(ET-LT) - O(ET). */ /* SSB --> O(ET) */ /* / | * */ /* / | * T(ET+LT) - O(ET) */ /* / |* */ /* / *| */ /* V V V */ /* T(ET+LT) T(ET) */ /* The light-time corrected position vector is */ /* T(ET+LT) - O(ET) */ /* If correction for stellar aberration is requested, the target */ /* position is rotated away from the solar system barycenter- */ /* relative velocity vector of the observer. The rotation is */ /* computed as in the reception case, but the sign of the */ /* rotation angle is negated. */ /* Precision of light time corrections */ /* =================================== */ /* Corrections using one iteration of the light time solution */ /* ---------------------------------------------------------- */ /* When the requested aberration correction is 'LT', 'LT+S', */ /* 'XLT', or 'XLT+S', only one iteration is performed in the */ /* algorithm used to compute LT. */ /* The relative error in this computation */ /* | LT_ACTUAL - LT_COMPUTED | / LT_ACTUAL */ /* is at most */ /* (V/C)**2 */ /* ---------- */ /* 1 - (V/C) */ /* which is well approximated by (V/C)**2, where V is the */ /* velocity of the target relative to an inertial frame and C is */ /* the speed of light. */ /* For nearly all objects in the solar system V is less than 60 */ /* km/sec. The value of C is 300000 km/sec. Thus the one */ /* iteration solution for LT has a potential relative error of */ /* not more than 4*10**-8. This is a potential light time error */ /* of approximately 2*10**-5 seconds per astronomical unit of */ /* distance separating the observer and target. Given the bound */ /* on V cited above: */ /* As long as the observer and target are */ /* separated by less than 50 astronomical units, */ /* the error in the light time returned using */ /* the one-iteration light time corrections */ /* is less than 1 millisecond. */ /* Converged corrections */ /* --------------------- */ /* When the requested aberration correction is 'CN', 'CN+S', */ /* 'XCN', or 'XCN+S', three iterations are performed in the */ /* computation of LT. The relative error present in this */ /* solution is at most */ /* (V/C)**4 */ /* ---------- */ /* 1 - (V/C) */ /* which is well approximated by (V/C)**4. Mathematically the */ /* precision of this computation is better than a nanosecond for */ /* any pair of objects in the solar system. */ /* However, to model the actual light time between target and */ /* observer one must take into account effects due to general */ /* relativity. These may be as high as a few hundredths of a */ /* millisecond for some objects. */ /* When one considers the extra time required to compute the */ /* converged Newtonian light time (the state of the target */ /* relative to the solar system barycenter is looked up three */ /* times instead of once) together with the real gain in */ /* accuracy, it seems unlikely that you will want to request */ /* either the "CN" or "CN+S" light time corrections. However, */ /* these corrections can be useful for testing situations where */ /* high precision (as opposed to accuracy) is required. */ /* Relativistic Corrections */ /* ========================= */ /* This routine does not attempt to perform either general or */ /* special relativistic corrections in computing the various */ /* aberration corrections. For many applications relativistic */ /* corrections are not worth the expense of added computation */ /* cycles. If however, your application requires these additional */ /* corrections we suggest you consult the astronomical almanac (page */ /* B36) for a discussion of how to carry out these corrections. */ /* $ Examples */ /* 1) Load a planetary ephemeris SPK, then look up a series of */ /* geometric positions of the moon relative to the earth, */ /* referenced to the J2000 frame. */ /* IMPLICIT NONE */ /* C */ /* C Local constants */ /* C */ /* CHARACTER*(*) FRAME */ /* PARAMETER ( FRAME = 'J2000' ) */ /* CHARACTER*(*) ABCORR */ /* PARAMETER ( ABCORR = 'NONE' ) */ /* C */ /* C The name of the SPK file shown here is fictitious; */ /* C you must supply the name of an SPK file available */ /* C on your own computer system. */ /* C */ /* CHARACTER*(*) SPK */ /* PARAMETER ( SPK = 'planet.bsp' ) */ /* C */ /* C ET0 represents the date 2000 Jan 1 12:00:00 TDB. */ /* C */ /* DOUBLE PRECISION ET0 */ /* PARAMETER ( ET0 = 0.0D0 ) */ /* C */ /* C Use a time step of 1 hour; look up 100 positions. */ /* C */ /* DOUBLE PRECISION STEP */ /* PARAMETER ( STEP = 3600.0D0 ) */ /* INTEGER MAXITR */ /* PARAMETER ( MAXITR = 100 ) */ /* C */ /* C The NAIF IDs of the earth and moon are 399 and 301 */ /* C respectively. */ /* C */ /* INTEGER OBSRVR */ /* PARAMETER ( OBSRVR = 399 ) */ /* INTEGER TARGET */ /* PARAMETER ( TARGET = 301 ) */ /* C */ /* C Local variables */ /* C */ /* DOUBLE PRECISION ET */ /* DOUBLE PRECISION LT */ /* DOUBLE PRECISION POS ( 3 ) */ /* INTEGER I */ /* C */ /* C Load the SPK file. */ /* C */ /* CALL FURNSH ( SPK ) */ /* C */ /* C Step through a series of epochs, looking up a */ /* C position vector at each one. */ /* C */ /* DO I = 1, MAXITR */ /* ET = ET0 + (I-1)*STEP */ /* CALL ZZSPKZP0 ( TARGET, ET, FRAME, ABCORR, OBSRVR, */ /* . POS, LT ) */ /* WRITE (*,*) 'ET = ', ET */ /* WRITE (*,*) 'J2000 x-position (km): ', POS(1) */ /* WRITE (*,*) 'J2000 y-position (km): ', POS(2) */ /* WRITE (*,*) 'J2000 z-position (km): ', POS(3) */ /* WRITE (*,*) ' ' */ /* END DO */ /* END */ /* $ Restrictions */ /* 1) SPICE Private routine. */ /* $ Literature_References */ /* SPK Required Reading. */ /* $ Author_and_Institution */ /* C.H. Acton (JPL) */ /* B.V. Semenov (JPL) */ /* N.J. Bachman (JPL) */ /* W.L. Taber (JPL) */ /* $ Version */ /* - SPICELIB Version 1.0.0, 05-JAN-2005 (NJB) */ /* Based on SPICELIB Version 3.1.0, 05-JAN-2005 (NJB) */ /* -& */ /* $ Index_Entries */ /* using body names get position relative to an observer */ /* get position relative observer corrected for aberrations */ /* read ephemeris data */ /* read trajectory data */ /* -& */ /* $ Revisions */ /* -& */ /* SPICELIB functions */ /* Local parameters */ /* Local variables */ /* Saved variables */ /* Initial values */ /* Standard SPICE error handling. */ if (return_()) { return 0; } else { chkin_("ZZSPKZP0", (ftnlen)8); } /* Get the frame id for J2000 on the first call to this routine. */ if (first) { first = FALSE_; namfrm_("J2000", &fj2000, (ftnlen)5); } /* Decide whether the aberration correction is for received or */ /* transmitted radiation. */ i__ = ltrim_(abcorr, abcorr_len); xmit = eqchr_(abcorr + (i__ - 1), "X", (ftnlen)1, (ftnlen)1); /* If we only want geometric positions, then compute just that. */ /* Otherwise, compute the state of the observer relative to */ /* the SSB. Then feed that position into ZZSPKPA0 to compute the */ /* apparent position of the target body relative to the observer */ /* with the requested aberration corrections. */ if (eqstr_(abcorr, "NONE", abcorr_len, (ftnlen)4)) { zzspkgp0_(targ, et, ref, obs, ptarg, lt, ref_len); } else { /* Get the auxiliary information about the requested output */ /* frame. */ namfrm_(ref, &reqfrm, ref_len); if (reqfrm == 0) { setmsg_("The requested output frame '#' is not recognized by the" " reference frame subsystem. Please check that the appro" "priate kernels have been loaded and that you have correc" "tly entered the name of the output frame. ", (ftnlen)209); errch_("#", ref, (ftnlen)1, ref_len); sigerr_("SPICE(UNKNOWNFRAME)", (ftnlen)19); chkout_("ZZSPKZP0", (ftnlen)8); return 0; } frinfo_(&reqfrm, ¢er, &type__, &typeid, &found); /* If we are dealing with an inertial frame, we can simply */ /* call ZZSPKSB0, ZZSPKPA0 and return. */ if (type__ == 1) { zzspksb0_(obs, et, ref, sobs, ref_len); zzspkpa0_(targ, et, ref, sobs, abcorr, ptarg, lt, ref_len, abcorr_len); chkout_("ZZSPKZP0", (ftnlen)8); return 0; } /* Still here? */ /* We are dealing with a non-inertial frame. But we need to */ /* do light time and stellar aberration in an inertial frame. */ /* Get the "apparent" position of TARG in the intermediary */ /* inertial reference frame J2000. */ /* We also need the light time to the center of the frame. */ zzspksb0_(obs, et, "J2000", sobs, (ftnlen)5); zzspkpa0_(targ, et, "J2000", sobs, abcorr, postn, lt, (ftnlen)5, abcorr_len); if (failed_()) { chkout_("ZZSPKZP0", (ftnlen)8); return 0; } if (center == *obs) { ltcent = 0.; } else if (center == *targ) { ltcent = *lt; } else { zzspkpa0_(¢er, et, "J2000", sobs, abcorr, temp, <cent, ( ftnlen)5, abcorr_len); } /* If something went wrong (like we couldn't get the position of */ /* the center relative to the observer) now it is time to quit. */ if (failed_()) { chkout_("ZZSPKZP0", (ftnlen)8); return 0; } /* If the aberration corrections are for transmission, negate */ /* the light time, since we wish to compute the orientation */ /* of the non-inertial frame at an epoch later than ET by */ /* the one-way light time. */ if (xmit) { ltcent = -ltcent; } /* Get the rotation from J2000 to the requested frame */ /* and convert the position. */ d__1 = *et - ltcent; zzrefch0_(&fj2000, &reqfrm, &d__1, xform); if (failed_()) { chkout_("ZZSPKZP0", (ftnlen)8); return 0; } mxv_(xform, postn, ptarg); } chkout_("ZZSPKZP0", (ftnlen)8); return 0; } /* zzspkzp0_ */
/* $Procedure ZZSPKGP0 ( S/P Kernel, geometric position ) */ /* Subroutine */ int zzspkgp0_(integer *targ, doublereal *et, char *ref, integer *obs, doublereal *pos, doublereal *lt, ftnlen ref_len) { /* Initialized data */ static logical first = TRUE_; /* System generated locals */ integer i__1, i__2, i__3; /* Builtin functions */ integer s_cmp(char *, char *, ftnlen, ftnlen), s_rnge(char *, integer, char *, integer); /* Local variables */ extern /* Subroutine */ int zzrefch0_(integer *, integer *, doublereal *, doublereal *), vadd_(doublereal *, doublereal *, doublereal *); integer cobs, legs; doublereal sobs[6]; extern /* Subroutine */ int vsub_(doublereal *, doublereal *, doublereal * ), vequ_(doublereal *, doublereal *), zznamfrm_(integer *, char *, integer *, char *, integer *, ftnlen, ftnlen), zzctruin_(integer *); integer i__; extern /* Subroutine */ int etcal_(doublereal *, char *, ftnlen); integer refid; extern /* Subroutine */ int chkin_(char *, ftnlen); char oname[40]; doublereal descr[5]; integer ctarg[20]; char ident[40], tname[40]; extern /* Subroutine */ int errch_(char *, char *, ftnlen, ftnlen), moved_(doublereal *, integer *, doublereal *); logical found; extern /* Subroutine */ int repmi_(char *, char *, integer *, char *, ftnlen, ftnlen, ftnlen); doublereal starg[120] /* was [6][20] */; logical nofrm; static char svref[32]; doublereal stemp[6]; integer ctpos; doublereal vtemp[6]; extern doublereal vnorm_(doublereal *); extern /* Subroutine */ int bodc2n_(integer *, char *, logical *, ftnlen); static integer svctr1[2]; extern logical failed_(void); extern /* Subroutine */ int cleard_(integer *, doublereal *); integer handle, cframe; extern doublereal clight_(void); integer tframe[20]; extern integer isrchi_(integer *, integer *, integer *); extern /* Subroutine */ int sigerr_(char *, ftnlen), chkout_(char *, ftnlen); static integer svrefi; extern /* Subroutine */ int irfnum_(char *, integer *, ftnlen), prefix_( char *, integer *, char *, ftnlen, ftnlen), setmsg_(char *, ftnlen), suffix_(char *, integer *, char *, ftnlen, ftnlen); integer tmpfrm; extern /* Subroutine */ int irfrot_(integer *, integer *, doublereal *), spksfs_(integer *, doublereal *, integer *, doublereal *, char *, logical *, ftnlen); extern integer frstnp_(char *, ftnlen); extern logical return_(void); doublereal psxfrm[9] /* was [3][3] */; extern /* Subroutine */ int spkpvn_(integer *, doublereal *, doublereal *, integer *, doublereal *, integer *), intstr_(integer *, char *, ftnlen); integer nct; doublereal rot[9] /* was [3][3] */; extern /* Subroutine */ int mxv_(doublereal *, doublereal *, doublereal *) ; char tstring[80]; /* $ 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. */ /* Compute the geometric position of a target body relative to an */ /* observing body. */ /* $ 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 */ /* $ Abstract */ /* This file contains the number of inertial reference */ /* frames that are currently known by the SPICE toolkit */ /* software. */ /* $ 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 */ /* FRAMES */ /* $ Declarations */ /* $ Brief_I/O */ /* VARIABLE I/O DESCRIPTION */ /* -------- --- -------------------------------------------------- */ /* NINERT P Number of known inertial reference frames. */ /* $ Parameters */ /* NINERT is the number of recognized inertial reference */ /* frames. This value is needed by both CHGIRF */ /* ZZFDAT, and FRAMEX. */ /* $ Author_and_Institution */ /* W.L. Taber (JPL) */ /* $ Literature_References */ /* None. */ /* $ Version */ /* - SPICELIB Version 1.0.0, 10-OCT-1996 (WLT) */ /* -& */ /* $ Abstract */ /* This include file defines the dimension of the counter */ /* array used by various SPICE subsystems to uniquely identify */ /* changes in their states. */ /* $ 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 */ /* CTRSIZ is the dimension of the counter array used by */ /* various SPICE subsystems to uniquely identify */ /* changes in their states. */ /* $ Author_and_Institution */ /* B.V. Semenov (JPL) */ /* $ Literature_References */ /* None. */ /* $ Version */ /* - SPICELIB Version 1.0.0, 29-JUL-2013 (BVS) */ /* -& */ /* End of include file. */ /* $ Brief_I/O */ /* Variable I/O Description */ /* -------- --- -------------------------------------------------- */ /* TARG I Target body. */ /* ET I Target epoch. */ /* REF I Target reference frame. */ /* OBS I Observing body. */ /* POS O Position of target. */ /* LT O Light time. */ /* $ Detailed_Input */ /* TARG is the standard NAIF ID code for a target body. */ /* ET is the epoch (ephemeris time) at which the position */ /* of the target body is to be computed. */ /* REF is the name of the reference frame to */ /* which the vectors returned by the routine should */ /* be rotated. This may be any frame supported by */ /* the SPICELIB subroutine ZZREFCH0. */ /* OBS is the standard NAIF ID code for an observing body. */ /* $ Detailed_Output */ /* POS contains the position of the target */ /* body, relative to the observing body. This vector is */ /* rotated into the specified reference frame. Units */ /* are always km. */ /* LT is the one-way light time from the observing body */ /* to the geometric position of the target body at the */ /* specified epoch. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If insufficient ephemeris data has been loaded to compute */ /* the necessary positions, the error SPICE(SPKINSUFFDATA) is */ /* signalled. */ /* $ Files */ /* See: $Restrictions. */ /* $ Particulars */ /* ZZSPKGP0 computes the geometric position, T(t), of the target */ /* body and the geometric position, O(t), of the observing body */ /* relative to the first common center of motion. Subtracting */ /* O(t) from T(t) gives the geometric position of the target */ /* body relative to the observer. */ /* CENTER ----- O(t) */ /* | / */ /* | / */ /* | / */ /* | / T(t) - O(t) */ /* | / */ /* T(t) */ /* The one-way light time, tau, is given by */ /* | T(t) - O(t) | */ /* tau = ----------------- */ /* c */ /* For example, if the observing body is -94, the Mars Observer */ /* spacecraft, and the target body is 401, Phobos, then the */ /* first common center is probably 4, the Mars Barycenter. */ /* O(t) is the position of -94 relative to 4 and T(t) is the */ /* position of 401 relative to 4. */ /* The center could also be the Solar System Barycenter, body 0. */ /* For example, if the observer is 399, Earth, and the target */ /* is 299, Venus, then O(t) would be the position of 399 relative */ /* to 0 and T(t) would be the position of 299 relative to 0. */ /* Ephemeris data from more than one segment may be required */ /* to determine the positions of the target body and observer */ /* relative to a common center. ZZSPKGP0 reads as many segments */ /* as necessary, from as many files as necessary, using files */ /* that have been loaded by previous calls to SPKLEF (load */ /* ephemeris file). */ /* ZZSPKGP0 is similar to SPKGEO but returns geometric positions */ /* only. */ /* $ Examples */ /* The following code example computes the geometric */ /* position of the moon with respect to the earth and */ /* then prints the distance of the moon from the */ /* the earth at a number of epochs. */ /* Assume the SPK file SAMPLE.BSP contains ephemeris data */ /* for the moon relative to earth over the time interval */ /* from BEGIN to END. */ /* INTEGER EARTH */ /* PARAMETER ( EARTH = 399 ) */ /* INTEGER MOON */ /* PARAMETER ( MOON = 301 ) */ /* INTEGER N */ /* PARAMETER ( N = 100 ) */ /* INTEGER I */ /* CHARACTER*(20) UTC */ /* DOUBLE PRECISION BEGIN */ /* DOUBLE PRECISION DELTA */ /* DOUBLE PRECISION END */ /* DOUBLE PRECISION ET */ /* DOUBLE PRECISION POS ( 3 ) */ /* DOUBLE PRECISION LT */ /* DOUBLE PRECISION VNORM */ /* C */ /* C Load the binary SPK ephemeris file. */ /* C */ /* CALL FURNSH ( 'SAMPLE.BSP' ) */ /* . */ /* . */ /* . */ /* C */ /* C Divide the interval of coverage [BEGIN,END] into */ /* C N steps. At each step, compute the position, and */ /* C print out the epoch in UTC time and position norm. */ /* C */ /* DELTA = ( END - BEGIN ) / N */ /* DO I = 0, N */ /* ET = BEGIN + I*DELTA */ /* CALL ZZSPKGP0 ( MOON, ET, 'J2000', EARTH, POS, LT ) */ /* CALL ET2UTC ( ET, 'C', 0, UTC ) */ /* WRITE (*,*) UTC, VNORM ( POS ) */ /* END DO */ /* $ Restrictions */ /* 1) SPICE Private routine. */ /* 2) The ephemeris files to be used by ZZSPKGP0 must be loaded */ /* by SPKLEF before ZZSPKGP0 is called. */ /* $ Literature_References */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* B.V. Semenov (JPL) */ /* W.L. Taber (JPL) */ /* $ Version */ /* - SPICELIB Version 2.0.0, 08-JAN-2014 (BVS) */ /* Updated to save the input frame name and POOL state counter */ /* and to do frame name-ID conversion only if the counter has */ /* changed. */ /* Updated to map the input frame name to its ID by first calling */ /* ZZNAMFRM, and then calling IRFNUM. The side effect of this */ /* change is that now the frame with the fixed name 'DEFAULT' */ /* that can be associated with any code via CHGIRF's entry point */ /* IRFDEF will be fully masked by a frame with indentical name */ /* defined via a text kernel. Previously the CHGIRF's 'DEFAULT' */ /* frame masked the text kernel frame with the same name. */ /* Replaced SPKLEF with FURNSH and fixed errors in Examples. */ /* - SPICELIB Version 1.1.0, 09-NOV-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VADD calls. */ /* - SPICELIB Version 1.0.0, 05-JAN-2005 (NJB) */ /* Based on SPICELIB Version 1.1.0, 05-JAN-2005 (NJB) */ /* -& */ /* $ Index_Entries */ /* geometric position of one body relative to another */ /* -& */ /* $ Revisions */ /* - SPICELIB Version 1.1.0, 09-NOV-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VADD calls. */ /* -& */ /* This is the idea: */ /* Every body moves with respect to some center. The center */ /* is itself a body, which in turn moves about some other */ /* center. If we begin at the target body (T), follow */ /* the chain, */ /* T */ /* \ */ /* SSB \ */ /* \ C[1] */ /* \ / */ /* \ / */ /* \ / */ /* \ / */ /* C[3]-----------C[2] */ /* and avoid circular definitions (A moves about B, and B moves */ /* about A), eventually we get the position relative to the solar */ /* system barycenter (which, for our purposes, doesn't move). */ /* Thus, */ /* T = T + C[1] + C[2] + ... + C[n] */ /* SSB C[1] C[2] [C3] SSB */ /* where */ /* X */ /* Y */ /* is the position of body X relative to body Y. */ /* However, we don't want to follow each chain back to the SSB */ /* if it isn't necessary. Instead we will just follow the chain */ /* of the target body and follow the chain of the observing body */ /* until we find a common node in the tree. */ /* In the example below, C is the first common node. We compute */ /* the position of TARG relative to C and the position of OBS */ /* relative to C, then subtract the two positions. */ /* TARG */ /* \ */ /* SSB \ */ /* \ A */ /* \ / OBS */ /* \ / | */ /* \ / | */ /* \ / | */ /* B-------------C-----------------D */ /* SPICELIB functions */ /* Local parameters */ /* CHLEN is the maximum length of a chain. That is, */ /* it is the maximum number of bodies in the chain from */ /* the target or observer to the SSB. */ /* Saved frame name length. */ /* Local variables */ /* Saved frame name/ID item declarations. */ /* Saved frame name/ID items. */ /* Initial values. */ /* In-line Function Definitions */ /* Standard SPICE error handling. */ if (return_()) { return 0; } else { chkin_("ZZSPKGP0", (ftnlen)8); } /* Initialization. */ if (first) { /* Initialize counter. */ zzctruin_(svctr1); first = FALSE_; } /* We take care of the obvious case first. It TARG and OBS are the */ /* same we can just fill in zero. */ if (*targ == *obs) { *lt = 0.; cleard_(&c__3, pos); chkout_("ZZSPKGP0", (ftnlen)8); return 0; } /* CTARG contains the integer codes of the bodies in the */ /* target body chain, beginning with TARG itself and then */ /* the successive centers of motion. */ /* STARG(1,I) is the position of the target body relative */ /* to CTARG(I). The id-code of the frame of this position is */ /* stored in TFRAME(I). */ /* COBS and SOBS will contain the centers and positions of the */ /* observing body. (They are single elements instead of arrays */ /* because we only need the current center and position of the */ /* observer relative to it.) */ /* First, we construct CTARG and STARG. CTARG(1) is */ /* just the target itself, and STARG(1,1) is just a zero */ /* vector, that is, the position of the target relative */ /* to itself. */ /* Then we follow the chain, filling up CTARG and STARG */ /* as we go. We use SPKSFS to search through loaded */ /* files to find the first segment applicable to CTARG(1) */ /* and time ET. Then we use SPKPVN to compute the position */ /* of the body CTARG(1) at ET in the segment that was found */ /* and get its center and frame of motion (CTARG(2) and TFRAME(2). */ /* We repeat the process for CTARG(2) and so on, until */ /* there is no data found for some CTARG(I) or until we */ /* reach the SSB. */ /* Next, we find centers and positions in a similar manner */ /* for the observer. It's a similar construction as */ /* described above, but I is always 1. COBS and SOBS */ /* are overwritten with each new center and position, */ /* beginning at OBS. However, we stop when we encounter */ /* a common center of motion, that is when COBS is equal */ /* to CTARG(I) for some I. */ /* Finally, we compute the desired position of the target */ /* relative to the observer by subtracting the position of */ /* the observing body relative to the common node from */ /* the position of the target body relative to the common */ /* node. */ /* CTPOS is the position in CTARG of the common node. */ /* Since the upgrade to use hashes and counter bypass ZZNAMFRM */ /* became more efficient in looking up frame IDs than IRFNUM. So the */ /* original order of calls "IRFNUM first, NAMFRM second" was */ /* switched to "ZZNAMFRM first, IRFNUM second". */ /* The call to IRFNUM, now redundant for built-in inertial frames, */ /* was preserved to for a sole reason -- to still support the */ /* ancient and barely documented ability for the users to associate */ /* a frame with the fixed name 'DEFAULT' with any CHGIRF inertial */ /* frame code via CHGIRF's entry point IRFDEF. */ /* Note that in the case of ZZNAMFRM's failure to resolve name and */ /* IRFNUM's success to do so, the code returned by IRFNUM for */ /* 'DEFAULT' frame is *not* copied to the saved code SVREFI (which */ /* would be set to 0 by ZZNAMFRM) to make sure that on subsequent */ /* calls ZZNAMFRM does not do a bypass (as SVREFI always forced look */ /* up) and calls IRFNUM again to reset the 'DEFAULT's frame ID */ /* should it change between the calls. */ zznamfrm_(svctr1, svref, &svrefi, ref, &refid, (ftnlen)32, ref_len); if (refid == 0) { irfnum_(ref, &refid, ref_len); } if (refid == 0) { if (frstnp_(ref, ref_len) > 0) { setmsg_("The string supplied to specify the reference frame, ('#" "') contains non-printing characters. The two most commo" "n causes for this kind of error are: 1. an error in the " "call to ZZSPKGP0; 2. an uninitialized variable. ", ( ftnlen)215); errch_("#", ref, (ftnlen)1, ref_len); } else if (s_cmp(ref, " ", ref_len, (ftnlen)1) == 0) { setmsg_("The string supplied to specify the reference frame is b" "lank. The most common cause for this kind of error is a" "n uninitialized variable. ", (ftnlen)137); } else { setmsg_("The string supplied to specify the reference frame was " "'#'. This frame is not recognized. Possible causes for " "this error are: 1. failure to load the frame definition " "into the kernel pool; 2. An out-of-date edition of the t" "oolkit. ", (ftnlen)231); errch_("#", ref, (ftnlen)1, ref_len); } sigerr_("SPICE(UNKNOWNFRAME)", (ftnlen)19); if (failed_()) { chkout_("ZZSPKGP0", (ftnlen)8); return 0; } } /* Fill in CTARG and STARG until no more data is found */ /* or until we reach the SSB. If the chain gets too */ /* long to fit in CTARG, that is if I equals CHLEN, */ /* then overwrite the last elements of CTARG and STARG. */ /* Note the check for FAILED in the loop. If SPKSFS */ /* or SPKPVN happens to fail during execution, and the */ /* current error handling action is to NOT abort, then */ /* FOUND may be stuck at TRUE, CTARG(I) will never */ /* become zero, and the loop will execute indefinitely. */ /* Construct CTARG and STARG. Begin by assigning the */ /* first elements: TARG and the position of TARG relative */ /* to itself. */ i__ = 1; ctarg[(i__1 = i__ - 1) < 20 && 0 <= i__1 ? i__1 : s_rnge("ctarg", i__1, "zzspkgp0_", (ftnlen)610)] = *targ; found = TRUE_; cleard_(&c__6, &starg[(i__1 = i__ * 6 - 6) < 120 && 0 <= i__1 ? i__1 : s_rnge("starg", i__1, "zzspkgp0_", (ftnlen)613)]); while(found && i__ < 20 && ctarg[(i__1 = i__ - 1) < 20 && 0 <= i__1 ? i__1 : s_rnge("ctarg", i__1, "zzspkgp0_", (ftnlen)615)] != *obs && ctarg[(i__2 = i__ - 1) < 20 && 0 <= i__2 ? i__2 : s_rnge("ctarg", i__2, "zzspkgp0_", (ftnlen)615)] != 0) { /* Find a file and segment that has position */ /* data for CTARG(I). */ spksfs_(&ctarg[(i__1 = i__ - 1) < 20 && 0 <= i__1 ? i__1 : s_rnge( "ctarg", i__1, "zzspkgp0_", (ftnlen)624)], et, &handle, descr, ident, &found, (ftnlen)40); if (found) { /* Get the position of CTARG(I) relative to some */ /* center of motion. This new center goes in */ /* CTARG(I+1) and the position is called STEMP. */ ++i__; spkpvn_(&handle, descr, et, &tframe[(i__1 = i__ - 1) < 20 && 0 <= i__1 ? i__1 : s_rnge("tframe", i__1, "zzspkgp0_", (ftnlen) 634)], &starg[(i__2 = i__ * 6 - 6) < 120 && 0 <= i__2 ? i__2 : s_rnge("starg", i__2, "zzspkgp0_", (ftnlen)634)], & ctarg[(i__3 = i__ - 1) < 20 && 0 <= i__3 ? i__3 : s_rnge( "ctarg", i__3, "zzspkgp0_", (ftnlen)634)]); /* Here's what we have. STARG is the position of CTARG(I-1) */ /* relative to CTARG(I) in reference frame TFRAME(I) */ /* If one of the routines above failed during */ /* execution, we just give up and check out. */ if (failed_()) { chkout_("ZZSPKGP0", (ftnlen)8); return 0; } } } tframe[0] = tframe[1]; /* If the loop above ended because we ran out of */ /* room in the arrays CTARG and STARG, then we */ /* continue finding positions but we overwrite the */ /* last elements of CTARG and STARG. */ /* If, as a result, the first common node is */ /* overwritten, we'll just have to settle for */ /* the last common node. This will cause a small */ /* loss of precision, but it's better than other */ /* alternatives. */ if (i__ == 20) { while(found && ctarg[19] != 0 && ctarg[19] != *obs) { /* Find a file and segment that has position */ /* data for CTARG(CHLEN). */ spksfs_(&ctarg[19], et, &handle, descr, ident, &found, (ftnlen)40) ; if (found) { /* Get the position of CTARG(CHLEN) relative to */ /* some center of motion. The new center */ /* overwrites the old. The position is called */ /* STEMP. */ spkpvn_(&handle, descr, et, &tmpfrm, stemp, &ctarg[19]); /* Add STEMP to the position of TARG relative to */ /* the old center to get the position of TARG */ /* relative to the new center. Overwrite */ /* the last element of STARG. */ if (tframe[19] == tmpfrm) { moved_(&starg[114], &c__3, vtemp); } else if (tmpfrm > 0 && tmpfrm <= 21 && tframe[19] > 0 && tframe[19] <= 21) { irfrot_(&tframe[19], &tmpfrm, rot); mxv_(rot, &starg[114], vtemp); } else { zzrefch0_(&tframe[19], &tmpfrm, et, psxfrm); if (failed_()) { chkout_("ZZSPKGP0", (ftnlen)8); return 0; } mxv_(psxfrm, &starg[114], vtemp); } vadd_(vtemp, stemp, &starg[114]); tframe[19] = tmpfrm; /* If one of the routines above failed during */ /* execution, we just give up and check out. */ if (failed_()) { chkout_("ZZSPKGP0", (ftnlen)8); return 0; } } } } nct = i__; /* NCT is the number of elements in CTARG, */ /* the chain length. We have in hand the following information */ /* STARG(1...3,K) position of body */ /* CTARG(K-1) relative to body CTARG(K) in the frame */ /* TFRAME(K) */ /* For K = 2,..., NCT. */ /* CTARG(1) = TARG */ /* STARG(1...3,1) = ( 0, 0, 0 ) */ /* TFRAME(1) = TFRAME(2) */ /* Now follow the observer's chain. Assign */ /* the first values for COBS and SOBS. */ cobs = *obs; cleard_(&c__6, sobs); /* Perhaps we have a common node already. */ /* If so it will be the last node on the */ /* list CTARG. */ /* We let CTPOS will be the position of the common */ /* node in CTARG if one is found. It will */ /* be zero if COBS is not found in CTARG. */ if (ctarg[(i__1 = nct - 1) < 20 && 0 <= i__1 ? i__1 : s_rnge("ctarg", i__1, "zzspkgp0_", (ftnlen)769)] == cobs) { ctpos = nct; cframe = tframe[(i__1 = ctpos - 1) < 20 && 0 <= i__1 ? i__1 : s_rnge( "tframe", i__1, "zzspkgp0_", (ftnlen)771)]; } else { ctpos = 0; } /* Repeat the same loop as above, but each time */ /* we encounter a new center of motion, check to */ /* see if it is a common node. (When CTPOS is */ /* not zero, CTARG(CTPOS) is the first common node.) */ /* Note that we don't need a centers array nor a */ /* positions array, just a single center and position */ /* is sufficient --- we just keep overwriting them. */ /* When the common node is found, we have everything */ /* we need in that one center (COBS) and position */ /* (SOBS-position of the target relative to COBS). */ found = TRUE_; nofrm = TRUE_; legs = 0; while(found && cobs != 0 && ctpos == 0) { /* Find a file and segment that has position */ /* data for COBS. */ spksfs_(&cobs, et, &handle, descr, ident, &found, (ftnlen)40); if (found) { /* Get the position of COBS; call it STEMP. */ /* The center of motion of COBS becomes the */ /* new COBS. */ if (legs == 0) { spkpvn_(&handle, descr, et, &tmpfrm, sobs, &cobs); } else { spkpvn_(&handle, descr, et, &tmpfrm, stemp, &cobs); } if (nofrm) { nofrm = FALSE_; cframe = tmpfrm; } /* Add STEMP to the position of OBS relative to */ /* the old COBS to get the position of OBS */ /* relative to the new COBS. */ if (cframe == tmpfrm) { /* On the first leg of the position of the observer, we */ /* don't have to add anything, the position of the */ /* observer is already in SOBS. We only have to add when */ /* the number of legs in the observer position is one or */ /* greater. */ if (legs > 0) { vadd_(sobs, stemp, vtemp); vequ_(vtemp, sobs); } } else if (tmpfrm > 0 && tmpfrm <= 21 && cframe > 0 && cframe <= 21) { irfrot_(&cframe, &tmpfrm, rot); mxv_(rot, sobs, vtemp); vadd_(vtemp, stemp, sobs); cframe = tmpfrm; } else { zzrefch0_(&cframe, &tmpfrm, et, psxfrm); if (failed_()) { chkout_("ZZSPKGP0", (ftnlen)8); return 0; } mxv_(psxfrm, sobs, vtemp); vadd_(vtemp, stemp, sobs); cframe = tmpfrm; } /* Check failed. We don't want to loop */ /* indefinitely. */ if (failed_()) { chkout_("ZZSPKGP0", (ftnlen)8); return 0; } /* We now have one more leg of the path for OBS. Set */ /* LEGS to reflect this. Then see if the new center */ /* is a common node. If not, repeat the loop. */ ++legs; ctpos = isrchi_(&cobs, &nct, ctarg); } } /* If CTPOS is zero at this point, it means we */ /* have not found a common node though we have */ /* searched through all the available data. */ if (ctpos == 0) { bodc2n_(targ, tname, &found, (ftnlen)40); if (found) { prefix_("# (", &c__0, tname, (ftnlen)3, (ftnlen)40); suffix_(")", &c__0, tname, (ftnlen)1, (ftnlen)40); repmi_(tname, "#", targ, tname, (ftnlen)40, (ftnlen)1, (ftnlen)40) ; } else { intstr_(targ, tname, (ftnlen)40); } bodc2n_(obs, oname, &found, (ftnlen)40); if (found) { prefix_("# (", &c__0, oname, (ftnlen)3, (ftnlen)40); suffix_(")", &c__0, oname, (ftnlen)1, (ftnlen)40); repmi_(oname, "#", obs, oname, (ftnlen)40, (ftnlen)1, (ftnlen)40); } else { intstr_(obs, oname, (ftnlen)40); } setmsg_("Insufficient ephemeris data has been loaded to compute the " "position of TARG relative to OBS at the ephemeris epoch #. ", (ftnlen)118); etcal_(et, tstring, (ftnlen)80); errch_("TARG", tname, (ftnlen)4, (ftnlen)40); errch_("OBS", oname, (ftnlen)3, (ftnlen)40); errch_("#", tstring, (ftnlen)1, (ftnlen)80); sigerr_("SPICE(SPKINSUFFDATA)", (ftnlen)20); chkout_("ZZSPKGP0", (ftnlen)8); return 0; } /* If CTPOS is not zero, then we have reached a */ /* common node, specifically, */ /* CTARG(CTPOS) = COBS = CENTER */ /* (in diagram below). The POSITION of the target */ /* (TARG) relative to the observer (OBS) is just */ /* STARG(1,CTPOS) - SOBS. */ /* SOBS */ /* CENTER ---------------->OBS */ /* | . */ /* | . N */ /* S | . O */ /* T | . I */ /* A | . T */ /* R | . I */ /* G | . S */ /* | . O */ /* | . P */ /* V L */ /* TARG */ /* And the light-time between them is just */ /* | POSITION | */ /* LT = --------- */ /* c */ /* Compute the position of the target relative to CTARG(CTPOS) */ if (ctpos == 1) { tframe[0] = cframe; } i__1 = ctpos - 1; for (i__ = 2; i__ <= i__1; ++i__) { if (tframe[(i__2 = i__ - 1) < 20 && 0 <= i__2 ? i__2 : s_rnge("tframe" , i__2, "zzspkgp0_", (ftnlen)967)] == tframe[(i__3 = i__) < 20 && 0 <= i__3 ? i__3 : s_rnge("tframe", i__3, "zzspkgp0_", ( ftnlen)967)]) { vadd_(&starg[(i__2 = i__ * 6 - 6) < 120 && 0 <= i__2 ? i__2 : s_rnge("starg", i__2, "zzspkgp0_", (ftnlen)969)], &starg[( i__3 = (i__ + 1) * 6 - 6) < 120 && 0 <= i__3 ? i__3 : s_rnge("starg", i__3, "zzspkgp0_", (ftnlen)969)], stemp); moved_(stemp, &c__3, &starg[(i__2 = (i__ + 1) * 6 - 6) < 120 && 0 <= i__2 ? i__2 : s_rnge("starg", i__2, "zzspkgp0_", ( ftnlen)970)]); } else if (tframe[(i__3 = i__) < 20 && 0 <= i__3 ? i__3 : s_rnge( "tframe", i__3, "zzspkgp0_", (ftnlen)972)] > 0 && tframe[( i__3 = i__) < 20 && 0 <= i__3 ? i__3 : s_rnge("tframe", i__3, "zzspkgp0_", (ftnlen)972)] <= 21 && tframe[(i__2 = i__ - 1) < 20 && 0 <= i__2 ? i__2 : s_rnge("tframe", i__2, "zzspkgp0_", ( ftnlen)972)] > 0 && tframe[(i__2 = i__ - 1) < 20 && 0 <= i__2 ? i__2 : s_rnge("tframe", i__2, "zzspkgp0_", (ftnlen)972)] <= 21) { irfrot_(&tframe[(i__2 = i__ - 1) < 20 && 0 <= i__2 ? i__2 : s_rnge("tframe", i__2, "zzspkgp0_", (ftnlen)974)], & tframe[(i__3 = i__) < 20 && 0 <= i__3 ? i__3 : s_rnge( "tframe", i__3, "zzspkgp0_", (ftnlen)974)], rot); mxv_(rot, &starg[(i__2 = i__ * 6 - 6) < 120 && 0 <= i__2 ? i__2 : s_rnge("starg", i__2, "zzspkgp0_", (ftnlen)975)], stemp); vadd_(stemp, &starg[(i__2 = (i__ + 1) * 6 - 6) < 120 && 0 <= i__2 ? i__2 : s_rnge("starg", i__2, "zzspkgp0_", (ftnlen)976)], vtemp); moved_(vtemp, &c__3, &starg[(i__2 = (i__ + 1) * 6 - 6) < 120 && 0 <= i__2 ? i__2 : s_rnge("starg", i__2, "zzspkgp0_", ( ftnlen)977)]); } else { zzrefch0_(&tframe[(i__2 = i__ - 1) < 20 && 0 <= i__2 ? i__2 : s_rnge("tframe", i__2, "zzspkgp0_", (ftnlen)981)], & tframe[(i__3 = i__) < 20 && 0 <= i__3 ? i__3 : s_rnge( "tframe", i__3, "zzspkgp0_", (ftnlen)981)], et, psxfrm); if (failed_()) { chkout_("ZZSPKGP0", (ftnlen)8); return 0; } mxv_(psxfrm, &starg[(i__2 = i__ * 6 - 6) < 120 && 0 <= i__2 ? i__2 : s_rnge("starg", i__2, "zzspkgp0_", (ftnlen)988)], stemp); vadd_(stemp, &starg[(i__2 = (i__ + 1) * 6 - 6) < 120 && 0 <= i__2 ? i__2 : s_rnge("starg", i__2, "zzspkgp0_", (ftnlen)989)], vtemp); moved_(vtemp, &c__3, &starg[(i__2 = (i__ + 1) * 6 - 6) < 120 && 0 <= i__2 ? i__2 : s_rnge("starg", i__2, "zzspkgp0_", ( ftnlen)990)]); } } /* To avoid unnecessary frame transformations we'll do */ /* a bit of extra decision making here. It's a lot */ /* faster to make logical checks than it is to compute */ /* frame transformations. */ if (tframe[(i__1 = ctpos - 1) < 20 && 0 <= i__1 ? i__1 : s_rnge("tframe", i__1, "zzspkgp0_", (ftnlen)1003)] == cframe) { vsub_(&starg[(i__1 = ctpos * 6 - 6) < 120 && 0 <= i__1 ? i__1 : s_rnge("starg", i__1, "zzspkgp0_", (ftnlen)1005)], sobs, pos); } else if (tframe[(i__1 = ctpos - 1) < 20 && 0 <= i__1 ? i__1 : s_rnge( "tframe", i__1, "zzspkgp0_", (ftnlen)1007)] == refid) { /* If the last frame associated with the target is already */ /* in the requested output frame, we convert the position of */ /* the observer to that frame and then subtract the position */ /* of the observer from the position of the target. */ if (refid > 0 && refid <= 21 && cframe > 0 && cframe <= 21) { irfrot_(&cframe, &refid, rot); mxv_(rot, sobs, stemp); } else { zzrefch0_(&cframe, &refid, et, psxfrm); if (failed_()) { chkout_("ZZSPKGP0", (ftnlen)8); return 0; } mxv_(psxfrm, sobs, stemp); } /* We've now transformed SOBS into the requested reference frame. */ /* Set CFRAME to reflect this. */ cframe = refid; vsub_(&starg[(i__1 = ctpos * 6 - 6) < 120 && 0 <= i__1 ? i__1 : s_rnge("starg", i__1, "zzspkgp0_", (ftnlen)1038)], stemp, pos) ; } else if (cframe > 0 && cframe <= 21 && tframe[(i__1 = ctpos - 1) < 20 && 0 <= i__1 ? i__1 : s_rnge("tframe", i__1, "zzspkgp0_", (ftnlen) 1041)] > 0 && tframe[(i__1 = ctpos - 1) < 20 && 0 <= i__1 ? i__1 : s_rnge("tframe", i__1, "zzspkgp0_", (ftnlen)1041)] <= 21) { /* If both frames are inertial we use IRFROT instead of */ /* ZZREFCH0 to get things into a common frame. */ irfrot_(&tframe[(i__1 = ctpos - 1) < 20 && 0 <= i__1 ? i__1 : s_rnge( "tframe", i__1, "zzspkgp0_", (ftnlen)1047)], &cframe, rot); mxv_(rot, &starg[(i__1 = ctpos * 6 - 6) < 120 && 0 <= i__1 ? i__1 : s_rnge("starg", i__1, "zzspkgp0_", (ftnlen)1048)], stemp); vsub_(stemp, sobs, pos); } else { /* Use the more general routine ZZREFCH0 to make the */ /* transformation. */ zzrefch0_(&tframe[(i__1 = ctpos - 1) < 20 && 0 <= i__1 ? i__1 : s_rnge("tframe", i__1, "zzspkgp0_", (ftnlen)1056)], &cframe, et, psxfrm); if (failed_()) { chkout_("ZZSPKGP0", (ftnlen)8); return 0; } mxv_(psxfrm, &starg[(i__1 = ctpos * 6 - 6) < 120 && 0 <= i__1 ? i__1 : s_rnge("starg", i__1, "zzspkgp0_", (ftnlen)1063)], stemp); vsub_(stemp, sobs, pos); } /* Finally, rotate as needed into the requested frame. */ if (cframe == refid) { /* We don't have to do anything in this case. */ } else if (refid > 0 && refid <= 21 && cframe > 0 && cframe <= 21) { /* Since both frames are inertial, we use the more direct */ /* routine IRFROT to get the transformation to REFID. */ irfrot_(&cframe, &refid, rot); mxv_(rot, pos, stemp); moved_(stemp, &c__3, pos); } else { zzrefch0_(&cframe, &refid, et, psxfrm); if (failed_()) { chkout_("ZZSPKGP0", (ftnlen)8); return 0; } mxv_(psxfrm, pos, stemp); moved_(stemp, &c__3, pos); } *lt = vnorm_(pos) / clight_(); chkout_("ZZSPKGP0", (ftnlen)8); return 0; } /* zzspkgp0_ */