/* $Procedure VPRJPI ( Vector projection onto plane, inverted ) */ /* Subroutine */ int vprjpi_(doublereal *vin, doublereal *projpl, doublereal * invpl, doublereal *vout, logical *found) { /* System generated locals */ doublereal d__1; /* Local variables */ doublereal invc, invn[3]; extern doublereal vdot_(doublereal *, doublereal *); doublereal mult; extern /* Subroutine */ int chkin_(char *, ftnlen); doublereal denom; extern doublereal dpmax_(void); doublereal projc, limit; extern /* Subroutine */ int vlcom_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); doublereal numer, projn[3]; extern /* Subroutine */ int pl2nvc_(doublereal *, doublereal *, doublereal *), chkout_(char *, ftnlen); extern logical return_(void); /* $ Abstract */ /* Find the vector in a specified plane that maps to a specified */ /* vector in another plane under orthogonal projection. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* PLANES */ /* $ Keywords */ /* GEOMETRY */ /* MATH */ /* PLANE */ /* VECTOR */ /* $ Declarations */ /* $ Brief_I/O */ /* Variable I/O Description */ /* -------- --- -------------------------------------------------- */ /* VIN I The projected vector. */ /* PROJPL I Plane containing VIN. */ /* INVPL I Plane containing inverse image of VIN. */ /* VOUT O Inverse projection of VIN. */ /* FOUND O Flag indicating whether VOUT could be calculated. */ /* $ Detailed_Input */ /* VIN, */ /* PROJPL, */ /* INVPL are, respectively, a 3-vector, a SPICELIB plane */ /* containing the vector, and a SPICELIB plane */ /* containing the inverse image of the vector under */ /* orthogonal projection onto PROJPL. */ /* $ Detailed_Output */ /* VOUT is the inverse orthogonal projection of VIN. This */ /* is the vector lying in the plane INVPL whose */ /* orthogonal projection onto the plane PROJPL is */ /* VIN. VOUT is valid only when FOUND (defined below) */ /* is .TRUE. Otherwise, VOUT is undefined. */ /* FOUND indicates whether the inverse orthogonal projection */ /* of VIN could be computed. FOUND is .TRUE. if so, */ /* .FALSE. otherwise. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If the geometric planes defined by PROJPL and INVPL are */ /* orthogonal, or nearly so, the inverse orthogonal projection */ /* of VIN may be undefined or have magnitude too large to */ /* represent with double precision numbers. In either such */ /* case, FOUND will be set to .FALSE. */ /* 2) Even when FOUND is .TRUE., VOUT may be a vector of extremely */ /* large magnitude, perhaps so large that it is impractical to */ /* compute with it. It's up to you to make sure that this */ /* situation does not occur in your application of this routine. */ /* $ Files */ /* None. */ /* $ Particulars */ /* Projecting a vector orthogonally onto a plane can be thought of */ /* as finding the closest vector in the plane to the original vector. */ /* This `closest vector' always exists; it may be coincident with the */ /* original vector. Inverting an orthogonal projection means finding */ /* the vector in a specified plane whose orthogonal projection onto */ /* a second specified plane is a specified vector. The vector whose */ /* projection is the specified vector is the inverse projection of */ /* the specified vector, also called the `inverse image under */ /* orthogonal projection' of the specified vector. This routine */ /* finds the inverse orthogonal projection of a vector onto a plane. */ /* Related routines are VPRJP, which projects a vector onto a plane */ /* orthogonally, and VPROJ, which projects a vector onto another */ /* vector orthogonally. */ /* $ Examples */ /* 1) Suppose */ /* VIN = ( 0.0, 1.0, 0.0 ), */ /* and that PROJPL has normal vector */ /* PROJN = ( 0.0, 0.0, 1.0 ). */ /* Also, let's suppose that INVPL has normal vector and constant */ /* INVN = ( 0.0, 2.0, 2.0 ) */ /* INVC = 4.0. */ /* Then VIN lies on the y-axis in the x-y plane, and we want to */ /* find the vector VOUT lying in INVPL such that the orthogonal */ /* projection of VOUT the x-y plane is VIN. Let the notation */ /* < a, b > indicate the inner product of vectors a and b. */ /* Since every point X in INVPL satisfies the equation */ /* < X, (0.0, 2.0, 2.0) > = 4.0, */ /* we can verify by inspection that the vector */ /* ( 0.0, 1.0, 1.0 ) */ /* is in INVPL and differs from VIN by a multiple of PROJN. So */ /* ( 0.0, 1.0, 1.0 ) */ /* must be VOUT. */ /* To find this result using SPICELIB, we can create the */ /* SPICELIB planes PROJPL and INVPL using the code fragment */ /* CALL NVP2PL ( PROJN, VIN, PROJPL ) */ /* CALL NVC2PL ( INVN, INVC, INVPL ) */ /* and then perform the inverse projection using the call */ /* CALL VPRJPI ( VIN, PROJPL, INVPL, VOUT ) */ /* VPRJPI will return the value */ /* VOUT = ( 0.0, 1.0, 1.0 ) */ /* $ Restrictions */ /* None. */ /* $ Literature_References */ /* [1] `Calculus and Analytic Geometry', Thomas and Finney. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* $ Version */ /* - SPICELIB Version 2.0.0, 17-FEB-2004 (NJB) */ /* Computation of LIMIT was re-structured to avoid */ /* run-time underflow warnings on some platforms. */ /* - SPICELIB Version 1.0.1, 10-MAR-1992 (WLT) */ /* Comment section for permuted index source lines was added */ /* following the header. */ /* - SPICELIB Version 1.0.0, 01-NOV-1990 (NJB) */ /* -& */ /* $ Index_Entries */ /* vector projection onto plane inverted */ /* -& */ /* $ Revisions */ /* - SPICELIB Version 2.0.0, 17-FEB-2004 (NJB) */ /* Computation of LIMIT was re-structured to avoid */ /* run-time underflow warnings on some platforms. */ /* In the revised code, BOUND/DPMAX() is never */ /* scaled by a number having absolute value < 1. */ /* -& */ /* SPICELIB functions */ /* Local parameters */ /* BOUND is used to bound the magnitudes of the numbers that we */ /* try to take the reciprocal of, since we can't necessarily invert */ /* any non-zero number. We won't try to invert any numbers with */ /* magnitude less than */ /* BOUND / DPMAX(). */ /* BOUND is chosen somewhat arbitrarily.... */ /* Local variables */ /* Standard SPICE error handling. */ if (return_()) { return 0; } else { chkin_("VPRJPI", (ftnlen)6); } /* Unpack the planes. */ pl2nvc_(projpl, projn, &projc); pl2nvc_(invpl, invn, &invc); /* We'll first discuss the computation of VOUT in the nominal case, */ /* and then deal with the exceptional cases. */ /* When PROJPL and INVPL are not orthogonal to each other, the */ /* inverse projection of VIN will differ from VIN by a multiple of */ /* PROJN, the unit normal vector to PROJPL. We find this multiple */ /* by using the fact that the inverse projection VOUT satisfies the */ /* plane equation for the inverse projection plane INVPL. */ /* We have */ /* VOUT = VIN + MULT * PROJN; (1) */ /* since VOUT satisfies */ /* < VOUT, INVN > = INVC */ /* we must have */ /* < VIN + MULT * PROJN, INVN > = INVC */ /* which in turn implies */ /* INVC - < VIN, INVN > */ /* MULT = ------------------------. (2) */ /* < PROJN, INVN > */ /* Having MULT, we can compute VOUT according to equation (1). */ /* Now, if the denominator in the above expression for MULT is zero */ /* or just too small, performing the division would cause a */ /* divide-by-zero error or an overflow of MULT. In either case, we */ /* will avoid carrying out the division, and we'll set FOUND to */ /* .FALSE. */ /* Compute the numerator and denominator of the right side of (2). */ numer = invc - vdot_(vin, invn); denom = vdot_(projn, invn); /* If the magnitude of the denominator is greater than the absolute */ /* value of */ /* BOUND */ /* LIMIT = --------- * NUMER, */ /* DPMAX() */ /* we can safely divide the numerator by the denominator, and the */ /* magnitude of the result will be no greater than */ /* DPMAX() */ /* --------- . */ /* BOUND */ /* Note that we have ruled out the case where NUMER and DENOM are */ /* both zero by insisting on strict inequality in the comparison of */ /* DENOM and LIMIT. */ /* We never set LIMIT smaller than BOUND/DPMAX(), since */ /* the computation using NUMER causes underflow to be signaled */ /* on some systems. */ if (abs(numer) < 1.) { limit = 10. / dpmax_(); } else { limit = (d__1 = 10. / dpmax_() * numer, abs(d__1)); } if (abs(denom) > limit) { /* We can find VOUT after all. */ mult = numer / denom; vlcom_(&c_b3, vin, &mult, projn, vout); *found = TRUE_; } else { /* No dice. */ *found = FALSE_; } chkout_("VPRJPI", (ftnlen)6); return 0; } /* vprjpi_ */
/* $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 PJELPL ( Project ellipse onto plane ) */ /* Subroutine */ int pjelpl_(doublereal *elin, doublereal *plane, doublereal * elout) { extern /* Subroutine */ int chkin_(char *, ftnlen); doublereal const__; extern /* Subroutine */ int vperp_(doublereal *, doublereal *, doublereal *), vprjp_(doublereal *, doublereal *, doublereal *), el2cgv_( doublereal *, doublereal *, doublereal *, doublereal *), cgv2el_( doublereal *, doublereal *, doublereal *, doublereal *), pl2nvc_( doublereal *, doublereal *, doublereal *); doublereal prjvc1[3], prjvc2[3], center[3], normal[3], smajor[3]; extern /* Subroutine */ int chkout_(char *, ftnlen); doublereal prjctr[3], sminor[3]; extern logical return_(void); /* $ Abstract */ /* Project an ellipse onto a plane, orthogonally. */ /* $ 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 */ /* PLANES */ /* $ Keywords */ /* ELLIPSE */ /* GEOMETRY */ /* MATH */ /* $ Declarations */ /* $ Brief_I/O */ /* Variable I/O Description */ /* -------- --- -------------------------------------------------- */ /* ELIN I A SPICELIB ellipse to be projected. */ /* PLANE I A plane onto which ELIN is to be projected. */ /* ELOUT O A SPICELIB ellipse resulting from the projection. */ /* $ Detailed_Input */ /* ELIN, */ /* PLANE are, respectively, a SPICELIB ellipse and a */ /* SPICELIB plane. The geometric ellipse represented */ /* by ELIN is to be orthogonally projected onto the */ /* geometric plane represented by PLANE. */ /* $ Detailed_Output */ /* ELOUT is a SPICELIB ellipse that represents the geometric */ /* ellipse resulting from orthogonally projecting the */ /* ellipse represented by INEL onto the plane */ /* represented by PLANE. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If the input plane is invalid, the error will be diagnosed */ /* by routines called by this routine. */ /* 2) The input ellipse may be degenerate--its semi-axes may be */ /* linearly dependent. Such ellipses are allowed as inputs. */ /* 3) The ellipse resulting from orthogonally projecting the input */ /* ellipse onto a plane may be degenerate, even if the input */ /* ellipse is not. */ /* $ Files */ /* None. */ /* $ Particulars */ /* Projecting an ellipse orthogonally onto a plane can be thought of */ /* finding the points on the plane that are `under' or `over' the */ /* ellipse, with the `up' direction considered to be perpendicular */ /* to the plane. More mathematically, the orthogonal projection is */ /* the set of points Y in the plane such that for some point X in */ /* the ellipse, the vector Y - X is perpendicular to the plane. */ /* The orthogonal projection of an ellipse onto a plane yields */ /* another ellipse. */ /* $ Examples */ /* 1) With CENTER = ( 1.D0, 1.D0, 1.D0 ), */ /* VECT1 = ( 2.D0, 0.D0, 0.D0 ), */ /* VECT2 = ( 0.D0, 1.D0, 1.D0 ), */ /* NORMAL = ( 0.D0, 0.D0, 1.D0 ), */ /* the code fragment */ /* CALL NVC2PL ( NORMAL, 0.D0, PLANE ) */ /* CALL CGV2EL ( CENTER, VECT1, VECT2, ELIN ) */ /* CALL PJELPL ( ELIN, PLANE, ELOUT ) */ /* CALL EL2CGV ( ELOUT, PRJCTR, PRJMAJ, PRJMIN ) */ /* returns */ /* PRJCTR = ( 1.D0, 1.D0, 0.D0 ) */ /* PRJMAJ = ( 2.D0, 0.D0, 0.D0 ) */ /* PRJMIN = ( 0.D0, 1.D0, 0.D0 ) */ /* 2) With VECT1 = ( 2.D0, 0.D0, 0.D0 ), */ /* VECT2 = ( 1.D0, 1.D0, 1.D0 ), */ /* CENTER = ( 0.D0, 0.D0, 0.D0 ), */ /* NORMAL = ( 0.D0, 0.D0, 1.D0 ), */ /* the code fragment */ /* CALL NVC2PL ( NORMAL, 0.D0, PLANE ) */ /* CALL CGV2EL ( CENTER, VECT1, VECT2, ELIN ) */ /* CALL PJELPL ( ELIN, PLANE, ELOUT ) */ /* CALL EL2CGV ( ELOUT, PRJCTR, PRJMAJ, PRJMIN ) */ /* returns */ /* PRJCTR = ( 0.D0, 0.D0, 0.D0 ) */ /* PRJMAJ = ( -2.227032728823213D0, */ /* -5.257311121191336D-1, */ /* 0.D0 ) */ /* PRJMIN = ( 2.008114158862273D-1, */ /* -8.506508083520399D-1, */ /* 0.D0 ) */ /* 3) An example of actual use: Suppose we wish to compute the */ /* distance from an ellipsoid to a line. Let the line be */ /* defined by a point P and a direction vector DIRECT; the */ /* line is the set of points */ /* P + t * DIRECT, */ /* where t is any real number. Let the ellipsoid have semi- */ /* axis lengths A, B, and C. */ /* We can reduce the problem to that of finding the distance */ /* between the line and an ellipse on the ellipsoid surface by */ /* considering the fact that the surface normal at the nearest */ /* point to the line will be orthogonal to DIRECT; the set of */ /* surface points where this condition holds lies in a plane, */ /* and hence is an ellipse on the surface. The problem can be */ /* further simplified by projecting the ellipse orthogonally */ /* onto the plane defined by */ /* < X, DIRECT > = 0. */ /* The problem is then a two dimensional one: find the */ /* distance of the projected ellipse from the intersection of */ /* the line and this plane (which is necessarily one point). */ /* A `paraphrase' of the relevant code is: */ /* C Step 1. Find the candidate ellipse CAND. */ /* C NORMAL is a normal vector to the plane */ /* C containing the candidate ellipse. The */ /* C ellipse must exist, since it's the */ /* C intersection of an ellipsoid centered at */ /* C the origin and a plane containing the */ /* C origin. For this reason, we don't check */ /* C INEDPL's `found flag' FOUND below. */ /* C */ /* NORMAL(1) = DIRECT(1) / A**2 */ /* NORMAL(2) = DIRECT(2) / B**2 */ /* NORMAL(3) = DIRECT(3) / C**2 */ /* CALL NVC2PL ( NORMAL, 0.D0, CANDPL ) */ /* CALL INEDPL ( A, B, C, CANDPL, CAND, FOUND ) */ /* C */ /* C Step 2. Project the candidate ellipse onto a */ /* C plane orthogonal to the line. We'll */ /* C call the plane PRJPL and the */ /* C projected ellipse PRJEL. */ /* C */ /* CALL NVC2PL ( DIRECT, 0.D0, PRJPL ) */ /* CALL PJELPL ( CAND, PRJPL, PRJEL ) */ /* C */ /* C Step 3. Find the point on the line lying in the */ /* C projection plane, and then find the */ /* C near point PJNEAR on the projected */ /* C ellipse. Here PRJPT is the point on the */ /* C input line that lies in the projection */ /* C plane. The distance between PRJPT and */ /* C PJNEAR is DIST. */ /* CALL VPRJP ( LINEPT, PRJPL, PRJPT ) */ /* CALL NPEDPT ( PRJEL, PRJPT, PJNEAR, DIST ) */ /* C */ /* C Step 4. Find the near point PNEAR on the */ /* C ellipsoid by taking the inverse */ /* C orthogonal projection of PJNEAR; this is */ /* C the point on the candidate ellipse that */ /* C projects to PJNEAR. Note that the output */ /* C DIST was computed in step 3. */ /* C */ /* C The inverse projection of PJNEAR is */ /* C guaranteed to exist, so we don't have to */ /* C check FOUND. */ /* C */ /* CALL VPRJPI ( PJNEAR, PRJPL, CANDPL, PNEAR, FOUND ) */ /* The value of DIST returned is the distance we're looking */ /* for. */ /* The procedure described here is carried out in the routine */ /* NPEDLN. */ /* $ Restrictions */ /* None. */ /* $ Literature_References */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* $ Version */ /* - 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, 02-NOV-1990 (NJB) */ /* -& */ /* $ Index_Entries */ /* project ellipse onto plane */ /* -& */ /* SPICELIB functions */ /* Local variables */ /* Standard SPICE error handling. */ if (return_()) { return 0; } else { chkin_("PJELPL", (ftnlen)6); } /* Find generating vectors of the input ellipse. */ el2cgv_(elin, center, smajor, sminor); /* Find a normal vector for the input plane. */ pl2nvc_(plane, normal, &const__); /* Find the components of the semi-axes that are orthogonal to the */ /* input plane's normal vector. The components are generating */ /* vectors for the projected plane. */ vperp_(smajor, normal, prjvc1); vperp_(sminor, normal, prjvc2); /* Find the projection of the ellipse's center onto the input plane. */ /* This is the center of the projected ellipse. */ /* In case the last assertion is non-obvious, note that the */ /* projection we're carrying out is the composition of a linear */ /* mapping (projection to a plane containing the origin and parallel */ /* to PLANE) and a translation mapping (adding the closest point to */ /* the origin in PLANE to every point), and both linear mappings and */ /* translations carry the center of an ellipse to the center of the */ /* ellipse's image. Let's state this using mathematical symbols. */ /* Let L be a linear mapping and let T be a translation mapping, */ /* say */ /* T(x) = x + A. */ /* Then */ /* T ( L ( center + cos(theta)smajor + sin(theta)sminor ) ) */ /* = A + L ( center + cos(theta)smajor + sin(theta)sminor ) */ /* = A + L (center) */ /* + cos(theta) L(smajor) */ /* + sin(theta) L(sminor) */ /* From the form of this last expression, we see that we have an */ /* ellipse centered at */ /* A + L (center) */ /* = T ( L (center) ) */ /* This last term is the image of the center of the original ellipse, */ /* as we wished to demonstrate. */ /* Now in the case of orthogonal projection onto a plane PL, L can be */ /* taken as the orthogonal projection onto a parallel plane PL' */ /* containing the origin. Then L is a linear mapping. Let M be */ /* the multiple of the normal vector of PL such that M is contained */ /* in PL (M is the closest point in PL to the origin). Then the */ /* orthogonal projection mapping onto PL, which we will name PRJ, */ /* can be defined by */ /* PRJ (x) = L (x) + M. */ /* So PRJ is the composition of a translation and a linear mapping, */ /* as claimed. */ vprjp_(center, plane, prjctr); /* Put together the projected ellipse. */ cgv2el_(prjctr, prjvc1, prjvc2, elout); chkout_("PJELPL", (ftnlen)6); return 0; } /* pjelpl_ */
/* $Procedure PL2NVP ( Plane to normal vector and point ) */ /* Subroutine */ int pl2nvp_(doublereal *plane, doublereal *normal, doublereal *point) { extern /* Subroutine */ int vscl_(doublereal *, doublereal *, doublereal * ); doublereal const__; extern /* Subroutine */ int pl2nvc_(doublereal *, doublereal *, doublereal *); /* $ Abstract */ /* Return a unit normal vector and point that define a specified */ /* plane. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* PLANES */ /* $ Keywords */ /* GEOMETRY */ /* MATH */ /* PLANE */ /* $ Declarations */ /* $ Brief_I/O */ /* Variable I/O Description */ /* -------- --- -------------------------------------------------- */ /* PLANE I A SPICELIB plane. */ /* NORMAL, */ /* POINT O A unit normal vector and point that define PLANE. */ /* $ Detailed_Input */ /* PLANE is a SPICELIB plane. */ /* $ Detailed_Output */ /* NORMAL, */ /* POINT are, respectively, a unit normal vector and point */ /* that define the geometric plane represented by */ /* PLANE. Let the symbol < a, b > indicate the inner */ /* product of vectors a and b; then the geometric */ /* plane is the set of vectors X in three-dimensional */ /* space that satisfy */ /* < X - POINT, NORMAL > = 0. */ /* POINT is always the closest point in the input */ /* plane to the origin. POINT is always a */ /* non-negative scalar multiple of NORMAL. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* Error free. */ /* 1) The input plane MUST have been created by one of the SPICELIB */ /* routines */ /* NVC2PL ( Normal vector and constant to plane ) */ /* NVP2PL ( Normal vector and point to plane ) */ /* PSV2PL ( Point and spanning vectors to plane ) */ /* Otherwise, the results of this routine are unpredictable. */ /* $ Files */ /* None. */ /* $ Particulars */ /* SPICELIB geometry routines that deal with planes use the `plane' */ /* data type to represent input and output planes. This data type */ /* makes the subroutine interfaces simpler and more uniform. */ /* The SPICELIB routines that produce SPICELIB planes from data that */ /* define a plane are: */ /* NVC2PL ( Normal vector and constant to plane ) */ /* NVP2PL ( Normal vector and point to plane ) */ /* PSV2PL ( Point and spanning vectors to plane ) */ /* The SPICELIB routines that convert SPICELIB planes to data that */ /* define a plane are: */ /* PL2NVC ( Plane to normal vector and constant ) */ /* PL2NVP ( Plane to normal vector and point ) */ /* PL2PSV ( Plane to point and spanning vectors ) */ /* $ Examples */ /* 1) Given a plane normal and constant, find a point in */ /* the plane. POINT is the point we seek. */ /* CALL NVC2PL ( NORMAL, CONST, PLANE ) */ /* CALL PL2NVP ( PLANE, NORMAL, POINT ) */ /* $ Restrictions */ /* None. */ /* $ Literature_References */ /* [1] `Calculus and Analytic Geometry', Thomas and Finney. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* $ Version */ /* - SPICELIB Version 1.0.1, 10-MAR-1992 (WLT) */ /* Comment section for permuted index source lines was added */ /* following the header. */ /* - SPICELIB Version 1.0.0, 01-NOV-1990 (NJB) */ /* -& */ /* $ Index_Entries */ /* plane to normal vector and point */ /* -& */ /* Local variables */ /* Find a unit normal and constant for the plane. Scaling the */ /* unit normal by the constant gives us the closest point in */ /* the plane to the origin. */ pl2nvc_(plane, normal, &const__); vscl_(&const__, normal, point); return 0; } /* pl2nvp_ */
/* $Procedure INEDPL ( Intersection of ellipsoid and plane ) */ /* Subroutine */ int inedpl_(doublereal *a, doublereal *b, doublereal *c__, doublereal *plane, doublereal *ellips, logical *found) { /* System generated locals */ integer i__1, i__2, i__3; doublereal d__1, d__2; /* Builtin functions */ integer s_rnge(char *, integer, char *, integer); double sqrt(doublereal); /* Local variables */ doublereal dist, span1[3], span2[3]; integer i__; extern /* Subroutine */ int chkin_(char *, ftnlen), errdp_(char *, doublereal *, ftnlen); doublereal const__, point[3]; extern doublereal vnorm_(doublereal *); extern logical vzero_(doublereal *); extern /* Subroutine */ int cgv2el_(doublereal *, doublereal *, doublereal *, doublereal *), pl2nvc_(doublereal *, doublereal *, doublereal *), pl2psv_(doublereal *, doublereal *, doublereal *, doublereal *), psv2pl_(doublereal *, doublereal *, doublereal *, doublereal *); doublereal dplane[4]; extern doublereal brcktd_(doublereal *, doublereal *, doublereal *); doublereal maxrad, rcircl, center[3], normal[3]; extern /* Subroutine */ int sigerr_(char *, ftnlen), chkout_(char *, ftnlen), vsclip_(doublereal *, doublereal *), setmsg_(char *, ftnlen); doublereal invdst[3]; extern logical return_(void); doublereal dstort[3], vec1[3], vec2[3]; /* $ Abstract */ /* Find the intersection of a triaxial ellipsoid and a plane. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* ELLIPSES */ /* PLANES */ /* $ Keywords */ /* ELLIPSE */ /* ELLIPSOID */ /* GEOMETRY */ /* MATH */ /* $ Declarations */ /* $ Brief_I/O */ /* Variable I/O Description */ /* -------- --- -------------------------------------------------- */ /* 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. */ /* PLANE I Plane that intersects ellipsoid. */ /* ELLIPS O Intersection ellipse, when FOUND is .TRUE. */ /* FOUND O Flag indicating whether ellipse was found. */ /* $ Detailed_Input */ /* 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. */ /* PLANE is a SPICELIB plane. */ /* $ Detailed_Output */ /* ELLIPS is the SPICELIB ellipse formed by the intersection */ /* of the input plane and ellipsoid. ELLIPS will */ /* represent a single point if the ellipsoid and */ /* plane are tangent. */ /* If the intersection of the ellipsoid and plane is */ /* empty, ELLIPS is not modified. */ /* FOUND is .TRUE. if and only if the intersection of the */ /* ellipsoid and plane is non-empty. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If any of the lengths of the semi-axes of the input ellipsoid */ /* are non-positive, the error SPICE(DEGENERATECASE) is */ /* signaled. ELLIPS is not modified. FOUND is set to .FALSE. */ /* 2) If the input plane in invalid, in other words, if the input */ /* plane as the zero vector as its normal vector, the error */ /* SPICE(INVALIDPLANE) is signaled. ELLIPS is not modified. */ /* FOUND is set to .FALSE. */ /* 3) If the input plane and ellipsoid are very nearly tangent, */ /* roundoff error may cause this routine to give unreliable */ /* results. */ /* 4) If the input plane and ellipsoid are precisely tangent, the */ /* intersection is a single point. In this case, the output */ /* ellipse is degenerate, but FOUND will still have the value */ /* .TRUE. You must decide whether this output makes sense for */ /* your application. */ /* $ Files */ /* None. */ /* $ Particulars */ /* An ellipsoid and a plane can intersect in an ellipse, a single */ /* point, or the empty set. */ /* $ Examples */ /* 1) Suppose we wish to find the limb of a body, as observed from */ /* location LOC in body-fixed coordinates. The SPICELIB routine */ /* EDLIMB solves this problem. Here's how INEDPL is used in */ /* that solution. */ /* We assume LOC is outside of the body. The body is modelled as */ /* a triaxial ellipsoid with semi-axes of length A, B, and C. */ /* The notation */ /* < X, Y > */ /* indicates the inner product of the vectors X and Y. */ /* The limb lies on the plane defined by */ /* < X, N > = 1, */ /* where the vector N is defined as */ /* ( LOC(1) / A**2, LOC(2) / B**2, LOC(3) / C**2 ). */ /* The assignments */ /* N(1) = LOC(1) / A**2 */ /* N(2) = LOC(2) / B**2 */ /* N(3) = LOC(3) / C**2 */ /* and the calls */ /* CALL NVC2PL ( N, 1.0D0, PLANE ) */ /* CALL INEDPL ( A, B, C, PLANE, LIMB, FOUND ) */ /* CALL EL2CGV ( LIMB, CENTER, SMAJOR, SMINOR ) */ /* will return the center and semi-axes of the limb. */ /* How do we know that < X, N > = 1 for all X on the limb? */ /* This is because all limb points X satisfy */ /* < LOC - X, SURFNM(X) > = 0, */ /* where SURFNM(X) is a surface normal at X. SURFNM(X) is */ /* parallel to the vector */ /* V = ( X(1) / A**2, X(2) / B**2, X(3) / C**2 ) */ /* so we have */ /* < LOC - X, V > = 0, */ /* < LOC, V > = < X, V > = 1 (from the original */ /* ellipsoid */ /* equation); */ /* and finally */ /* < X, N > = 1, */ /* where the vector N is defined as */ /* ( LOC(1) / A**2, LOC(2) / B**2, LOC(3) / C**2 ). */ /* 2) Suppose we wish to find the terminator of a body. We can */ /* make a fair approximation to the location of the terminator */ /* by finding the limb of the body as seen from the vertex of */ /* the umbra; then the problem is essentially the same as in */ /* example 1. Let VERTEX be this location. We make the */ /* assignments */ /* P(1) = VERTEX(1) / A**2 */ /* P(2) = VERTEX(2) / B**2 */ /* P(3) = VERTEX(3) / C**2 */ /* and then make the calls */ /* CALL NVC2PL ( P, 1.0D0, PLANE ) */ /* CALL INEDPL ( A, B, C, PLANE, TERM, FOUND ) */ /* The SPICELIB ellipse TERM represents the terminator of the */ /* body. */ /* $ Restrictions */ /* None. */ /* $ Literature_References */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* $ Version */ /* - SPICELIB Version 1.2.0, 16-NOV-2005 (NJB) */ /* Bug fix: error detection for case of invalid input plane was */ /* added. */ /* Updated to remove non-standard use of duplicate arguments */ /* in VSCL calls. */ /* - SPICELIB Version 1.1.0, 11-JUL-1995 (KRG) */ /* Removed potential numerical precision problems that could be */ /* caused by using a REAL constant in a double precision */ /* computation. The value 1.0 was repaced with the value 1.0D0 in */ /* the following three lines: */ /* DSTORT(1) = 1.0 / A */ /* DSTORT(2) = 1.0 / B */ /* DSTORT(3) = 1.0 / C */ /* Also changed was a numeric constant from 1.D0 to the */ /* equivalent, but more aesthetically pleasing 1.0D0. */ /* - 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, 02-NOV-1990 (NJB) */ /* -& */ /* $ Index_Entries */ /* intersection of ellipsoid and plane */ /* -& */ /* $ Revisions */ /* - SPICELIB Version 1.2.0, 16-NOV-2005 (NJB) */ /* Bug fix: error detection for case of invalid input plane was */ /* added. */ /* Updated to remove non-standard use of duplicate arguments */ /* in VSCL calls. */ /* - SPICELIB Version 1.1.0, 11-JUL-1995 (KRG) */ /* Removed potential numerical precision problems that could be */ /* caused by using a REAL constant in a double precision */ /* computation. The value 1.0 was repaced with the value 1.0D0 in */ /* the following three lines: */ /* DSTORT(1) = 1.0 / A */ /* DSTORT(2) = 1.0 / B */ /* DSTORT(3) = 1.0 / C */ /* Also changed was a numeric constant from 1.D0 to the */ /* equivalent, but more aesthetically pleasing 1.0D0. */ /* - SPICELIB Version 1.0.1, 10-MAR-1992 (WLT) */ /* Comment section for permuted index source lines was added */ /* following the header. */ /* -& */ /* SPICELIB functions */ /* Local variables */ /* Standard SPICE error handling. */ if (return_()) { return 0; } else { chkin_("INEDPL", (ftnlen)6); } /* We don't want to worry about flat ellipsoids: */ if (*a <= 0. || *b <= 0. || *c__ <= 0.) { *found = FALSE_; setmsg_("Semi-axes: A = #, B = #, C = #.", (ftnlen)33); errdp_("#", a, (ftnlen)1); errdp_("#", b, (ftnlen)1); errdp_("#", c__, (ftnlen)1); sigerr_("SPICE(DEGENERATECASE)", (ftnlen)21); chkout_("INEDPL", (ftnlen)6); return 0; } /* Check input plane for zero normal vector. */ pl2nvc_(plane, normal, &const__); if (vzero_(normal)) { setmsg_("Normal vector of the input PLANE is the zero vector.", ( ftnlen)52); sigerr_("SPICE(INVALIDPLANE)", (ftnlen)19); chkout_("INEDPL", (ftnlen)6); return 0; } /* This algorithm is partitioned into a series of steps: */ /* 1) Identify a linear transformation that maps the input */ /* ellipsoid to the unit sphere. We'll call this mapping the */ /* `distortion' mapping. Apply the distortion mapping to both */ /* the input plane and ellipsoid. The image of the plane under */ /* this transformation will be a plane. */ /* 2) Find the intersection of the transformed plane and the unit */ /* sphere. */ /* 3) Apply the inverse of the distortion mapping to the */ /* intersection ellipse to find the undistorted intersection */ /* ellipse. */ /* Step 1: */ /* Find the image of the ellipsoid and plane under the distortion */ /* matrix. Since the image of the ellipsoid is the unit sphere, */ /* only the plane transformation requires any work. */ /* If the input plane is too far from the origin to possibly */ /* intersect the ellipsoid, return now. This can save us */ /* some numerical problems when we scale the plane and ellipsoid. */ /* The point returned by PL2PSV is the closest point in PLANE */ /* to the origin, so its norm gives the distance of the plane */ /* from the origin. */ pl2psv_(plane, point, span1, span2); /* Computing MAX */ d__1 = abs(*a), d__2 = abs(*b), d__1 = max(d__1,d__2), d__2 = abs(*c__); maxrad = max(d__1,d__2); if (vnorm_(point) > maxrad) { *found = FALSE_; chkout_("INEDPL", (ftnlen)6); return 0; } /* The distortion matrix and its inverse are */ /* +- -+ +- -+ */ /* | 1/A 0 0 | | A 0 0 | */ /* | 0 1/B 0 |, | 0 B 0 |. */ /* | 0 0 1/C | | 0 0 C | */ /* +- -+ +- -+ */ /* We declare them with length three, since we are going to make */ /* use of the diagonal elements only. */ dstort[0] = 1. / *a; dstort[1] = 1. / *b; dstort[2] = 1. / *c__; invdst[0] = *a; invdst[1] = *b; invdst[2] = *c__; /* Apply the distortion mapping to the input plane. Applying */ /* the distortion mapping to a point and two spanning vectors that */ /* define the input plane yields a point and two spanning vectors */ /* that define the distorted plane. */ for (i__ = 1; i__ <= 3; ++i__) { point[(i__1 = i__ - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("point", i__1, "inedpl_", (ftnlen)449)] = dstort[(i__2 = i__ - 1) < 3 && 0 <= i__2 ? i__2 : s_rnge("dstort", i__2, "inedpl_", (ftnlen) 449)] * point[(i__3 = i__ - 1) < 3 && 0 <= i__3 ? i__3 : s_rnge("point", i__3, "inedpl_", (ftnlen)449)]; span1[(i__1 = i__ - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("span1", i__1, "inedpl_", (ftnlen)450)] = dstort[(i__2 = i__ - 1) < 3 && 0 <= i__2 ? i__2 : s_rnge("dstort", i__2, "inedpl_", (ftnlen) 450)] * span1[(i__3 = i__ - 1) < 3 && 0 <= i__3 ? i__3 : s_rnge("span1", i__3, "inedpl_", (ftnlen)450)]; span2[(i__1 = i__ - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("span2", i__1, "inedpl_", (ftnlen)451)] = dstort[(i__2 = i__ - 1) < 3 && 0 <= i__2 ? i__2 : s_rnge("dstort", i__2, "inedpl_", (ftnlen) 451)] * span2[(i__3 = i__ - 1) < 3 && 0 <= i__3 ? i__3 : s_rnge("span2", i__3, "inedpl_", (ftnlen)451)]; } psv2pl_(point, span1, span2, dplane); /* Step 2: */ /* Find the intersection of the distorted plane and unit sphere. */ /* The intersection of the distorted plane and the unit sphere */ /* may be a circle, a point, or the empty set. The distance of the */ /* plane from the origin determines which type of intersection we */ /* have. If we represent the distorted plane by a unit normal */ /* vector and constant, the size of the constant gives us the */ /* distance of the plane from the origin. If the distance is greater */ /* than 1, the intersection of plane and unit sphere is empty. If */ /* the distance is equal to 1, we have the tangency case. */ /* The routine PL2PSV always gives us an output point that is the */ /* closest point to the origin in the input plane. This point is */ /* the center of the intersection circle. The spanning vectors */ /* returned by PL2PSV, after we scale them by the radius of the */ /* intersection circle, become an orthogonal pair of vectors that */ /* extend from the center of the circle to the circle itself. So, */ /* the center and these scaled vectors define the intersection */ /* circle. */ pl2psv_(dplane, center, vec1, vec2); dist = vnorm_(center); if (dist > 1.) { *found = FALSE_; chkout_("INEDPL", (ftnlen)6); return 0; } /* Scale the generating vectors by the radius of the intersection */ /* circle. */ /* Computing 2nd power */ d__2 = dist; d__1 = 1. - d__2 * d__2; rcircl = sqrt(brcktd_(&d__1, &c_b32, &c_b33)); vsclip_(&rcircl, vec1); vsclip_(&rcircl, vec2); /* Step 3: */ /* Apply the inverse distortion to the intersection circle to find */ /* the actual intersection ellipse. */ for (i__ = 1; i__ <= 3; ++i__) { center[(i__1 = i__ - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("center", i__1, "inedpl_", (ftnlen)511)] = invdst[(i__2 = i__ - 1) < 3 && 0 <= i__2 ? i__2 : s_rnge("invdst", i__2, "inedpl_", ( ftnlen)511)] * center[(i__3 = i__ - 1) < 3 && 0 <= i__3 ? i__3 : s_rnge("center", i__3, "inedpl_", (ftnlen)511)]; vec1[(i__1 = i__ - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("vec1", i__1, "inedpl_", (ftnlen)512)] = invdst[(i__2 = i__ - 1) < 3 && 0 <= i__2 ? i__2 : s_rnge("invdst", i__2, "inedpl_", (ftnlen)512)] * vec1[(i__3 = i__ - 1) < 3 && 0 <= i__3 ? i__3 : s_rnge( "vec1", i__3, "inedpl_", (ftnlen)512)]; vec2[(i__1 = i__ - 1) < 3 && 0 <= i__1 ? i__1 : s_rnge("vec2", i__1, "inedpl_", (ftnlen)513)] = invdst[(i__2 = i__ - 1) < 3 && 0 <= i__2 ? i__2 : s_rnge("invdst", i__2, "inedpl_", (ftnlen)513)] * vec2[(i__3 = i__ - 1) < 3 && 0 <= i__3 ? i__3 : s_rnge( "vec2", i__3, "inedpl_", (ftnlen)513)]; } /* Make an ellipse from the center and generating vectors. */ cgv2el_(center, vec1, vec2, ellips); *found = TRUE_; chkout_("INEDPL", (ftnlen)6); return 0; } /* inedpl_ */
/* $Procedure INRYPL ( Intersection of ray and plane ) */ /* Subroutine */ int inrypl_(doublereal *vertex, doublereal *dir, doublereal * plane, integer *nxpts, doublereal *xpt) { /* System generated locals */ doublereal d__1, d__2; /* Local variables */ doublereal udir[3]; extern /* Subroutine */ int vhat_(doublereal *, doublereal *), vscl_( doublereal *, doublereal *, doublereal *); extern doublereal vdot_(doublereal *, doublereal *); extern /* Subroutine */ int vequ_(doublereal *, doublereal *); doublereal scale; extern /* Subroutine */ int chkin_(char *, ftnlen); extern doublereal dpmax_(void); extern /* Subroutine */ int vlcom_(doublereal *, doublereal *, doublereal *, doublereal *, doublereal *); doublereal const__, prjvn; extern doublereal vnorm_(doublereal *); extern logical vzero_(doublereal *); extern /* Subroutine */ int pl2nvc_(doublereal *, doublereal *, doublereal *), cleard_(integer *, doublereal *); doublereal mscale, prjdif, sclcon, toobig, normal[3], prjdir; extern logical smsgnd_(doublereal *, doublereal *); extern /* Subroutine */ int sigerr_(char *, ftnlen), chkout_(char *, ftnlen), vsclip_(doublereal *, doublereal *), setmsg_(char *, ftnlen); extern logical return_(void); doublereal sclvtx[3]; /* $ Abstract */ /* Find the intersection of a ray and a plane. */ /* $ Disclaimer */ /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */ /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */ /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */ /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */ /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */ /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */ /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */ /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */ /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */ /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */ /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */ /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */ /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */ /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */ /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */ /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */ /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */ /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */ /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */ /* $ Required_Reading */ /* PLANES */ /* $ Keywords */ /* GEOMETRY */ /* $ Declarations */ /* $ Brief_I/O */ /* Variable I/O Description */ /* -------- --- -------------------------------------------------- */ /* VERTEX, */ /* DIR I Vertex and direction vector of ray. */ /* PLANE I A SPICELIB plane. */ /* NXPTS O Number of intersection points of ray and plane. */ /* XPT O Intersection point, if NXPTS = 1. */ /* $ Detailed_Input */ /* VERTEX, */ /* DIR are a point and direction vector that define a */ /* ray in three-dimensional space. */ /* PLANE is a SPICELIB plane. */ /* $ Detailed_Output */ /* NXPTS is the number of points of intersection of the */ /* input ray and plane. Values and meanings of */ /* NXPTS are: */ /* 0 No intersection. */ /* 1 One point of intersection. Note that */ /* this case may occur when the ray's */ /* vertex is in the plane. */ /* -1 An infinite number of points of */ /* intersection; the ray lies in the plane. */ /* XPT is the point of intersection of the input ray */ /* and plane, when there is exactly one point of */ /* intersection. Otherwise, XPT is the zero vector. */ /* $ Parameters */ /* None. */ /* $ Exceptions */ /* 1) If the ray's direction vector is the zero vector, the error */ /* SPICE(ZEROVECTOR) is signaled. NXPTS and XPT are not */ /* modified. */ /* 2) If the ray's vertex is further than DPMAX() / 3 from the */ /* origin, the error SPICE(VECTORTOOBIG) is signaled. NXPTS */ /* and XPT are not modified. */ /* 3) If the input plane is s further than DPMAX() / 3 from the */ /* origin, the error SPICE(VECTORTOOBIG) is signaled. NXPTS */ /* and XPT are not modified. */ /* 4) The input plane should be created by one of the SPICELIB */ /* routines */ /* NVC2PL */ /* NVP2PL */ /* PSV2PL */ /* Invalid input planes will cause unpredictable results. */ /* 5) In the interest of good numerical behavior, in the case */ /* where the ray's vertex is not in the plane, this routine */ /* considers that an intersection of the ray and plane occurs */ /* only if the distance between the ray's vertex and the */ /* intersection point is less than DPMAX() / 3. */ /* If VERTEX is not in the plane and this condition is not */ /* met, then NXPTS is set to 0 and XPT is set to the zero */ /* vector. */ /* $ Files */ /* None. */ /* $ Particulars */ /* The intersection of a ray and plane in three-dimensional space */ /* can be a the empty set, a single point, or the ray itself. */ /* $ Examples */ /* 1) Find the camera projection of the center of an extended */ /* body. For simplicity, we assume: */ /* -- The camera has no distortion; the image of a point */ /* is determined by the intersection of the focal plane */ /* and the line determined by the point and the camera's */ /* focal point. */ /* -- The camera's pointing matrix (C-matrix) is available */ /* in a C-kernel. */ /* C */ /* C Load Leapseconds and SCLK kernels to support time */ /* C conversion. */ /* C */ /* CALL FURNSH ( 'LEAP.KER' ) */ /* CALL FURNSH ( 'SCLK.KER' ) */ /* C */ /* C Load an SPK file containing ephemeris data for */ /* C observer (a spacecraft, whose NAIF integer code */ /* C is SC) and target at the UTC epoch of observation. */ /* C */ /* CALL FURNSH ( 'SPK.BSP' ) */ /* C */ /* C Load a C-kernel containing camera pointing for */ /* C the UTC epoch of observation. */ /* C */ /* CALL FURNSH ( 'CK.BC' ) */ /* C */ /* C Find the ephemeris time (barycentric dynamical time) */ /* C and encoded spacecraft clock times corresponding to */ /* C the UTC epoch of observation. */ /* C */ /* CALL UTC2ET ( UTC, ET ) */ /* CALL SCE2C ( SC, ET, SCLKDP ) */ /* C */ /* C Encode the pointing lookup tolerance. */ /* C */ /* CALL SCTIKS ( SC, TOLCH, TOLDP ) */ /* C */ /* C Find the observer-target vector at the observation */ /* C epoch. In this example, we'll use a light-time */ /* C corrected state vector. */ /* C */ /* CALL SPKEZ ( TARGET, ET, 'J2000', 'LT', SC, */ /* . STATE, LT ) */ /* C */ /* C Look up camera pointing. */ /* C */ /* CALL CKGP ( CAMERA, SCLKDP, TOLDP, 'J2000', CMAT, */ /* . CLKOUT, FOUND ) */ /* IF ( .NOT. FOUND ) THEN */ /* [Handle this case...] */ /* END IF */ /* C */ /* C Negate the spacecraft-to-target body vector and */ /* C convert it to camera coordinates. */ /* C */ /* CALL VMINUS ( STATE, DIR ) */ /* CALL MXV ( CMAT, DIR, DIR ) */ /* C */ /* C If FL is the camera's focal length, the effective */ /* C focal point is */ /* C */ /* C FL * ( 0, 0, 1 ) */ /* C */ /* CALL VSCL ( FL, ZVEC, FOCUS ) */ /* C */ /* C The camera's focal plane contains the origin in */ /* C camera coordinates, and the z-vector is orthogonal */ /* C to the plane. Make a SPICELIB plane representing */ /* C the focal plane. */ /* C */ /* CALL NVC2PL ( ZVEC, 0.D0, FPLANE ) */ /* C */ /* C The image of the target body's center in the focal */ /* C plane is defined by the intersection with the focal */ /* C plane of the ray whose vertex is the focal point and */ /* C whose direction is DIR. */ /* C */ /* CALL INRYPL ( FOCUS, DIR, FPLANE, NXPTS, IMAGE ) */ /* IF ( NXPTS .EQ. 1 ) THEN */ /* C */ /* C The body center does project to the focal plane. */ /* C Check whether the image is actually in the */ /* C camera's field of view... */ /* C */ /* . */ /* . */ /* . */ /* ELSE */ /* C */ /* C The body center does not map to the focal plane. */ /* C Handle this case... */ /* C */ /* . */ /* . */ /* . */ /* END IF */ /* 2) Find the Saturn ring plane intercept of a spacecraft-mounted */ /* instrument's boresight vector. We want the find the point */ /* in the ring plane that will be observed by an instrument */ /* with a give boresight direction at a specified time. We */ /* must account for light time and stellar aberration in order */ /* to find this point. The intercept point will be expressed */ /* in Saturn body-fixed coordinates. */ /* In this example, we assume */ /* -- The ring plane is equatorial. */ /* -- Light travels in a straight line. */ /* -- The light time correction for the ring plane intercept */ /* can be obtained by performing three light-time */ /* correction iterations. If this assumption does not */ /* lead to a sufficiently accurate result, additional */ /* iterations can be performed. */ /* -- A Newtonian approximation of stellar aberration */ /* suffices. */ /* -- The boresight vector is given in J2000 coordinates. */ /* -- The observation epoch is ET ephemeris seconds past */ /* J2000. */ /* -- The boresight vector, spacecraft and planetary */ /* ephemerides, and ring plane orientation are all known */ /* with sufficient accuracy for the application. */ /* -- All necessary kernels are loaded by the caller of */ /* this example routine. */ /* SUBROUTINE RING_XPT ( SC, ET, BORVEC, SBFXPT, FOUND ) */ /* IMPLICIT NONE */ /* CHARACTER*(*) SC */ /* DOUBLE PRECISION ET */ /* DOUBLE PRECISION BORVEC ( 3 ) */ /* DOUBLE PRECISION SBFXPT ( 3 ) */ /* LOGICAL FOUND */ /* C */ /* C SPICELIB functions */ /* C */ /* DOUBLE PRECISION CLIGHT */ /* DOUBLE PRECISION VDIST */ /* C */ /* C Local parameters */ /* C */ /* INTEGER UBPL */ /* PARAMETER ( UBPL = 4 ) */ /* INTEGER SATURN */ /* PARAMETER ( SATURN = 699 ) */ /* C */ /* C Local variables */ /* C */ /* DOUBLE PRECISION BORV2 ( 3 ) */ /* DOUBLE PRECISION CORVEC ( 3 ) */ /* DOUBLE PRECISION LT */ /* DOUBLE PRECISION PLANE ( UBPL ) */ /* DOUBLE PRECISION SATSSB ( 6 ) */ /* DOUBLE PRECISION SCPOS ( 3 ) */ /* DOUBLE PRECISION SCSSB ( 6 ) */ /* DOUBLE PRECISION STATE ( 6 ) */ /* DOUBLE PRECISION STCORR ( 3 ) */ /* DOUBLE PRECISION TAU */ /* DOUBLE PRECISION TPMI ( 3, 3 ) */ /* DOUBLE PRECISION XPT ( 3 ) */ /* DOUBLE PRECISION ZVEC ( 3 ) */ /* INTEGER I */ /* INTEGER NXPTS */ /* INTEGER SCID */ /* LOGICAL FND */ /* C */ /* C First step: account for stellar aberration. Since the */ /* C instrument pointing is given, we need to find the intercept */ /* C point such that, when the stellar aberration correction is */ /* C applied to the vector from the spacecraft to that point, */ /* C the resulting vector is parallel to BORVEC. An easy */ /* C solution is to apply the inverse of the normal stellar */ /* C aberration correction to BORVEC, and then solve the */ /* C intercept problem with this corrected boresight vector. */ /* C */ /* C Find the position of the observer relative */ /* C to the solar system barycenter at ET. */ /* C */ /* CALL BODN2C ( SC, SCID, FND ) */ /* IF ( .NOT. FND ) THEN */ /* CALL SETMSG ( 'ID code for body # was not found.' ) */ /* CALL ERRCH ( '#', SC ) */ /* CALL SIGERR ( 'SPICE(NOTRANSLATION' ) */ /* RETURN */ /* END IF */ /* CALL SPKSSB ( SCID, ET, 'J2000', SCSSB ) */ /* C */ /* C We now wish to find the vector CORVEC that, when */ /* C corrected for stellar aberration, yields BORVEC. */ /* C A good first approximation is obtained by applying */ /* C the stellar aberration correction for transmission */ /* C to BORVEC. */ /* C */ /* CALL STLABX ( BORVEC, SCSSB(4), CORVEC ) */ /* C */ /* C The inverse of the stellar aberration correction */ /* C applicable to CORVEC should be a very good estimate of */ /* C the correction we need to apply to BORVEC. Apply */ /* C this correction to BORVEC to obtain an improved estimate */ /* C of CORVEC. */ /* C */ /* CALL STELAB ( CORVEC, SCSSB(4), BORV2 ) */ /* CALL VSUB ( BORV2, CORVEC, STCORR ) */ /* CALL VSUB ( BORVEC, STCORR, CORVEC ) */ /* C */ /* C Because the ring plane intercept may be quite far from */ /* C Saturn's center, we cannot assume light time from the */ /* C intercept to the observer is well approximated by */ /* C light time from Saturn's center to the observer. */ /* C We compute the light time explicitly using an iterative */ /* C approach. */ /* C */ /* C We can however use the light time from Saturn's center to */ /* C the observer to obtain a first estimate of the actual light */ /* C time. */ /* C */ /* CALL SPKEZR ( 'SATURN', ET, 'J2000', 'LT', SC, */ /* . STATE, LT ) */ /* TAU = LT */ /* C */ /* C Find the ring plane intercept and calculate the */ /* C light time from it to the spacecraft. */ /* C Perform three iterations. */ /* C */ /* I = 1 */ /* FOUND = .TRUE. */ /* DO WHILE ( ( I .LE. 3 ) .AND. ( FOUND ) ) */ /* C */ /* C Find the position of Saturn relative */ /* C to the solar system barycenter at ET-TAU. */ /* C */ /* CALL SPKSSB ( SATURN, ET-TAU, 'J2000', SATSSB ) */ /* C */ /* C Find the Saturn-to-observer vector defined by these */ /* C two position vectors. */ /* C */ /* CALL VSUB ( SCSSB, SATSSB, SCPOS ) */ /* C */ /* C Look up Saturn's pole at ET-TAU; this is the third */ /* C column of the matrix that transforms Saturn body-fixed */ /* C coordinates to J2000 coordinates. */ /* C */ /* CALL PXFORM ( 'IAU_SATURN', 'J2000', ET-TAU, TPMI ) */ /* CALL MOVED ( TPMI(1,3), 3, ZVEC ) */ /* C */ /* C Make a SPICELIB plane representing the ring plane. */ /* C We're treating Saturn's center as the origin, so */ /* C the plane constant is 0. */ /* C */ /* CALL NVC2PL ( ZVEC, 0.D0, PLANE ) */ /* C */ /* C Find the intersection of the ring plane and the */ /* C ray having vertex SCPOS and direction vector */ /* C CORVEC. */ /* C */ /* CALL INRYPL ( SCPOS, CORVEC, PLANE, NXPTS, XPT ) */ /* C */ /* C If the number of intersection points is 1, */ /* C find the next light time estimate. */ /* C */ /* IF ( NXPTS .EQ. 1 ) THEN */ /* C */ /* C Find the light time (zero-order) from the */ /* C intercept point to the spacecraft. */ /* C */ /* TAU = VDIST ( SCPOS, XPT ) / CLIGHT() */ /* I = I + 1 */ /* ELSE */ /* FOUND = .FALSE. */ /* END IF */ /* END DO */ /* C */ /* C At this point, if FOUND is .TRUE., we iterated */ /* C 3 times, and XPT is our estimate of the */ /* C position of the ring plane intercept point */ /* C relative to Saturn in the J2000 frame. This is the */ /* C point observed by an instrument pointed in direction */ /* C BORVEC at ET at mounted on the spacecraft SC. */ /* C */ /* C If FOUND is .FALSE., the boresight ray does not */ /* C intersect the ring plane. */ /* C */ /* C As a final step, transform XPT to Saturn body-fixed */ /* C coordinates. */ /* C */ /* IF ( FOUND ) THEN */ /* CALL MTXV ( TPMI, XPT, SBFXPT ) */ /* END IF */ /* END */ /* $ Restrictions */ /* None. */ /* $ Literature_References */ /* None. */ /* $ Author_and_Institution */ /* N.J. Bachman (JPL) */ /* W.L. Taber (JPL) */ /* $ Version */ /* - SPICELIB Version 1.1.1, 07-FEB-2008 (BVS) */ /* Fixed a few typos in the header. */ /* - SPICELIB Version 1.1.0, 02-SEP-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VSCL call. */ /* - SPICELIB Version 1.0.3, 12-DEC-2002 (NJB) */ /* Header fix: ring plane intercept algorithm was corrected. */ /* Now light time is computed accurately, and stellar aberration */ /* is accounted for. Example was turned into a complete */ /* subroutine. */ /* - SPICELIB Version 1.0.2, 09-MAR-1999 (NJB) */ /* Reference to SCE2T replaced by reference to SCE2C. An */ /* occurrence of ENDIF was replaced by END IF. */ /* - SPICELIB Version 1.0.1, 10-MAR-1992 (WLT) */ /* Comment section for permuted index source lines was added */ /* following the header. */ /* - SPICELIB Version 1.0.0, 01-APR-1991 (NJB) (WLT) */ /* -& */ /* $ Index_Entries */ /* intersection of ray and plane */ /* -& */ /* $ Revisions */ /* - SPICELIB Version 1.1.0, 02-SEP-2005 (NJB) */ /* Updated to remove non-standard use of duplicate arguments */ /* in VSCL call. */ /* -& */ /* SPICELIB functions */ /* Local parameters */ /* Local variables */ /* Standard SPICE error handling. */ if (return_()) { return 0; } else { chkin_("INRYPL", (ftnlen)6); } /* We'll give the name TOOBIG to the bound DPMAX() / MARGIN. */ /* If we let VTXPRJ be the orthogonal projection of VERTEX onto */ /* PLANE, and let DIFF be the vector VTXPRJ - VERTEX, then */ /* we know that */ /* || DIFF || < 2 * TOOBIG */ /* Check the distance of the ray's vertex from the origin. */ toobig = dpmax_() / 3.; if (vnorm_(vertex) >= toobig) { setmsg_("Ray's vertex is too far from the origin.", (ftnlen)40); sigerr_("SPICE(VECTORTOOBIG)", (ftnlen)19); chkout_("INRYPL", (ftnlen)6); return 0; } /* Check the distance of the plane from the origin. (The returned */ /* plane constant IS this distance.) */ pl2nvc_(plane, normal, &const__); if (const__ >= toobig) { setmsg_("Plane is too far from the origin.", (ftnlen)33); sigerr_("SPICE(VECTORTOOBIG)", (ftnlen)19); chkout_("INRYPL", (ftnlen)6); return 0; } /* Check the ray's direction vector. */ vhat_(dir, udir); if (vzero_(udir)) { setmsg_("Ray's direction vector is the zero vector.", (ftnlen)42); sigerr_("SPICE(ZEROVECTOR)", (ftnlen)17); chkout_("INRYPL", (ftnlen)6); return 0; } /* That takes care of the error cases. Now scale the input vertex */ /* and plane to improve numerical behavior. */ /* Computing MAX */ d__1 = const__, d__2 = vnorm_(vertex); mscale = max(d__1,d__2); if (mscale != 0.) { d__1 = 1. / mscale; vscl_(&d__1, vertex, sclvtx); sclcon = const__ / mscale; } else { vequ_(vertex, sclvtx); sclcon = const__; } if (mscale > 1.) { toobig /= mscale; } /* Find the projection (coefficient) of the ray's vertex along the */ /* plane's normal direction. */ prjvn = vdot_(sclvtx, normal); /* If this projection is the plane constant, the ray's vertex lies in */ /* the plane. We have one intersection or an infinite number of */ /* intersections. It all depends on whether the ray actually lies */ /* in the plane. */ /* The absolute value of PRJDIF is the distance of the ray's vertex */ /* from the plane. */ prjdif = sclcon - prjvn; if (prjdif == 0.) { /* XPT is the original, unscaled vertex. */ vequ_(vertex, xpt); if (vdot_(normal, udir) == 0.) { /* The ray's in the plane. */ *nxpts = -1; } else { *nxpts = 1; } chkout_("INRYPL", (ftnlen)6); return 0; } /* Ok, the ray's vertex is not in the plane. The ray may still be */ /* parallel to or may point away from the plane. If the ray does */ /* point towards the plane, mathematicians would say that the */ /* ray does intersect the plane, but the computer may disagree. */ /* For this routine to find an intersection, both of the following */ /* conditions must be met: */ /* -- The ray must point toward the plane; this happens when */ /* PRJDIF has the same sign as < UDIR, NORMAL >. */ /* -- The vector difference XPT - SCLVTX must not overflow. */ /* Qualitatively, the case of interest looks something like the */ /* picture below: */ /* * SCLVTX */ /* |\ */ /* | \ <-- UDIR */ /* | \ */ /* length of this | \| */ /* segment is | -* */ /* | */ /* | PRJDIF | --> | ___________________________ */ /* |/ / */ /* | * / <-- PLANE */ /* /| XPT / */ /* / ^ / */ /* / | NORMAL / */ /* / | . / */ /* / |/| / */ /* / .---| / / */ /* / | |/ / */ /* / `---* / */ /* / Projection of SCLVTX onto the plane */ /* / / */ /* / / */ /* ---------------------------- */ /* Find the projection of the direction vector along the plane's */ /* normal vector. */ prjdir = vdot_(udir, normal); /* We're done if the ray doesn't point toward the plane. PRJDIF */ /* has already been found to be non-zero at this point; PRJDIR is */ /* zero if the ray and plane are parallel. The SPICELIB routine */ /* SMSGND will return a value of .FALSE. if PRJDIR is zero. */ if (! smsgnd_(&prjdir, &prjdif)) { /* The ray is parallel to or points away from the plane. */ *nxpts = 0; cleard_(&c__3, xpt); chkout_("INRYPL", (ftnlen)6); return 0; } /* The difference XPT - SCLVTX is the hypotenuse of a right triangle */ /* formed by SCLVTX, XPT, and the orthogonal projection of SCLVTX */ /* onto the plane. We'll obtain the hypotenuse by scaling UDIR. */ /* We must make sure that this hypotenuse does not overflow. The */ /* scale factor has magnitude */ /* | PRJDIF | */ /* -------------- */ /* | PRJDIR | */ /* and UDIR is a unit vector, so as long as */ /* | PRJDIF | < | PRJDIR | * TOOBIG */ /* the hypotenuse is no longer than TOOBIG. The product can be */ /* computed safely since PRJDIR has magnitude 1 or less. */ if (abs(prjdif) >= abs(prjdir) * toobig) { /* If the hypotenuse is too long, we say that no intersection */ /* exists. */ *nxpts = 0; cleard_(&c__3, xpt); chkout_("INRYPL", (ftnlen)6); return 0; } /* We conclude that it's safe to compute XPT. Scale UDIR and add */ /* the result to SCLVTX. The addition is safe because both addends */ /* have magnitude no larger than TOOBIG. The vector thus obtained */ /* is the intersection point. */ *nxpts = 1; scale = abs(prjdif) / abs(prjdir); vlcom_(&c_b17, sclvtx, &scale, udir, xpt); /* Re-scale XPT. This is safe, since TOOBIG has already been */ /* scaled to allow for any growth of XPT at this step. */ vsclip_(&mscale, xpt); chkout_("INRYPL", (ftnlen)6); return 0; } /* inrypl_ */