/* $Procedure ILLUM ( Illumination angles ) */ /* Subroutine */ int illum_(char *target, doublereal *et, char *abcorr, char * obsrvr, doublereal *spoint, doublereal *phase, doublereal *solar, doublereal *emissn, ftnlen target_len, ftnlen abcorr_len, ftnlen obsrvr_len) { /* Initialized data */ static logical first = TRUE_; extern /* Subroutine */ int zzbods2c_(integer *, char *, integer *, logical *, char *, integer *, logical *, ftnlen, ftnlen); extern doublereal vsep_(doublereal *, doublereal *); extern /* Subroutine */ int vsub_(doublereal *, doublereal *, doublereal * ), vequ_(doublereal *, doublereal *), zzctruin_(integer *); integer n; doublereal radii[3]; extern /* Subroutine */ int chkin_(char *, ftnlen), errch_(char *, char *, ftnlen, ftnlen); logical found; extern /* Subroutine */ int spkez_(integer *, doublereal *, char *, char * , integer *, doublereal *, doublereal *, ftnlen, ftnlen); extern logical eqstr_(char *, char *, ftnlen, ftnlen); static logical svfnd1, svfnd2; static integer svctr1[2], svctr2[2]; integer obscde; doublereal lt; extern /* Subroutine */ int bodvcd_(integer *, char *, integer *, integer *, doublereal *, ftnlen); integer frcode; extern /* Subroutine */ int cidfrm_(integer *, integer *, char *, logical *, ftnlen); char frname[80]; integer trgcde; doublereal offobs[3], obsvec[3], tepoch, normal[3]; static integer svtcde; extern /* Subroutine */ int sigerr_(char *, ftnlen), chkout_(char *, ftnlen); static integer svobsc; doublereal offsun[3]; extern /* Subroutine */ int setmsg_(char *, ftnlen); doublereal sstate[6], sunvec[3], tstate[6]; static char svtarg[36]; extern /* Subroutine */ int surfnm_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); extern logical return_(void); static char svobsr[36]; extern /* Subroutine */ int vminus_(doublereal *, doublereal *); doublereal lts; /* $ Abstract */ /* Deprecated: This routine has been superseded by the SPICELIB */ /* routine ILUMIN. This routine is supported for purposes of */ /* backward compatibility only. */ /* Find the illumination angles at a specified surface point of a */ /* target 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 */ /* KERNEL */ /* NAIF_IDS */ /* SPK */ /* TIME */ /* $ Keywords */ /* GEOMETRY */ /* MOSPICE */ /* $ Declarations */ /* $ 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 */ /* -------- --- -------------------------------------------------- */ /* TARGET I Name of target body. */ /* ET I Epoch in ephemeris seconds past J2000. */ /* ABCORR I Desired aberration correction. */ /* OBSRVR I Name of observing body. */ /* SPOINT I Body-fixed coordinates of a target surface point. */ /* PHASE O Phase angle at the surface point. */ /* SOLAR O Solar incidence angle at the surface point. */ /* EMISSN O Emission angle at the surface point. */ /* $ Detailed_Input */ /* TARGET is the name of the target body. TARGET is */ /* case-insensitive, and leading and trailing blanks */ /* in TARGET are not significant. Optionally, you may */ /* supply a string containing the integer ID code for */ /* the object. For example both 'MOON' and '301' are */ /* legitimate strings that indicate the moon is the */ /* target body. */ /* ET is the epoch, specified in ephemeris seconds past */ /* J2000, at which the apparent illumination angles at */ /* the specified surface point on the target body, as */ /* seen from the observing body, are to be computed. */ /* ABCORR is the aberration correction to be used in */ /* computing the location and orientation of the */ /* target body and the location of the Sun. Possible */ /* values are: */ /* 'NONE' No aberration correction. */ /* 'LT' Correct the position and */ /* orientation of target body for */ /* light time, and correct the */ /* position of the Sun for light */ /* time. */ /* 'LT+S' Correct the observer-target vector */ /* for light time and stellar */ /* aberration, correct the */ /* orientation of the target body */ /* for light time, and correct the */ /* target-Sun vector for light time */ /* and stellar aberration. */ /* '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). Whether the 'CN+S' */ /* solution is substantially more */ /* accurate than the 'LT' solution */ /* depends on the geometry of the */ /* participating objects and on the */ /* accuracy of the input data. In */ /* all cases this routine will */ /* execute more slowly when a */ /* converged solution is computed. */ /* See the Particulars section of */ /* SPKEZR for a discussion of */ /* precision of light time */ /* corrections. */ /* Both the state and rotation of */ /* the target body are corrected for */ /* light time. */ /* 'CN+S' Converged Newtonian light time */ /* correction and stellar aberration */ /* correction. */ /* Both the state and rotation of */ /* the target body are corrected for */ /* light time. */ /* OBSRVR is the name of the observing body, typically a */ /* spacecraft, the earth, or a surface point on the */ /* earth. OBSRVR is case-insensitive, and leading */ /* and trailing blanks in OBSRVR are not significant. */ /* Optionally, you may supply a string containing the */ /* integer ID code for the object. For example both */ /* 'EARTH' and '399' are legitimate strings that */ /* indicate the earth is the observer. */ /* OBSRVR may be not be identical to TARGET. */ /* SPOINT is a surface point on the target body, expressed */ /* in rectangular body-fixed (body equator and prime */ /* meridian) coordinates. SPOINT need not be visible */ /* from the observer's location at time ET. */ /* $ Detailed_Output */ /* PHASE is the phase angle at SPOINT, as seen from OBSRVR */ /* at time ET. This is the angle between the */ /* SPOINT-OBSRVR vector and the SPOINT-Sun vector. */ /* Units are radians. The range of PHASE is [0, pi]. */ /* See Particulars below for a detailed discussion of */ /* the definition. */ /* SOLAR is the solar incidence angle at SPOINT, as seen */ /* from OBSRVR at time ET. This is the angle */ /* between the surface normal vector at SPOINT and the */ /* SPOINT-Sun vector. Units are radians. The range */ /* of SOLAR is [0, pi]. See Particulars below for a */ /* detailed discussion of the definition. */ /* EMISSN is the emission angle at SPOINT, as seen from */ /* OBSRVR at time ET. This is the angle between the */ /* surface normal vector at SPOINT and the */ /* SPOINT-observer vector. Units are radians. The */ /* range of EMISSN is [0, pi]. See Particulars below */ /* for a detailed discussion of the definition. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If TARGET and OBSRVR are not distinct, the error */ /* SPICE(BODIESNOTDISTINCT) will be signaled. */ /* 2) If no SPK (ephemeris) data are available for the observer, */ /* target, and Sun at the time specified by ET, the error will */ /* be diagnosed by routines called by this routine. If light */ /* time corrections are used, SPK data for the target body must */ /* be available at the time ET - LT, where LT is the one-way */ /* light time from the target to the observer at ET. */ /* Additionally, SPK data must be available for the Sun at the */ /* time ET - LT - LT2, where LT2 is the light time from the Sun */ /* to the target body at time ET - LT. */ /* 3) If PCK data defining the orientation or shape of the target */ /* body are unavailable, the error will be diagnosed by routines */ /* called by this routine. */ /* 4) If no body-fixed frame is associated with the target body, */ /* the error SPICE(NOFRAME) is signaled. */ /* 5) If name of target or observer cannot be translated to its */ /* NAIF ID code, the error SPICE(IDCODENOTFOUND) is signaled. */ /* $ Files */ /* No files are input to this routine. However, ILLUM expects */ /* that the appropriate SPK and PCK files have been loaded via */ /* FURNSH. */ /* $ Particulars */ /* The term "illumination angles" refers to following set of */ /* angles: */ /* solar incidence angle Angle between the surface normal at */ /* the specified surface point and the */ /* vector from the surface point to the */ /* Sun. */ /* emission angle Angle between the surface normal at */ /* the specified surface point and the */ /* vector from the surface point to the */ /* observer. */ /* phase angle Angle between the vectors from the */ /* surface point to the observing body's */ /* location and from the surface point */ /* to the Sun. */ /* The diagram below illustrates the geometrical relationships */ /* defining these angles. The labels for the solar incidence, */ /* emission, and phase angles are "s.i.", "e.", and "phase". */ /* * */ /* Sun */ /* surface normal vector */ /* ._ _. */ /* |\ /| Sun vector */ /* \ phase / */ /* \ . . / */ /* . . */ /* \ ___ / */ /* . \/ \/ */ /* _\ s.i./ */ /* . / \ / */ /* . | e. \ / */ /* * <--------------- * surface point on */ /* viewing vector target body */ /* location to viewing */ /* (observer) location */ /* Note that if the target-observer vector, the target normal vector */ /* at the surface point, and the target-sun vector are coplanar, */ /* then phase is the sum of incidence and emission. This is rarely */ /* true; usually */ /* phase angle < solar incidence angle + emission angle */ /* All of the above angles can be computed using light time */ /* corrections, light time and stellar aberration corrections, or */ /* no aberration corrections. The way aberration corrections */ /* are used is described below. */ /* Care must be used in computing light time corrections. The */ /* guiding principle used here is "describe what appears in */ /* an image." We ignore differential light time; the light times */ /* from all points on the target to the observer are presumed to be */ /* equal. */ /* Observer-target body vector */ /* --------------------------- */ /* Let ET be the epoch at which an observation or remote */ /* sensing measurement is made, and let ET - LT ("LT" stands */ /* for "light time") be the epoch at which the photons received */ /* at ET were emitted from the body (we use the term "emitted" */ /* loosely here). */ /* The correct observer-target vector points from the observer's */ /* location at ET to the target body's location at ET - LT. */ /* The target-observer vector points in the opposite direction. */ /* Since light time corrections are not symmetric, the correct */ /* target-observer vector CANNOT be found by computing the light */ /* time corrected position of the observer as seen from the */ /* target body. */ /* Target body's orientation */ /* ------------------------- */ /* Using the definitions of ET and LT above, the target */ /* body's orientation at ET - LT is used. The surface */ /* normal is dependent on the target body's orientation, so */ /* the body's orientation model must be evaluated for the correct */ /* epoch. */ /* Target body -- Sun vector */ /* ------------------------- */ /* All surface features on the target body will appear in */ /* a measurement made at ET as they were at ET-LT. In */ /* particular, lighting on the target body is dependent on */ /* the apparent location of the Sun as seen from the target */ /* body at ET-LT. So, a second light time correction is used */ /* in finding the apparent location of the Sun. */ /* Stellar aberration corrections, when used, are applied as follows: */ /* Observer-target body vector */ /* --------------------------- */ /* In addition to light time correction, stellar aberration is */ /* used in computing the apparent target body position as seen */ /* from the observer's location at time ET. This apparent */ /* position defines the observer-target body vector. */ /* Target body-Sun vector */ /* ---------------------- */ /* The target body-Sun vector is the apparent position of the Sun, */ /* corrected for light time and stellar aberration, as seen from */ /* the target body at time ET-LT. Note that the target body's */ /* position is not affected by the stellar aberration correction */ /* applied in finding its apparent position as seen by the */ /* observer. */ /* Once all of the vectors, as well as the target body's */ /* orientation, have been computed with the proper aberration */ /* corrections, the element of time is eliminated from the */ /* computation. The problem becomes a purely geometrical one, */ /* and is described by the diagram above. */ /* $ Examples */ /* The numerical results shown for this example may differ across */ /* platforms. The results depend on the SPICE kernels used as */ /* input, the compiler and supporting libraries, and the machine */ /* specific arithmetic implementation. */ /* In the following example program, the file */ /* spk_m_031103-040201_030502.bsp */ /* is a binary SPK file containing data for Mars Global Surveyor, */ /* Mars, and the Sun for a time interval bracketing the date */ /* 2004 JAN 1 12:00:00 UTC. */ /* pck00007.tpc is a planetary constants kernel file containing */ /* radii and rotation model constants. naif0007.tls is a */ /* leapseconds kernel. */ /* Find the phase, solar incidence, and emission angles at the */ /* sub-solar and sub-spacecraft points on Mars as seen from the */ /* Mars Global Surveyor spacecraft at a specified UTC time. */ /* Use light time and stellar aberration corrections. */ /* PROGRAM ANGLES */ /* IMPLICIT NONE */ /* C */ /* C SPICELIB functions */ /* C */ /* DOUBLE PRECISION DPR */ /* C */ /* C Local parameters */ /* C */ /* INTEGER NAMLEN */ /* PARAMETER ( NAMLEN = 32 ) */ /* INTEGER TIMLEN */ /* PARAMETER ( TIMLEN = 25 ) */ /* C */ /* C Local variables */ /* C */ /* CHARACTER*(NAMLEN) OBSRVR */ /* CHARACTER*(NAMLEN) TARGET */ /* CHARACTER*(TIMLEN) UTC */ /* DOUBLE PRECISION ALT */ /* DOUBLE PRECISION ET */ /* DOUBLE PRECISION SSCEMI */ /* DOUBLE PRECISION SSCPHS */ /* DOUBLE PRECISION SSCSOL */ /* DOUBLE PRECISION SSLEMI */ /* DOUBLE PRECISION SSLPHS */ /* DOUBLE PRECISION SSLSOL */ /* DOUBLE PRECISION SSOLPT ( 3 ) */ /* DOUBLE PRECISION SSCPT ( 3 ) */ /* C */ /* C Load kernel files. */ /* C */ /* CALL FURNSH ( 'naif0007.tls' ) */ /* CALL FURNSH ( 'pck00007.tpc' ) */ /* CALL FURNSH ( 'spk_m_031103-040201_030502.bsp' ) */ /* C */ /* C Convert our UTC time to ephemeris seconds past J2000. */ /* C */ /* UTC = '2004 JAN 1 12:00:00' */ /* CALL UTC2ET ( UTC, ET ) */ /* C */ /* C Assign observer and target names. The acronym MGS */ /* C indicates Mars Global Surveyor. See NAIF_IDS for a */ /* C list of names recognized by SPICE. */ /* C */ /* TARGET = 'Mars' */ /* OBSRVR = 'MGS' */ /* C */ /* C Find the sub-solar point on the Earth as seen from */ /* C the MGS spacecraft at ET. Use the "surface intercept" */ /* C style of sub-point definition. This makes it easy */ /* C to verify the solar incidence angle. */ /* C */ /* CALL SUBSOL ( 'Near point', TARGET, ET, */ /* . 'LT+S', OBSRVR, SSOLPT ) */ /* C */ /* C Now find the sub-spacecraft point. Use the */ /* C "nearest point" definition of the sub-point */ /* C here---this makes it easy to verify the emission angle. */ /* C */ /* CALL SUBPT ( 'Near point', TARGET, ET, */ /* . 'LT+S', OBSRVR, SSCPT, ALT ) */ /* C */ /* C Find the phase, solar incidence, and emission */ /* C angles at the sub-solar point on the Earth as seen */ /* C from Mars Observer at time ET. */ /* C */ /* CALL ILLUM ( TARGET, ET, 'LT+S', OBSRVR, */ /* . SSOLPT, SSLPHS, SSLSOL, SSLEMI ) */ /* C */ /* C Do the same for the sub-spacecraft point. */ /* C */ /* CALL ILLUM ( TARGET, ET, 'LT+S', OBSRVR, */ /* . SSCPT, SSCPHS, SSCSOL, SSCEMI ) */ /* C */ /* C Convert the angles to degrees and write them out. */ /* C */ /* SSLPHS = DPR() * SSLPHS */ /* SSLSOL = DPR() * SSLSOL */ /* SSLEMI = DPR() * SSLEMI */ /* SSCPHS = DPR() * SSCPHS */ /* SSCSOL = DPR() * SSCSOL */ /* SSCEMI = DPR() * SSCEMI */ /* WRITE (*,*) ' ' */ /* WRITE (*,*) 'UTC epoch is ', UTC */ /* WRITE (*,*) ' ' */ /* WRITE (*,*) 'Illumination angles at the sub-solar point:' */ /* WRITE (*,*) ' ' */ /* WRITE (*,*) 'Phase angle (deg.): ', SSLPHS */ /* WRITE (*,*) 'Solar incidence angle (deg.): ', SSLSOL */ /* WRITE (*,*) 'Emission angle (deg.): ', SSLEMI */ /* WRITE (*,*) ' ' */ /* WRITE (*,*) 'The solar incidence angle should be 0.' */ /* WRITE (*,*) 'The emission and phase angles should be equal.' */ /* WRITE (*,*) ' ' */ /* WRITE (*,*) 'Illumination angles at the sub-s/c point:' */ /* WRITE (*,*) ' ' */ /* WRITE (*,*) 'Phase angle (deg.): ', SSCPHS */ /* WRITE (*,*) 'Solar incidence angle (deg.): ', SSCSOL */ /* WRITE (*,*) 'Emission angle (deg.): ', SSCEMI */ /* WRITE (*,*) ' ' */ /* WRITE (*,*) 'The emission angle should be 0.' */ /* WRITE (*,*) 'The solar incidence and phase angles should '// */ /* . 'be equal.' */ /* END */ /* When this program is executed, the output will be: */ /* UTC epoch is 2004 JAN 1 12:00:00 */ /* Illumination angles at the sub-solar point: */ /* Phase angle (deg.): 150.210714 */ /* Solar incidence angle (deg.): 6.3735213E-15 */ /* Emission angle (deg.): 150.210714 */ /* The solar incidence angle should be 0. */ /* The emission and phase angles should be equal. */ /* Illumination angles at the sub-s/c point: */ /* Phase angle (deg.): 123.398202 */ /* Solar incidence angle (deg.): 123.398202 */ /* Emission angle (deg.): 6.36110936E-15 */ /* The emission angle should be 0. */ /* The solar incidence and phase angles should be equal. */ /* $ Restrictions */ /* None. */ /* $ Literature_References */ /* None. */ /* $ Author_and_Institution */ /* C.H. Acton (JPL) */ /* B.V. Semenov (JPL) */ /* N.J. Bachman (JPL) */ /* $ Version */ /* - SPICELIB Version 1.3.0, 04-JUL-2014 (NJB) (BVS) */ /* Discussion of light time corrections was updated. Assertions */ /* that converged light time corrections are unlikely to be */ /* useful were removed. */ /* Last update was 19-SEP-2013 (BVS) */ /* Updated to save the input body names and ZZBODTRN state */ /* counters and to do name-ID conversions only if the counters */ /* have changed. */ /* - SPICELIB Version 1.2.2, 18-MAY-2010 (BVS) */ /* Index lines now state that this routine is deprecated. */ /* - SPICELIB Version 1.2.1, 07-FEB-2008 (NJB) */ /* Abstract now states that this routine is deprecated. */ /* - SPICELIB Version 1.2.0, 23-OCT-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VSUB calls. Replaced call to BODVAR with call to BODVCD. */ /* - SPICELIB Version 1.1.0, 22-JUL-2004 (NJB) */ /* Updated to support representations of integers in the input */ /* arguments TARGET and OBSRVR. */ /* - SPICELIB Version 1.0.2, 27-JUL-2003 (NJB) (CHA) */ /* Various header corrections were made. The example program */ /* was upgraded to use real kernels, and the program's output is */ /* shown. */ /* - SPICELIB Version 1.0.1, 10-JUL-2002 (NJB) */ /* Updated Index_Entries header section. */ /* - SPICELIB Version 1.0.0, 21-MAR-1999 (NJB) */ /* Adapted from the MGSSPICE version dated 10-MAR-1992. */ /* -& */ /* $ Index_Entries */ /* DEPRECATED illumination angles */ /* DEPRECATED lighting angles */ /* DEPRECATED phase angle */ /* DEPRECATED solar incidence angle */ /* DEPRECATED emission angle */ /* -& */ /* $ Revisions */ /* - SPICELIB Version 1.2.0, 23-OCT-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VSUB calls. Replaced call to BODVAR with call to BODVCD. */ /* - SPICELIB Version 1.1.0, 22-JUL-2004 (NJB) */ /* Updated to support representations of integers in the */ /* input arguments TARGET and OBSRVR: calls to BODN2C */ /* were replaced by calls to BODS2C. */ /* -& */ /* SPICELIB functions */ /* Local parameters */ /* Saved body name length. */ /* Local variables */ /* Saved name/ID item declarations. */ /* Saved name/ID items. */ /* Initial values. */ /* Standard SPICE error handling. */ if (return_()) { return 0; } else { chkin_("ILLUM", (ftnlen)5); } /* Initialization. */ if (first) { /* Initialize counters. */ zzctruin_(svctr1); zzctruin_(svctr2); first = FALSE_; } /* Obtain integer codes for the target and observer. */ zzbods2c_(svctr1, svtarg, &svtcde, &svfnd1, target, &trgcde, &found, ( ftnlen)36, target_len); if (! found) { setmsg_("The target, '#', is not a recognized name for an ephemeris " "object. The cause of this problem may be that you need an up" "dated version of the SPICE Toolkit. ", (ftnlen)155); errch_("#", target, (ftnlen)1, target_len); sigerr_("SPICE(IDCODENOTFOUND)", (ftnlen)21); chkout_("ILLUM", (ftnlen)5); return 0; } zzbods2c_(svctr2, svobsr, &svobsc, &svfnd2, obsrvr, &obscde, &found, ( ftnlen)36, obsrvr_len); if (! found) { setmsg_("The observer, '#', is not a recognized name for an ephemeri" "s object. The cause of this problem may be that you need an " "updated version of the SPICE Toolkit. ", (ftnlen)157); errch_("#", obsrvr, (ftnlen)1, obsrvr_len); sigerr_("SPICE(IDCODENOTFOUND)", (ftnlen)21); chkout_("ILLUM", (ftnlen)5); return 0; } /* The observer and target must be distinct. */ if (trgcde == obscde) { setmsg_("Target is #; observer is #.", (ftnlen)27); errch_("#", target, (ftnlen)1, target_len); errch_("#", obsrvr, (ftnlen)1, obsrvr_len); sigerr_("SPICE(BODIESNOTDISTINCT)", (ftnlen)24); chkout_("ILLUM", (ftnlen)5); return 0; } /* Find the name of the body-fixed frame associated with the */ /* target body. We'll want the state of the target relative to */ /* the observer in this body-fixed frame. */ cidfrm_(&trgcde, &frcode, frname, &found, (ftnlen)80); if (! found) { setmsg_("No body-fixed frame is associated with target body #; a fra" "me kernel must be loaded to make this association. Consult " "the FRAMES Required Reading for details.", (ftnlen)159); errch_("#", target, (ftnlen)1, target_len); sigerr_("SPICE(NOFRAME)", (ftnlen)14); chkout_("ILLUM", (ftnlen)5); return 0; } /* Find the body-fixed state of the target as seen from the observer */ /* at ET. The appropriate aberration corrections will be used in */ /* evaluating this state. */ spkez_(&trgcde, et, frname, abcorr, &obscde, tstate, <, (ftnlen)80, abcorr_len); /* Determine the epoch to be used in computing the target-Sun vector. */ if (eqstr_(abcorr, "NONE", abcorr_len, (ftnlen)4)) { tepoch = *et; } else { tepoch = *et - lt; } /* Find the body-fixed state of the Sun as seen from the target at */ /* TEPOCH. */ spkez_(&c__10, &tepoch, frname, abcorr, &trgcde, sstate, <s, (ftnlen)80, abcorr_len); /* Grab the position portions of the states (the first three */ /* elements of each state). Negate the observer-target vector, */ /* since the vector required for the illumination angle */ /* computation is the target-observer vector. The vectors we've */ /* found point from the target body center to the observer and */ /* Sun, and already take light time corrections into account. */ vminus_(tstate, obsvec); vequ_(sstate, sunvec); /* Now we'll modify target-observer and target-Sun vectors to */ /* take into account the offset between the target center and the */ /* surface point of interest; we want the vectors to point from */ /* the surface point to the observer and Sun respectively. */ vsub_(obsvec, spoint, offobs); vsub_(sunvec, spoint, offsun); /* Find the surface normal at SPOINT. We'll need the radii of the */ /* target body. */ bodvcd_(&trgcde, "RADII", &c__3, &n, radii, (ftnlen)5); surfnm_(radii, &radii[1], &radii[2], spoint, normal); /* Find the illumination angles. VSEP will give us angular */ /* separation in radians. */ *phase = vsep_(offsun, offobs); *solar = vsep_(normal, offsun); *emissn = vsep_(normal, offobs); chkout_("ILLUM", (ftnlen)5); return 0; } /* illum_ */
/* $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 ZZEDTERM ( Ellipsoid terminator ) */ /* Subroutine */ int zzedterm_(char *type__, doublereal *a, doublereal *b, doublereal *c__, doublereal *srcrad, doublereal *srcpos, integer * npts, doublereal *trmpts, ftnlen type_len) { /* System generated locals */ integer trmpts_dim2, i__1, i__2; doublereal d__1, d__2, d__3; /* Builtin functions */ integer s_cmp(char *, char *, ftnlen, ftnlen); double asin(doublereal); integer s_rnge(char *, integer, char *, integer); double d_sign(doublereal *, doublereal *); /* Local variables */ extern /* Subroutine */ int vadd_(doublereal *, doublereal *, doublereal * ); doublereal rmin, rmax; extern /* Subroutine */ int vscl_(doublereal *, doublereal *, doublereal * ); extern doublereal vdot_(doublereal *, doublereal *), vsep_(doublereal *, doublereal *); integer nitr; extern /* Subroutine */ int vsub_(doublereal *, doublereal *, doublereal * ), vequ_(doublereal *, doublereal *); doublereal d__, e[3]; integer i__; doublereal s, angle, v[3], x[3], delta, y[3], z__[3], inang; extern /* Subroutine */ int chkin_(char *, ftnlen), frame_(doublereal *, doublereal *, doublereal *); doublereal plane[4]; extern /* Subroutine */ int ucase_(char *, char *, ftnlen, ftnlen), errch_(char *, char *, ftnlen, ftnlen), vpack_(doublereal *, doublereal *, doublereal *, doublereal *); doublereal theta; extern /* Subroutine */ int errdp_(char *, doublereal *, ftnlen); doublereal trans[9] /* was [3][3] */, srcpt[3], vtemp[3]; extern doublereal vnorm_(doublereal *), twopi_(void); extern /* Subroutine */ int ljust_(char *, char *, ftnlen, ftnlen), pl2nvc_(doublereal *, doublereal *, doublereal *); doublereal lambda; extern /* Subroutine */ int nvp2pl_(doublereal *, doublereal *, doublereal *); extern doublereal halfpi_(void); doublereal minang, minrad, maxang, maxrad; extern /* Subroutine */ int latrec_(doublereal *, doublereal *, doublereal *, doublereal *); doublereal angerr; logical umbral; extern doublereal touchd_(doublereal *); doublereal offset[3], prvdif; extern /* Subroutine */ int sigerr_(char *, ftnlen); doublereal outang, plcons, prvang; extern /* Subroutine */ int chkout_(char *, ftnlen), setmsg_(char *, ftnlen), errint_(char *, integer *, ftnlen); char loctyp[50]; extern logical return_(void); extern /* Subroutine */ int vminus_(doublereal *, doublereal *); doublereal dir[3]; extern /* Subroutine */ int mxv_(doublereal *, doublereal *, doublereal *) ; doublereal vtx[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. */ /* Compute a set of points on the umbral or penumbral terminator of */ /* a specified ellipsoid, given a spherical light source. */ /* $ 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 */ /* ELLIPSES */ /* $ Keywords */ /* BODY */ /* GEOMETRY */ /* MATH */ /* $ Declarations */ /* $ Brief_I/O */ /* Variable I/O Description */ /* -------- --- -------------------------------------------------- */ /* TYPE I Terminator type. */ /* A I Length of ellipsoid semi-axis lying on the x-axis. */ /* B I Length of ellipsoid semi-axis lying on the y-axis. */ /* C I Length of ellipsoid semi-axis lying on the z-axis. */ /* SRCRAD I Radius of light source. */ /* SRCPOS I Position of center of light source. */ /* NPTS I Number of points in terminator point set. */ /* TRMPTS O Terminator point set. */ /* $ Detailed_Input */ /* TYPE is a string indicating the type of terminator to */ /* compute: umbral or penumbral. The umbral */ /* terminator is the boundary of the portion of the */ /* ellipsoid surface in total shadow. The penumbral */ /* terminator is the boundary of the portion of the */ /* surface that is completely illuminated. Possible */ /* values of TYPE are */ /* 'UMBRAL' */ /* 'PENUMBRAL' */ /* Case and leading or trailing blanks in TYPE are */ /* not significant. */ /* A, */ /* B, */ /* C are the lengths of the semi-axes of a triaxial */ /* ellipsoid. The ellipsoid is centered at the */ /* origin and oriented so that its axes lie on the */ /* x, y and z axes. A, B, and C are the lengths of */ /* the semi-axes that point in the x, y, and z */ /* directions respectively. */ /* Length units associated with A, B, and C must */ /* match those associated with SRCRAD, SRCPOS, */ /* and the output TRMPTS. */ /* SRCRAD is the radius of the spherical light source. */ /* SRCPOS is the position of the center of the light source */ /* relative to the center of the ellipsoid. */ /* NPTS is the number of terminator points to compute. */ /* $ Detailed_Output */ /* TRMPTS is an array of points on the umbral or penumbral */ /* terminator of the ellipsoid, as specified by the */ /* input argument TYPE. The Ith point is contained */ /* in the array elements */ /* TRMPTS(J,I), J = 1, 2, 3 */ /* The terminator points are expressed in the */ /* body-fixed reference frame associated with the */ /* ellipsoid. Units are those associated with */ /* the input axis lengths. */ /* Each terminator point is the point of tangency of */ /* a plane that is also tangent to the light source. */ /* These associated points of tangency on the light */ /* source have uniform distribution in longitude when */ /* expressed in a cylindrical coordinate system whose */ /* Z-axis is SRCPOS. The magnitude of the separation */ /* in longitude between these tangency points on the */ /* light source is */ /* 2*Pi / NPTS */ /* If the target is spherical, the terminator points */ /* also are uniformly distributed in longitude in the */ /* cylindrical system described above. If the target */ /* is non-spherical, the longitude distribution of */ /* the points generally is not uniform. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If the terminator type is not recognized, the error */ /* SPICE(NOTSUPPORTED) is signaled. */ /* 2) If the set size NPTS is not at least 1, the error */ /* SPICE(INVALIDSIZE) is signaled. */ /* 3) If any of the ellipsoid's semi-axis lengths is non-positive, */ /* the error SPICE(INVALIDAXISLENGTH) is signaled. */ /* 4) If the light source has non-positive radius, the error */ /* SPICE(INVALIDRADIUS) is signaled. */ /* 5) If the light source intersects the smallest sphere */ /* centered at the origin and containing the ellipsoid, the */ /* error SPICE(OBJECTSTOOCLOSE) is signaled. */ /* $ Files */ /* None. */ /* $ Particulars */ /* This routine models the boundaries of shadow regions on an */ /* ellipsoid "illuminated" by a spherical light source. Light rays */ /* are assumed to travel along straight lines; refraction is not */ /* modeled. */ /* Points on the ellipsoid at which the entire cap of the light */ /* source is visible are considered to be completely illuminated. */ /* Points on the ellipsoid at which some portion (or all) of the cap */ /* of the light source are blocked are considered to be in partial */ /* (or total) shadow. */ /* In this routine, we use the term "umbral terminator" to denote */ /* the curve ususally called the "terminator": this curve is the */ /* boundary of the portion of the surface that lies in total shadow. */ /* We use the term "penumbral terminator" to denote the boundary of */ /* the completely illuminated portion of the surface. */ /* In general, the terminator on an ellipsoid is a more complicated */ /* curve than the limb (which is always an ellipse). Aside from */ /* various special cases, the terminator does not lie in a plane. */ /* However, the condition for a point X on the ellipsoid to lie on */ /* the terminator is simple: a plane tangent to the ellipsoid at X */ /* must also be tangent to the light source. If this tangent plane */ /* does not intersect the vector from the center of the ellipsoid to */ /* the center of the light source, then X lies on the umbral */ /* terminator; otherwise X lies on the penumbral terminator. */ /* $ Examples */ /* See the SPICELIB routine EDTERM. */ /* $ Restrictions */ /* This is a private SPICELIB routine. User applications should not */ /* call this routine. */ /* $ Literature_References */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* $ Version */ /* - SPICELIB Version 1.0.0, 03-FEB-2007 (NJB) */ /* -& */ /* $ Index_Entries */ /* find terminator on ellipsoid */ /* find umbral terminator on ellipsoid */ /* find penumbral terminator on ellipsoid */ /* -& */ /* SPICELIB functions */ /* Local parameters */ /* Local variables */ /* Standard SPICELIB error handling. */ /* Parameter adjustments */ trmpts_dim2 = *npts; /* Function Body */ if (return_()) { return 0; } chkin_("ZZEDTERM", (ftnlen)8); /* Check the terminator type. */ ljust_(type__, loctyp, type_len, (ftnlen)50); ucase_(loctyp, loctyp, (ftnlen)50, (ftnlen)50); if (s_cmp(loctyp, "UMBRAL", (ftnlen)50, (ftnlen)6) == 0) { umbral = TRUE_; } else if (s_cmp(loctyp, "PENUMBRAL", (ftnlen)50, (ftnlen)9) == 0) { umbral = FALSE_; } else { setmsg_("Terminator type must be UMBRAL or PENUMBRAL but was actuall" "y #.", (ftnlen)63); errch_("#", type__, (ftnlen)1, type_len); sigerr_("SPICE(NOTSUPPORTED)", (ftnlen)19); chkout_("ZZEDTERM", (ftnlen)8); return 0; } /* Check the terminator set dimension. */ if (*npts < 1) { setmsg_("Set must contain at least one point; NPTS = #.", (ftnlen)47) ; errint_("#", npts, (ftnlen)1); sigerr_("SPICE(INVALIDSIZE)", (ftnlen)18); chkout_("ZZEDTERM", (ftnlen)8); return 0; } /* The ellipsoid semi-axes must have positive length. */ if (*a <= 0. || *b <= 0. || *c__ <= 0.) { setmsg_("Semi-axis lengths: A = #, B = #, C = #. ", (ftnlen)41); errdp_("#", a, (ftnlen)1); errdp_("#", b, (ftnlen)1); errdp_("#", c__, (ftnlen)1); sigerr_("SPICE(INVALIDAXISLENGTH)", (ftnlen)24); chkout_("ZZEDTERM", (ftnlen)8); return 0; } /* Check the input light source radius. */ if (*srcrad <= 0.) { setmsg_("Light source must have positive radius; actual radius was #." , (ftnlen)60); errdp_("#", srcrad, (ftnlen)1); sigerr_("SPICE(INVALIDRADIUS)", (ftnlen)20); chkout_("ZZEDTERM", (ftnlen)8); return 0; } /* The light source must not intersect the outer bounding */ /* sphere of the ellipsoid. */ d__ = vnorm_(srcpos); /* Computing MAX */ d__1 = max(*a,*b); rmax = max(d__1,*c__); /* Computing MIN */ d__1 = min(*a,*b); rmin = min(d__1,*c__); if (*srcrad + rmax >= d__) { /* The light source is too close. */ setmsg_("Light source intersects outer bounding sphere of the ellips" "oid. Light source radius = #; ellipsoid's longest axis = #;" " sum = #; distance between centers = #.", (ftnlen)158); errdp_("#", srcrad, (ftnlen)1); errdp_("#", &rmax, (ftnlen)1); d__1 = *srcrad + rmax; errdp_("#", &d__1, (ftnlen)1); errdp_("#", &d__, (ftnlen)1); sigerr_("SPICE(OBJECTSTOOCLOSE)", (ftnlen)22); chkout_("ZZEDTERM", (ftnlen)8); return 0; } /* Find bounds on the angular size of the target as seen */ /* from the source. */ /* Computing MIN */ d__1 = rmax / d__; minang = asin((min(d__1,1.))); /* Computing MIN */ d__1 = rmin / d__; maxang = asin((min(d__1,1.))); /* Let the inverse of the ellipsoid-light source vector be the */ /* Z-axis of a frame we'll use to generate the terminator set. */ vminus_(srcpos, z__); frame_(z__, x, y); /* Create the rotation matrix required to convert vectors */ /* from the source-centered frame back to the target body-fixed */ /* frame. */ vequ_(x, trans); vequ_(y, &trans[3]); vequ_(z__, &trans[6]); /* Find the maximum and minimum target radii. */ /* Computing MAX */ d__1 = max(*a,*b); maxrad = max(d__1,*c__); /* Computing MIN */ d__1 = min(*a,*b); minrad = min(d__1,*c__); if (umbral) { /* Compute the angular offsets from the axis of rays tangent to */ /* both the source and the bounding spheres of the target, where */ /* the tangency points lie in a half-plane bounded by the line */ /* containing the origin and SRCPOS. (We'll call this line */ /* the "axis.") */ /* OUTANG corresponds to the target's outer bounding sphere; */ /* INANG to the inner bounding sphere. */ outang = asin((*srcrad - maxrad) / d__); inang = asin((*srcrad - minrad) / d__); } else { /* Compute the angular offsets from the axis of rays tangent to */ /* both the source and the bounding spheres of the target, where */ /* the tangency points lie in opposite half-planes bounded by the */ /* axis (compare the case above). */ /* OUTANG corresponds to the target's outer bounding sphere; */ /* INANG to the inner bounding sphere. */ outang = asin((*srcrad + maxrad) / d__); inang = asin((*srcrad + minrad) / d__); } /* Compute the angular delta we'll use for generating */ /* terminator points. */ delta = twopi_() / *npts; /* Generate the terminator points. */ i__1 = *npts; for (i__ = 1; i__ <= i__1; ++i__) { theta = (i__ - 1) * delta; /* Let SRCPT be the surface point on the source lying in */ /* the X-Y plane of the frame produced by FRAME */ /* and corresponding to the angle THETA. */ latrec_(srcrad, &theta, &c_b30, srcpt); /* Now solve for the angle by which SRCPT must be rotated (toward */ /* +Z in the umbral case, away from +Z in the penumbral case) */ /* so that a plane tangent to the source at SRCPT is also tangent */ /* to the target. The rotation is bracketed by OUTANG on the low */ /* side and INANG on the high side in the umbral case; the */ /* bracketing values are reversed in the penumbral case. */ if (umbral) { angle = outang; } else { angle = inang; } prvdif = twopi_(); prvang = angle + halfpi_(); nitr = 0; for(;;) { /* while(complicated condition) */ d__2 = (d__1 = angle - prvang, abs(d__1)); if (!(nitr <= 10 && touchd_(&d__2) < prvdif)) break; ++nitr; d__2 = (d__1 = angle - prvang, abs(d__1)); prvdif = touchd_(&d__2); prvang = angle; /* Find the closest point on the ellipsoid to the plane */ /* corresponding to "ANGLE". */ /* The tangent point on the source is obtained by rotating */ /* SRCPT by ANGLE towards +Z. The plane's normal vector is */ /* parallel to VTX in the source-centered frame. */ latrec_(srcrad, &theta, &angle, vtx); vequ_(vtx, dir); /* VTX and DIR are expressed in the source-centered frame. We */ /* must translate VTX to the target frame and rotate both */ /* vectors into that frame. */ mxv_(trans, vtx, vtemp); vadd_(srcpos, vtemp, vtx); mxv_(trans, dir, vtemp); vequ_(vtemp, dir); /* Create the plane defined by VTX and DIR. */ nvp2pl_(dir, vtx, plane); /* Find the closest point on the ellipsoid to the plane. At */ /* the point we seek, the outward normal on the ellipsoid is */ /* parallel to the choice of plane normal that points away */ /* from the origin. We can always obtain this choice from */ /* PL2NVC. */ pl2nvc_(plane, dir, &plcons); /* At the point */ /* E = (x, y, z) */ /* on the ellipsoid's surface, an outward normal */ /* is */ /* N = ( x/A**2, y/B**2, z/C**2 ) */ /* which is also */ /* lambda * ( DIR(1), DIR(2), DIR(3) ) */ /* Equating components in the normal vectors yields */ /* E = lambda * ( DIR(1)*A**2, DIR(2)*B**2, DIR(3)*C**2 ) */ /* Taking the inner product with the point E itself and */ /* applying the ellipsoid equation, we find */ /* lambda * <DIR, E> = < N, E > = 1 */ /* The first term above is */ /* lambda**2 * || ( A*DIR(1), B*DIR(2), C*DIR(3) ) ||**2 */ /* So the positive root lambda is */ /* 1 / || ( A*DIR(1), B*DIR(2), C*DIR(3) ) || */ /* Having lambda we can compute E. */ d__1 = *a * dir[0]; d__2 = *b * dir[1]; d__3 = *c__ * dir[2]; vpack_(&d__1, &d__2, &d__3, v); lambda = 1. / vnorm_(v); d__1 = *a * v[0]; d__2 = *b * v[1]; d__3 = *c__ * v[2]; vpack_(&d__1, &d__2, &d__3, e); vscl_(&lambda, e, &trmpts[(i__2 = i__ * 3 - 3) < trmpts_dim2 * 3 && 0 <= i__2 ? i__2 : s_rnge("trmpts", i__2, "zzedterm_", (ftnlen)586)]); /* Make a new estimate of the plane rotation required to touch */ /* the target. */ vsub_(&trmpts[(i__2 = i__ * 3 - 3) < trmpts_dim2 * 3 && 0 <= i__2 ? i__2 : s_rnge("trmpts", i__2, "zzedterm_", (ftnlen)592)] , vtx, offset); /* Let ANGERR be an estimate of the magnitude of angular error */ /* between the plane and the terminator. */ angerr = vsep_(dir, offset) - halfpi_(); /* Let S indicate the sign of the altitude error: where */ /* S is positive, the plane is above E. */ d__1 = vdot_(e, dir); s = d_sign(&c_b35, &d__1); if (umbral) { /* If the plane is above the target, increase the */ /* rotation angle; otherwise decrease the angle. */ angle += s * angerr; } else { /* This is the penumbral case; decreasing the angle */ /* "lowers" the plane toward the target. */ angle -= s * angerr; } } } chkout_("ZZEDTERM", (ftnlen)8); return 0; } /* zzedterm_ */
/* $Procedure SPKE15 ( Evaluate a type 15 SPK data record) */ /* Subroutine */ int spke15_(doublereal *et, doublereal *recin, doublereal * state) { /* System generated locals */ doublereal d__1; /* Builtin functions */ double sqrt(doublereal), d_mod(doublereal *, doublereal *), d_sign( doublereal *, doublereal *); /* Local variables */ doublereal near__, dmdt; extern /* Subroutine */ int vscl_(doublereal *, doublereal *, doublereal * ); extern doublereal vdot_(doublereal *, doublereal *), vsep_(doublereal *, doublereal *); extern /* Subroutine */ int vequ_(doublereal *, doublereal *); integer j2flg; doublereal p, angle, dnode, z__; extern /* Subroutine */ int chkin_(char *, ftnlen); doublereal epoch, speed, dperi, theta, manom; extern /* Subroutine */ int moved_(doublereal *, integer *, doublereal *), errdp_(char *, doublereal *, ftnlen), vcrss_(doublereal *, doublereal *, doublereal *); extern doublereal twopi_(void); extern logical vzero_(doublereal *); extern /* Subroutine */ int vrotv_(doublereal *, doublereal *, doublereal *, doublereal *); doublereal oneme2, state0[6]; extern /* Subroutine */ int prop2b_(doublereal *, doublereal *, doublereal *, doublereal *); doublereal pa[3], gm, ta, dt; extern doublereal pi_(void); doublereal tp[3], pv[3], cosinc; extern /* Subroutine */ int sigerr_(char *, ftnlen), vhatip_(doublereal *) , chkout_(char *, ftnlen), vsclip_(doublereal *, doublereal *), setmsg_(char *, ftnlen); doublereal tmpsta[6], oj2; extern logical return_(void); doublereal ecc; extern doublereal dpr_(void); doublereal dot, rpl, k2pi; /* $ Abstract */ /* Evaluates a single SPK data record from a segment of type 15 */ /* (Precessing Conic Propagation). */ /* $ 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 */ /* -------- --- -------------------------------------------------- */ /* ET I Target epoch. */ /* RECIN I Data record. */ /* STATE O State (position and velocity). */ /* $ Detailed_Input */ /* ET is a target epoch, specified as ephemeris seconds past */ /* J2000, at which a state vector is to be computed. */ /* RECIN is a data record which, when evaluated at epoch ET, */ /* will give the state (position and velocity) of some */ /* body, relative to some center, in some inertial */ /* reference frame. */ /* The structure of RECIN is: */ /* RECIN(1) epoch of periapsis */ /* in ephemeris seconds past J2000. */ /* RECIN(2)-RECIN(4) unit trajectory pole vector */ /* RECIN(5)-RECIN(7) unit periapsis vector */ /* RECIN(8) semi-latus rectum---p in the */ /* equation: */ /* r = p/(1 + ECC*COS(Nu)) */ /* RECIN(9) eccentricity */ /* RECIN(10) J2 processing flag describing */ /* what J2 corrections are to be */ /* applied when the orbit is */ /* propagated. */ /* All J2 corrections are applied */ /* if this flag has a value that */ /* 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. */ /* RECIN(11)-RECIN(13) unit central body pole vector */ /* RECIN(14) central body GM */ /* RECIN(15) central body J2 */ /* RECIN(16) central body radius */ /* Units are radians, km, seconds */ /* $ Detailed_Output */ /* STATE is the state produced by evaluating RECIN at ET. */ /* Units are km and km/sec. */ /* $ Parameters */ /* None. */ /* $ Files */ /* None. */ /* $ Exceptions */ /* 1) If the eccentricity is less than zero, the error */ /* 'SPICE(BADECCENTRICITY)' will be signalled. */ /* 2) If the semi-latus rectum is non-positive, the error */ /* 'SPICE(BADLATUSRECTUM)' is signalled. */ /* 3) If the pole vector, trajectory pole vector or periapsis vector */ /* has zero length, the error 'SPICE(BADVECTOR)' is signalled. */ /* 4) If the trajectory pole vector and the periapsis vector are */ /* not orthogonal, the error 'SPICE(BADINITSTATE)' is */ /* signalled. The test for orthogonality is very crude. The */ /* routine simply checks that the absolute value of 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 tolerance. */ /* 5) If the mass of the central body is non-positive, the error */ /* 'SPICE(NONPOSITIVEMASS)' is signalled. */ /* 6) If the radius of the central body is negative, the error */ /* 'SPICE(BADRADIUS)' is signalled. */ /* $ Particulars */ /* This algorithm applies J2 corrections for precessing the */ /* node and argument of periapse for an object orbiting an */ /* oblate spheroid. */ /* Note the effects of J2 are incorporated only for elliptic */ /* orbits that do not intersect the central body. */ /* While the derivation of the effect of the various harmonics */ /* of gravitational field are beyond the scope of this header */ /* the effect of the J2 term of the gravity model are as follows */ /* The line of node precesses. Over one orbit average rate of */ /* precession, DNode/dNu, is given by */ /* 3 J2 */ /* dNode/dNu = - ----------------- DCOS( inc ) */ /* 2 (P/RPL)**2 */ /* (Since this is always less than zero for oblate spheroids, this */ /* should be called regression of nodes.) */ /* The line of apsides precesses. The average rate of precession */ /* DPeri/dNu is given by */ /* 3 J2 */ /* dPeri/dNu = ----------------- ( 5*DCOS ( inc ) - 1 ) */ /* 2 (P/RPL)**2 */ /* Details of these formulae are given in the Battin's book (see */ /* literature references below). */ /* It is assumed that this routine is used in conjunction with */ /* the routine SPKR15 as shown here: */ /* CALL SPKR15 ( HANDLE, DESCR, ET, RECIN ) */ /* CALL SPKE15 ( ET, RECIN, STATE ) */ /* where it is known in advance that the HANDLE, DESCR pair points */ /* to a type 15 data segment. */ /* $ Examples */ /* The SPKEnn routines are almost always used in conjunction with */ /* the corresponding SPKRnn routines, which read the records from */ /* SPK files. */ /* The data returned by the SPKRnn routine is in its rawest form, */ /* taken directly from the segment. As such, it will be meaningless */ /* to a user unless he/she understands the structure of the data type */ /* completely. Given that understanding, however, the SPKRnn */ /* routines might be used to examine raw segment data before */ /* evaluating it with the SPKEnn routines. */ /* C */ /* C Get a segment applicable to a specified body and epoch. */ /* C */ /* CALL SPKSFS ( BODY, ET, HANDLE, DESCR, IDENT, FOUND ) */ /* C */ /* C Look at parts of the descriptor. */ /* C */ /* CALL DAFUS ( DESCR, 2, 6, DCD, ICD ) */ /* CENTER = ICD( 2 ) */ /* REF = ICD( 3 ) */ /* TYPE = ICD( 4 ) */ /* IF ( TYPE .EQ. 15 ) THEN */ /* CALL SPKR15 ( HANDLE, DESCR, ET, RECORD ) */ /* . */ /* . Look at the RECORD data. */ /* . */ /* CALL SPKE15 ( ET, RECORD, STATE ) */ /* . */ /* . Check out the evaluated state. */ /* . */ /* END IF */ /* $ Restrictions */ /* None. */ /* $ Author_and_Institution */ /* K.R. Gehringer (JPL) */ /* S. Schlaifer (JPL) */ /* W.L. Taber (JPL) */ /* $ Literature_References */ /* [1] `Fundamentals of Celestial Mechanics', Second Edition 1989 */ /* by J.M.A. Danby; Willman-Bell, Inc., P.O. Box 35025 */ /* Richmond Virginia; pp 345-347. */ /* [2] `Astronautical Guidance', by Richard H. Battin. 1964 */ /* McGraw-Hill Book Company, San Francisco. pp 199 */ /* $ Version */ /* - SPICELIB Version 1.2.0, 02-SEP-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VHAT, VROTV, and VSCL calls. */ /* - SPICELIB Version 1.1.0, 29-FEB-1996 (KRG) */ /* The declaration for the SPICELIB function PI is now */ /* preceded by an EXTERNAL statement declaring PI to be an */ /* external function. This removes a conflict with any */ /* compilers that have a PI intrinsic function. */ /* - SPICELIB Version 1.0.0, 15-NOV-1994 (WLT) (SS) */ /* -& */ /* $ Index_Entries */ /* evaluate type_15 spk segment */ /* -& */ /* $ Revisions */ /* - SPICELIB Version 1.2.0, 02-SEP-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VHAT, VROTV, and VSCL calls. */ /* - SPICELIB Version 1.1.0, 29-FEB-1996 (KRG) */ /* The declaration for the SPICELIB function PI is now */ /* preceded by an EXTERNAL statement declaring PI to be an */ /* external function. This removes a conflict with any */ /* compilers that have a PI intrinsic function. */ /* - SPICELIB Version 1.0.0, 15-NOV-1994 (WLT) (SS) */ /* -& */ /* SPICELIB Functions */ /* Local Variables */ /* Standard SPICE error handling. */ if (return_()) { return 0; } chkin_("SPKE15", (ftnlen)6); /* Fetch the various entities from the input record, first the epoch. */ epoch = recin[0]; /* The trajectory pole vector. */ vequ_(&recin[1], tp); /* The periapsis vector. */ vequ_(&recin[4], pa); /* Semi-latus rectum ( P in the P/(1 + ECC*COS(Nu) ), */ /* and eccentricity. */ p = recin[7]; ecc = recin[8]; /* J2 processing flag. */ j2flg = (integer) recin[9]; /* Central body pole vector. */ vequ_(&recin[10], pv); /* The central mass, J2 and radius of the central body. */ gm = recin[13]; oj2 = recin[14]; rpl = recin[15]; /* Check all the inputs here for obvious failures. Yes, perhaps */ /* this is overkill. However, there is a lot more computation */ /* going on in this routine so that the small amount of overhead */ /* here should not be significant. */ 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_("SPKE15", (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_("SPKE15", (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_("SPKE15", (ftnlen)6); return 0; } else if (vzero_(tp)) { setmsg_("The trajectory pole vector supplied to SPKE15 had length ze" "ro. The most likely cause of this problem is a corrupted SPK" " (ephemeris) file. ", (ftnlen)138); sigerr_("SPICE(BADVECTOR)", (ftnlen)16); chkout_("SPKE15", (ftnlen)6); return 0; } else if (vzero_(pa)) { setmsg_("The periapse vector supplied to SPKE15 had length zero. The" " most likely cause of this problem is a corrupted SPK (ephem" "eris) file. ", (ftnlen)131); sigerr_("SPICE(BADVECTOR)", (ftnlen)16); chkout_("SPKE15", (ftnlen)6); return 0; } else if (vzero_(pv)) { setmsg_("The central pole vector supplied to SPKE15 had length zero." " The most likely cause of this problem is a corrupted SPK (e" "phemeris) file. ", (ftnlen)135); sigerr_("SPICE(BADVECTOR)", (ftnlen)16); chkout_("SPKE15", (ftnlen)6); return 0; } else if (rpl < 0.) { setmsg_("The central body radius was negative. It must be zero or po" "sitive. The value supplied was #. ", (ftnlen)94); errdp_("#", &rpl, (ftnlen)1); sigerr_("SPICE(BADRADIUS)", (ftnlen)16); chkout_("SPKE15", (ftnlen)6); return 0; } /* Convert TP, PV and PA to unit vectors. */ /* (It won't hurt to polish them up a bit here if they are already */ /* unit vectors.) */ vhatip_(pa); vhatip_(tp); vhatip_(pv); /* 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_(pa, tp); if (abs(dot) > 1e-5) { angle = vsep_(pa, tp) * dpr_(); setmsg_("The periapsis and trajectory pole vectors are not orthogona" "l. The anglebetween them is # degrees. ", (ftnlen)98); errdp_("#", &angle, (ftnlen)1); sigerr_("SPICE(BADINITSTATE)", (ftnlen)19); chkout_("SPKE15", (ftnlen)6); return 0; } /* Compute the distance and speed at periapse. */ near__ = p / (ecc + 1.); speed = sqrt(gm / p) * (ecc + 1.); /* Next get the position at periapse ... */ vscl_(&near__, pa, state0); /* ... and the velocity at periapsis. */ vcrss_(tp, pa, &state0[3]); vsclip_(&speed, &state0[3]); /* Determine the elapsed time from periapse to the requested */ /* epoch and propagate the state at periapsis to the epoch of */ /* interest. */ /* Note that we are making use of the following fact. */ /* If R is a rotation, then the states obtained by */ /* the following blocks of code are mathematically the */ /* same. (In reality they may differ slightly due to */ /* roundoff.) */ /* Code block 1. */ /* CALL MXV ( R, STATE0, STATE0 ) */ /* CALL MXV ( R, STATE0(4), STATE0(4) ) */ /* CALL PROP2B( GM, STATE0, DT, STATE ) */ /* Code block 2. */ /* CALL PROP2B( GM, STATE0, DT, STATE ) */ /* CALL MXV ( R, STATE, STATE ) */ /* CALL MXV ( R, STATE(4), STATE(4) ) */ /* This allows us to first compute the propagation of our initial */ /* state and then if needed perform the precession of the line */ /* of nodes and apsides by simply precessing the resulting state. */ dt = *et - epoch; prop2b_(&gm, state0, &dt, state); /* If called for, handle precession needed due to the J2 term. Note */ /* that the motion of the lines of nodes and apsides is formulated */ /* in terms of the true anomaly. This means we need the accumulated */ /* true anomaly in order to properly transform the state. */ if (j2flg != 3 && oj2 != 0. && ecc < 1. && near__ > rpl) { /* First compute the change in mean anomaly since periapsis. */ /* Computing 2nd power */ d__1 = ecc; oneme2 = 1. - d__1 * d__1; dmdt = oneme2 / p * sqrt(gm * oneme2 / p); manom = dmdt * dt; /* Next compute the angle THETA such that THETA is between */ /* -pi and pi and such than MANOM = THETA + K*2*pi for */ /* some integer K. */ d__1 = twopi_(); theta = d_mod(&manom, &d__1); if (abs(theta) > pi_()) { d__1 = twopi_(); theta -= d_sign(&d__1, &theta); } k2pi = manom - theta; /* We can get the accumulated true anomaly from the propagated */ /* state theta and the accumulated mean anomaly prior to this */ /* orbit. */ ta = vsep_(pa, state); ta = d_sign(&ta, &theta); ta += k2pi; /* Determine how far the line of nodes and periapsis have moved. */ cosinc = vdot_(pv, tp); /* Computing 2nd power */ d__1 = rpl / p; z__ = ta * 1.5 * oj2 * (d__1 * d__1); dnode = -z__ * cosinc; /* Computing 2nd power */ d__1 = cosinc; dperi = z__ * (d__1 * d__1 * 2.5 - .5); /* Precess the periapsis by rotating the state vector about the */ /* trajectory pole */ if (j2flg != 1) { vrotv_(state, tp, &dperi, tmpsta); vrotv_(&state[3], tp, &dperi, &tmpsta[3]); moved_(tmpsta, &c__6, state); } /* Regress the line of nodes by rotating the state */ /* about the pole of the central body. */ if (j2flg != 2) { vrotv_(state, pv, &dnode, tmpsta); vrotv_(&state[3], pv, &dnode, &tmpsta[3]); moved_(tmpsta, &c__6, state); } /* We could perform the rotations above in the other order, */ /* but we would also have to rotate the pole before precessing */ /* the line of apsides. */ } /* That's all folks. Check out and return. */ chkout_("SPKE15", (ftnlen)6); return 0; } /* spke15_ */
/* $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 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_ */