/* $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 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 FRAME ( Build a right handed coordinate frame ) */ /* Subroutine */ int frame_(doublereal *x, doublereal *y, doublereal *z__) { /* System generated locals */ integer i__1, i__2, i__3; /* Builtin functions */ double sqrt(doublereal); integer s_rnge(char *, integer, char *, integer); /* Local variables */ doublereal a, b, c__, f; integer s1, s2, s3; extern /* Subroutine */ int vhatip_(doublereal *); /* $ Abstract */ /* Given a vector X, this routine builds a right handed */ /* orthonormal frame X,Y,Z where the output X is parallel to */ /* the input X. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* None. */ /* $ Keywords */ /* AXES, FRAME */ /* $ Declarations */ /* $ Brief_I/O */ /* VARIABLE I/O DESCRIPTION */ /* -------- --- ------------------------------------------------ */ /* X I/0 Input vector. A parallel unit vector on output. */ /* Y O Unit vector in the plane orthogonal to X. */ /* Z O Unit vector given by X x Y. */ /* $ Detailed_Input */ /* X This vector is used to form the first vector of a */ /* right-handed orthonormal triple. */ /* $ Detailed_Output */ /* X, */ /* Y, */ /* Z form a right handed orthonormal frame, where X is */ /* now a unit vector parallel to the original input */ /* vector in X. There are no special geometric properties */ /* connected to Y and Z (other than that they complete the */ /* right handed frame). */ /* $ Parameters */ /* None. */ /* $ Particulars */ /* Given an input vector X, this routine returns unit vectors X, */ /* Y, and Z such that XYZ forms a right-handed orthonormal frame */ /* where the output X is parallel to the input X. */ /* This routine is intended primarily to provide a basis for */ /* the plane orthogonal to X. There are no special properties */ /* associated with Y and Z other than that the resulting XYZ frame */ /* is right handed and orthonormal. There are an infinite */ /* collection of pairs (Y,Z) that could be used to this end. */ /* Even though for a given X, Y and Z are uniquely */ /* determined, users */ /* should regard the pair (Y,Z) as a random selection from this */ /* infinite collection. */ /* For instance, when attempting to determine the locus of points */ /* that make up the limb of a triaxial body, it is a straightforward */ /* matter to determine the normal to the limb plane. To find */ /* the actual parametric equation of the limb one needs to have */ /* a basis of the plane. This routine can be used to get a basis */ /* in which one can describe the curve and from which one can */ /* then determine the principal axes of the limb ellipse. */ /* $ Examples */ /* In addition to using a vector to construct a right handed frame */ /* with the x-axis aligned with the input vector, one can construct */ /* right handed frames with any of the axes aligned with the input */ /* vector. */ /* For example suppose we want a right hand frame XYZ with the */ /* Z-axis aligned with some vector V. Assign V to Z */ /* Z(1) = V(1) */ /* Z(2) = V(2) */ /* Z(3) = V(3) */ /* Then call FRAME with the arguements X,Y,Z cycled so that Z */ /* appears first. */ /* CALL FRAME (Z, X, Y) */ /* The resulting XYZ frame will be orthonormal with Z parallel */ /* to the vector V. */ /* To get an XYZ frame with Y parallel to V perform the following */ /* Y(1) = V(1) */ /* Y(2) = V(2) */ /* Y(3) = V(3) */ /* CALL FRAME (Y, Z, X) */ /* $ Restrictions */ /* None. */ /* $ Exceptions */ /* Error Free */ /* 1) If X on input is the zero vector the ``standard'' frame (ijk) */ /* is returned. */ /* $ Files */ /* None. */ /* $ Author_and_Institution */ /* W.L. Taber (JPL) */ /* I.M. Underwood (JPL) */ /* $ Literature_References */ /* None. */ /* $ Version */ /* - SPICELIB Version 1.2.0, 02-SEP-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VHAT call. */ /* - SPICELIB Version 1.0.1, 10-MAR-1992 (WLT) */ /* Comment section for permuted index source lines was added */ /* following the header. */ /* - SPICELIB Version 1.0.0, 31-JAN-1990 (WLT) */ /* -& */ /* $ Index_Entries */ /* build a right handed coordinate frame */ /* -& */ /* $ Revisions */ /* - SPICELIB Version 1.2.0, 02-SEP-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VHAT call. */ /* - Beta Version 2.0.0, 29-DEC-1988 (WLT) (IMU) */ /* The routine was modified so that it now accepts any input */ /* vector in the X slot (it originally was assumed to be a unit */ /* vector). Moreover, the original algorithm has been streamlined */ /* a great deal to take advantage of our knowledge of the */ /* internal structure of the orthonormal triple. */ /* -& */ /* Local variables */ /* First make X into a unit vector. */ vhatip_(x); /* We'll need the squares of the components of X in a bit. */ a = x[0] * x[0]; b = x[1] * x[1]; c__ = x[2] * x[2]; /* If X is zero, then just return the ijk frame. */ if (a + b + c__ == 0.) { x[0] = 1.; x[1] = 0.; x[2] = 0.; y[0] = 0.; y[1] = 1.; y[2] = 0.; z__[0] = 0.; z__[1] = 0.; z__[2] = 1.; return 0; } /* If we make it this far, determine which component of X has the */ /* smallest magnitude. This component will be zero in Y. The other */ /* two components of X will put into Y swapped with the sign of */ /* the first changed. From there, Z can have only one possible */ /* set of values which it gets from the smallest component */ /* of X, the non-zero components of Y and the length of Y. */ if (a <= b && a <= c__) { f = sqrt(b + c__); s1 = 1; s2 = 2; s3 = 3; } else if (b <= a && b <= c__) { f = sqrt(a + c__); s1 = 2; s2 = 3; s3 = 1; } else { f = sqrt(a + b); s1 = 3; s2 = 1; s3 = 2; } /* Note: by construction, F is the magnitude of the large components */ /* of X. With this in mind, one can verify by inspection that X, Y */ /* and Z yield an orthonormal frame. The right handedness follows */ /* from the assignment of values to S1, S2 and S3 (they are merely */ /* cycled from one case to the next). */ y[(i__1 = s1 - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("y", i__1, "frame_", ( ftnlen)285)] = 0.; y[(i__1 = s2 - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("y", i__1, "frame_", ( ftnlen)286)] = -x[(i__2 = s3 - 1) < 3 && 0 <= i__2 ? i__2 : s_rnge("x", i__2, "frame_", (ftnlen)286)] / f; y[(i__1 = s3 - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("y", i__1, "frame_", ( ftnlen)287)] = x[(i__2 = s2 - 1) < 3 && 0 <= i__2 ? i__2 : s_rnge( "x", i__2, "frame_", (ftnlen)287)] / f; z__[(i__1 = s1 - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("z", i__1, "frame_", (ftnlen)289)] = f; z__[(i__1 = s2 - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("z", i__1, "frame_", (ftnlen)290)] = -x[(i__2 = s1 - 1) < 3 && 0 <= i__2 ? i__2 : s_rnge("x", i__2, "frame_", (ftnlen)290)] * y[(i__3 = s3 - 1) < 3 && 0 <= i__3 ? i__3 : s_rnge("y", i__3, "frame_", (ftnlen)290)]; z__[(i__1 = s3 - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("z", i__1, "frame_", (ftnlen)291)] = x[(i__2 = s1 - 1) < 3 && 0 <= i__2 ? i__2 : s_rnge("x", i__2, "frame_", (ftnlen)291)] * y[(i__3 = s2 - 1) < 3 && 0 <= i__3 ? i__3 : s_rnge("y", i__3, "frame_", (ftnlen)291)]; return 0; } /* frame_ */
/* $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_ */