1 /*
2 
3 -Procedure dskxsi_c (DSK, ray-surface intercept with source information)
4 
5 -Abstract
6 
7    Compute a ray-surface intercept using data provided by
8    multiple loaded DSK segments. Return information about
9    the source of the data defining the surface on which the
10    intercept was found: DSK handle, DLA and DSK descriptors,
11    and DSK data type-dependent parameters.
12 
13 -Disclaimer
14 
15    THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE
16    CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S.
17    GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE
18    ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE
19    PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS"
20    TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY
21    WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A
22    PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC
23    SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE
24    SOFTWARE AND RELATED MATERIALS, HOWEVER USED.
25 
26    IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA
27    BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT
28    LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND,
29    INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS,
30    REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE
31    REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY.
32 
33    RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF
34    THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY
35    CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE
36    ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE.
37 
38 -Required_Reading
39 
40    CK
41    DSK
42    FRAMES
43    PCK
44    SPK
45    TIME
46 
47 -Keywords
48 
49    GEOMETRY
50    INTERCEPT
51    SURFACE
52    TOPOGRAPHY
53 
54 */
55 
56    #include "SpiceUsr.h"
57    #include "SpiceZfc.h"
58    #include "SpiceZst.h"
59    #include "SpiceZmc.h"
60    #undef dskxsi_c
61 
62 
dskxsi_c(SpiceBoolean pri,ConstSpiceChar * target,SpiceInt nsurf,ConstSpiceInt srflst[],SpiceDouble et,ConstSpiceChar * fixref,ConstSpiceDouble vertex[3],ConstSpiceDouble raydir[3],SpiceInt maxd,SpiceInt maxi,SpiceDouble xpt[3],SpiceInt * handle,SpiceDLADescr * dladsc,SpiceDSKDescr * dskdsc,SpiceDouble dc[],SpiceInt ic[],SpiceBoolean * found)63    void dskxsi_c ( SpiceBoolean         pri,
64                    ConstSpiceChar     * target,
65                    SpiceInt             nsurf,
66                    ConstSpiceInt        srflst [],
67                    SpiceDouble          et,
68                    ConstSpiceChar     * fixref,
69                    ConstSpiceDouble     vertex [3],
70                    ConstSpiceDouble     raydir [3],
71                    SpiceInt             maxd,
72                    SpiceInt             maxi,
73                    SpiceDouble          xpt    [3],
74                    SpiceInt           * handle,
75                    SpiceDLADescr      * dladsc,
76                    SpiceDSKDescr      * dskdsc,
77                    SpiceDouble          dc     [],
78                    SpiceInt             ic     [],
79                    SpiceBoolean       * found      )
80 /*
81 
82 -Brief_I/O
83 
84    VARIABLE  I/O  DESCRIPTION
85    --------  ---  --------------------------------------------------
86    pri        I   Data prioritization flag.
87    target     I   Target body name.
88    nsurf      I   Number of surface IDs in list.
89    srflst     I   Surface ID list.
90    et         I   Epoch, expressed as seconds past J2000 TDB.
91    fixref     I   Name of target body-fixed reference frame.
92    vertex     I   Vertex of ray.
93    raydir     I   Direction vector of ray.
94    maxd       I   Size of DC array.
95    maxi       I   Size of IC array.
96    xpt        O   Intercept point.
97    handle     O   Handle of segment contributing surface data.
98    dladsc     O   DLA descriptor of segment.
99    dskdsc     O   DSK descriptor of segment.
100    dc         O   Double precision component of source info.
101    ic         O   Integer component of source info.
102    found      O   Found flag.
103    SPICE_DSKXSI_DCSIZE
104               P    Required size of DC array.
105    SPICE_DSKXSI_ICSIZE
106               P    Required size of IC array.
107 
108 -Detailed_Input
109 
110    pri        is a logical flag indicating whether to perform
111               a prioritized or unprioritized DSK segment search.
112               In an unprioritized search, no segment masks another:
113               data from all specified segments are used to
114               define the surface of interest.
115 
116               The search is unprioritized if and only if `pri'
117               is set to SPICEFALSE. In the N0066 SPICE Toolkit, this
118               is the only allowed value.
119 
120 
121    target     is the name of the target body on which a surface
122               intercept is sought.
123 
124 
125    nsurf,
126    srflst     are, respectively, a count of surface ID codes in a list
127               and an array containing the list. Only DSK segments for
128               the body designated by `target' and having surface IDs in
129               this list will be considered in the intercept
130               computation. If the list is empty, all DSK segments for
131               `target' will be considered.
132 
133 
134    et         is the epoch of the intersection computation, expressed
135               as seconds past J2000 TDB. This epoch is used only for
136               DSK segment selection. Segments used in the intercept
137               computation must include `et' in their time coverage
138               intervals.
139 
140 
141    fixref     is the name of a body-fixed, body-centered reference
142               frame associated with the target. The input ray vectors
143               are specified in this frame, as is the output intercept
144               point.
145 
146               The frame designated by `fixref' must have a fixed
147               orientation relative to the frame of any DSK segment
148               used in the computation.
149 
150 
151    vertex,
152    raydir     are, respectively, the vertex and direction vector of
153               the ray to be used in the intercept computation.
154 
155               Both the vertex and ray's direction vector must be
156               represented in the reference frame designated by
157               `fixref'. The vertex is considered to be an offset from
158               the target body.
159 
160    maxd,
161    maxi       are, respectively, the declared sizes of the arrays
162               `dc' and `ic'. `maxd' must be at least
163 
164                  SPICE_DSKXSI_DCSIZE
165 
166               while `maxi' must be at least
167 
168                  SPICE_DSKXSI_ICSIZE
169 
170               See the Parameters section for details.
171 
172 -Detailed_Output
173 
174 
175    xpt        is the intercept of the input ray on the surface
176               specified by the inputs
177 
178                  pri
179                  target
180                  nsurf
181                  srflst
182                  et
183 
184               if such an intercept exists. If the ray intersects the
185               surface at multiple points, the one closest to the
186               ray's vertex is selected.
187 
188               `xpt' is defined if and only if `found' is SPICETRUE.
189 
190               Units are km.
191 
192 
193    handle,
194    dladsc,
195    dskdsk     are, respectively, the DSK file handle, DLA descriptor,
196               and DSK descriptor of the DSK file and segment that
197               contributed the surface data on which the intercept
198               was found.
199 
200               These outputs are defined if and only if `found' is
201               SPICETRUE.
202 
203    dc,
204    ic         are, respectively, double precision and integer arrays
205               that may contain additional information associated
206               with the segment contributing the surface data on
207               which the intercept was found. The information is
208               DSK data type-dependent.
209 
210                  For DSK type 2 segments
211 
212                     ic[0] is the intercept plate ID.
213                     `dc' is unused.
214 
215               These outputs are defined if and only if `found' is
216               SPICETRUE.
217 
218 
219    found      is a logical flag that is set to SPICETRUE if and only if
220               and intercept was found.
221 
222 
223 -Parameters
224 
225    See the header file
226 
227       SpiceDSK.h
228 
229    for declarations of size parameters for the output arguments
230 
231       dc
232       ic
233 
234    See the header files
235 
236       SpiceDLA.h
237       SpiceDSK.h
238 
239    for declarations of DLA and DSK descriptor sizes and
240    documentation of the contents of these descriptors.
241 
242    See the header file
243 
244       SpiceDtl.h
245 
246    for the values of tolerance parameters used by default by the
247    ray-surface intercept algorithm. These are discussed in in the
248    Particulars section below.
249 
250 -Exceptions
251 
252    1)  If the input prioritization flag `pri' is set to SPICETRUE,
253        the error SPICE(NOPRIORITIZATION) is signaled.
254 
255    2)  If the input body name `target' cannot be mapped to an
256        ID code, the error SPICE(IDCODENOTFOUND) is signaled.
257 
258    3)  If the input frame name `fixref' cannot be mapped to an
259        ID code, the error SPICE(IDCODENOTFOUND) is signaled.
260 
261    4)  If the frame center associated with `fixref' cannot be
262        retrieved, the error SPICE(NOFRAMEINFO) is signaled.
263 
264    5)  If the frame center associated with `fixref' is not
265        the target body, the error SPICE(INVALIDFRAME) is signaled.
266 
267    6)  Any errors that occur during the intercept computation
268        will be signaled by routines in the call tree of this
269        routine.
270 
271    7)  If `maxd' is less than SPICE_DSKXIS_DCSIZE or `maxi' is less
272        than SPICE_DSKXSI_ICSIZE, the error SPICE(ARRAYTOOSMALL) will
273        be signaled.
274 
275    8)  If any input string argument pointer is null, the error
276        SPICE(NULLPOINTER) will be signaled.
277 
278    9)  If any input string argument is empty, the error
279        SPICE(EMPTYSTRING) will be signaled.
280 
281 -Files
282 
283    Appropriate kernels must be loaded by the calling program before
284    this routine is called.
285 
286    The following data are required:
287 
288       - SPK data: ephemeris data for the positions of the centers
289         of DSK reference frames relative to the target body are
290         required if those frames are not centered at the target
291         body center.
292 
293         Typically ephemeris data are made available by loading one
294         or more SPK files via furnsh_c.
295 
296       - DSK data: DSK files containing topographic data for the
297         target body must be loaded. If a surface list is specified,
298         data for at least one of the listed surfaces must be loaded.
299 
300       - Frame data: if a frame definition is required to convert
301         DSK segment data to the body-fixed frame designated by
302         `fixref', the target, that definition must be available in the
303         kernel pool. Typically the definitions of frames not already
304         built-in to SPICE are supplied by loading a frame kernel.
305 
306       - CK data: if the frame to which `fixref' refers is a CK frame,
307         and if any DSK segments used in the computation have a
308         different frame, at least one CK file will be needed to
309         permit transformation of vectors between that frame and both
310         the J2000 and the target body-fixed frames.
311 
312       - SCLK data: if a CK file is needed, an associated SCLK
313         kernel is required to enable conversion between encoded SCLK
314         (used to time-tag CK data) and barycentric dynamical time
315         (TDB).
316 
317    In all cases, kernel data are normally loaded once per program
318    run, NOT every time this routine is called.
319 
320 
321 -Particulars
322 
323 
324    This is the lowest-level public interface for computing
325    ray-surface intercepts, where the surface is modeled using
326    topographic data provided by DSK files. The highest-level
327    interface for this purpose is sincpt_c.
328 
329    In cases where the data source information returned by this
330    routine are not needed, the routine dskxv_c may be more suitable.
331 
332    This routine works with multiple DSK files. It places no
333    restrictions on the data types or coordinate systems of the DSK
334    segments used in the computation. DSK segments using different
335    reference frames may be used in a single computation. The only
336    restriction is that any pair of reference frames used directly or
337    indirectly are related by a constant rotation.
338 
339    This routine enables calling applications to identify the source of
340    the data defining the surface on which an intercept was found. The
341    file, segment, and segment-specific information such as a DSK type 2
342    plate ID are returned.
343 
344    This routine can be used for improved efficiency in situations
345    in which multiple ray-surface intercepts are to be performed
346    using a constant ray vertex.
347 
348 
349    Using DSK data
350    ==============
351 
352       DSK loading and unloading
353       -------------------------
354 
355       DSK files providing data used by this routine are loaded by
356       calling furnsh_c and can be unloaded by calling unload_c or
357       kclear_c. See the documentation of furnsh_c for limits on numbers
358       of loaded DSK files.
359 
360       For run-time efficiency, it's desirable to avoid frequent
361       loading and unloading of DSK files. When there is a reason to
362       use multiple versions of data for a given target body---for
363       example, if topographic data at varying resolutions are to be
364       used---the surface list can be used to select DSK data to be
365       used for a given computation. It is not necessary to unload
366       the data that are not to be used. This recommendation presumes
367       that DSKs containing different versions of surface data for a
368       given body have different surface ID codes.
369 
370 
371       DSK data priority
372       -----------------
373 
374       A DSK coverage overlap occurs when two segments in loaded DSK
375       files cover part or all of the same domain---for example, a
376       given longitude-latitude rectangle---and when the time
377       intervals of the segments overlap as well.
378 
379       When DSK data selection is prioritized, in case of a coverage
380       overlap, if the two competing segments are in different DSK
381       files, the segment in the DSK file loaded last takes
382       precedence. If the two segments are in the same file, the
383       segment located closer to the end of the file takes
384       precedence.
385 
386       When DSK data selection is unprioritized, data from competing
387       segments are combined. For example, if two competing segments
388       both represent a surface as sets of triangular plates, the
389       union of those sets of plates is considered to represent the
390       surface.
391 
392       Currently only unprioritized data selection is supported.
393       Because prioritized data selection may be the default behavior
394       in a later version of the routine, the presence of the `pri'
395       argument is required.
396 
397 
398       Round-off errors and mitigating algorithms
399       ------------------------------------------
400 
401       When topographic data are used to represent the surface of a
402       target body, round-off errors can produce some results that
403       may seem surprising.
404 
405       Note that, since the surface in question might have mountains,
406       valleys, and cliffs, the points of intersection found for
407       nearly identical sets of inputs may be quite far apart from
408       each other: for example, a ray that hits a mountain side in a
409       nearly tangent fashion may, on a different host computer, be
410       found to miss the mountain and hit a valley floor much farther
411       from the observer, or even miss the target altogether.
412 
413       Round-off errors can affect segment selection: for example, a
414       ray that is expected to intersect the target body's surface
415       near the boundary between two segments might hit either
416       segment, or neither of them; the result may be
417       platform-dependent.
418 
419       A similar situation exists when a surface is modeled by a set
420       of triangular plates, and the ray is expected to intersect the
421       surface near a plate boundary.
422 
423       To avoid having the routine fail to find an intersection when
424       one clearly should exist, this routine uses two "greedy"
425       algorithms:
426 
427          1) If the ray passes sufficiently close to any of the
428             boundary surfaces of a segment (for example, surfaces of
429             maximum and minimum longitude or latitude), that segment
430             is tested for an intersection of the ray with the
431             surface represented by the segment's data.
432 
433             This choice prevents all of the segments from being
434             missed when at least one should be hit, but it could, on
435             rare occasions, cause an intersection to be found in a
436             segment other than the one that would be found if higher
437             precision arithmetic were used.
438 
439          2) For type 2 segments, which represent surfaces as
440             sets of triangular plates, each plate is expanded very
441             slightly before a ray-plate intersection test is
442             performed. The default plate expansion factor is
443 
444                1 + XFRACT
445 
446             where XFRACT is declared in
447 
448                SpiceDtl.h
449 
450             For example, given a value for XFRACT of 1.e-10, the
451             sides of the plate are lengthened by 1/10 of a micron
452             per km. The expansion keeps the centroid of the plate
453             fixed.
454 
455             Plate expansion prevents all plates from being missed
456             in cases where clearly at least one should be hit.
457 
458             As with the greedy segment selection algorithm, plate
459             expansion can occasionally cause an intercept to be
460             found on a different plate than would be found if higher
461             precision arithmetic were used. It also can occasionally
462             cause an intersection to be found when the ray misses
463             the target by a very small distance.
464 
465 -Examples
466 
467    The numerical results shown for these examples may differ across
468    platforms. The results depend on the SPICE kernels used as
469    input, the compiler and supporting libraries, and the machine
470    specific arithmetic implementation.
471 
472    1) Compute surface intercepts of rays emanating from a set of
473       vertices distributed on a longitude-latitude grid. All
474       vertices are outside the target body, and all rays point
475       toward the target's center.
476 
477       Check intercepts against expected values. Indicate the
478       number of errors, the number of computations, and the
479       number of intercepts found.
480 
481       Use the meta-kernel shown below to load example SPICE
482       kernels.
483 
484           KPL/MK
485 
486           File: dskxsi_ex1.tm
487 
488           This meta-kernel is intended to support operation of SPICE
489           example programs. The kernels shown here should not be
490           assumed to contain adequate or correct versions of data
491           required by SPICE-based user applications.
492 
493           In order for an application to use this meta-kernel, the
494           kernels referenced here must be present in the user's
495           current working directory.
496 
497           The names and contents of the kernels referenced
498           by this meta-kernel are as follows:
499 
500              File name                        Contents
501              ---------                        --------
502              phobos512.bds                    DSK based on
503                                               Gaskell ICQ Q=512
504                                               plate model
505           \begindata
506 
507              PATH_SYMBOLS    = 'GEN'
508              PATH_VALUES     = '/ftp/pub/naif/generic_kernels'
509 
510              KERNELS_TO_LOAD = ( '$GEN/dsk/phobos/phobos512.bds' )
511 
512           \begintext
513 
514 
515    Example code begins here.
516 
517 
518       /.
519       Multi-segment spear program.
520 
521       This program expects all loaded DSKs
522       to represent the same body and surface.
523 
524       Syntax: spear <meta-kernel>
525       ./
526 
527       #include <stdio.h>
528       #include <stdlib.h>
529       #include "SpiceUsr.h"
530 
531       int main( int argc,  char **argv )
532       {
533          /.
534          Local constants
535          ./
536          #define  DTOL           1.0e-14
537          #define  FILSIZ         256
538          #define  FRNMLN         33
539          #define  BDNMLN         37
540          #define  TYPLEN         5
541          #define  INTLEN         12
542          #define  MAXN           100000
543          #define  MAXSRF         100
544          #define  MAXD           SPICE_DSKXSI_DCSIZE
545          #define  MAXI           SPICE_DSKXSI_ICSIZE
546 
547          /.
548          Local variables
549          ./
550          SpiceBoolean            found;
551 
552          SpiceChar               dsk1   [FILSIZ];
553          SpiceChar               fixref [FRNMLN];
554          SpiceChar               source [FILSIZ];
555          SpiceChar               filtyp [TYPLEN];
556          SpiceChar               target [BDNMLN];
557 
558          SpiceDLADescr           dladsc;
559          SpiceDLADescr           xptDLAdsc;
560 
561          SpiceDSKDescr           dskdsc;
562          SpiceDSKDescr           xptDSKdsc;
563 
564          SpiceDouble             d;
565          SpiceDouble             dc    [1];
566          static SpiceDouble      dirarr[MAXN][3];
567          SpiceDouble             et;
568          SpiceDouble             lat;
569          SpiceDouble             latcrd[3];
570          SpiceDouble             latstp;
571          SpiceDouble             lon;
572          SpiceDouble             lonstp;
573          SpiceDouble             polmrg;
574          SpiceDouble             r;
575          SpiceDouble             radius;
576          SpiceDouble             vlat;
577          SpiceDouble             vlon;
578          SpiceDouble             vrad;
579          static SpiceDouble      vtxarr[MAXN][3];
580          static SpiceDouble      xpt   [3];
581          SpiceDouble             xyzhit[3];
582 
583          SpiceInt                bodyid;
584          SpiceInt                framid;
585          SpiceInt                handle;
586          SpiceInt                i;
587          SpiceInt                ic    [1];
588          SpiceInt                nderr;
589          SpiceInt                nhits;
590          SpiceInt                nlstep;
591          SpiceInt                nrays;
592          SpiceInt                nsurf;
593          static SpiceInt         srflst [MAXSRF];
594          SpiceInt                surfid;
595          SpiceInt                xpthan;
596 
597 
598 
599          chkin_c ( "spear" );
600 
601          /.
602          Get meta-kernel name from the command line.
603          ./
604          if ( argc != 2 )
605          {
606             printf ( "Command syntax:  spear <meta-kernel>\n" );
607             exit(1);
608          }
609 
610          /.
611          Load the meta-kernel.
612          ./
613          furnsh_c ( argv[1] );
614 
615          /.
616          Get a handle for one of the loaded DSKs,
617          then find the first segment and extract
618          the body and surface IDs.
619          ./
620          kdata_c ( 0,    "DSK",  FILSIZ, TYPLEN,  FILSIZ,
621                    dsk1, filtyp, source, &handle, &found );
622          if ( !found )
623          {
624             sigerr_c ( "SPICE(NOINFO)" );
625          }
626 
627          dlabfs_c ( handle, &dladsc, &found );
628 
629          if ( !found )
630          {
631             sigerr_c ( "SPICE(NOSEGMENT)" );
632          }
633 
634          dskgd_c ( handle, &dladsc, &dskdsc );
635 
636          bodyid = dskdsc.center;
637          surfid = dskdsc.surfce;
638          framid = dskdsc.frmcde;
639 
640          bodc2n_c ( bodyid, BDNMLN, target, &found );
641 
642          if ( !found )
643          {
644             setmsg_c ( "Cannot map body ID # to a name." );
645             errint_c ( "#", bodyid                       );
646             sigerr_c ( "SPICE(BODYNAMENOTFOUND)"         );
647          }
648 
649          frmnam_c ( framid, FRNMLN, fixref );
650 
651          if ( eqstr_c( fixref, " " ) )
652          {
653             setmsg_c ( "Cannot map frame ID # to a name." );
654             errint_c ( "#", framid                        );
655             sigerr_c ( "SPICE(BODYNAMENOTFOUND)"          );
656          }
657 
658          /.
659          Set the magnitude of the ray vertices. Use a large
660          number to ensure the vertices are outside of
661          any realistic target.
662          ./
663          r = 1.0e10;
664 
665          /.
666          Spear the target with rays pointing toward
667          the origin.  Use a grid of ray vertices
668          located on a sphere enclosing the target.
669 
670          The variable `polmrg' ("pole margin") can
671          be set to a small positive value to reduce
672          the number of intercepts done at the poles.
673          This may speed up the computation for
674          the multi-segment case, since rays parallel
675          to the Z axis will cause all segments converging
676          at the pole of interest to be tested for an
677          intersection.
678          ./
679 
680          polmrg =    0.5;
681          latstp =    1.0;
682          lonstp =    2.0;
683 
684          nhits  =    0;
685          nderr  =    0;
686 
687          lon    = -180.0;
688          lat    =   90.0;
689          nlstep =    0;
690          nrays  =    0;
691 
692          /.
693          Generate rays.
694          ./
695          while ( lon < 180.0 )
696          {
697             while ( nlstep <= 180 )
698             {
699                if ( lon == 180.0 )
700                {
701                   lat = 90.0 - nlstep*latstp;
702                }
703                else
704                {
705                   if ( nlstep == 0 )
706                   {
707                      lat =  90.0 - polmrg;
708                   }
709                   else if ( nlstep == 180 )
710                   {
711                      lat = -90.0 + polmrg;
712                   }
713                   else
714                   {
715                      lat =  90.0 - nlstep*latstp;
716                   }
717                }
718 
719                latrec_c ( r,             lon*rpd_c(),
720                           lat*rpd_c(),   vtxarr[nrays] );
721 
722                vminus_c ( vtxarr[nrays], dirarr[nrays] );
723 
724                ++ nrays;
725                ++ nlstep;
726             }
727 
728             lon   += lonstp;
729             lat    = 90.0;
730             nlstep = 0;
731          }
732 
733          /.
734          Assign surface ID list.
735 
736          Note that, if we knew that all files had the desired
737          surface ID, we could set `nsurf' to 0 and omit the
738          initialization of the surface ID list.
739          ./
740          nsurf     = 1;
741          srflst[0] = surfid;
742 
743          printf ( "Computing intercepts...\n" );
744 
745          for ( i = 0;  i < nrays;  i++ )
746          {
747             /.
748             Find the surface intercept of the ith ray.
749             ./
750 
751             dskxsi_c ( SPICEFALSE, target,     nsurf,      srflst,
752                        et,         fixref,     vtxarr[i],  dirarr[i],
753                        MAXD,       MAXI,       xpt,        &xpthan,
754                        &xptDLAdsc, &xptDSKdsc, dc,         ic,
755                        &found                                       );
756 
757             if ( found )
758             {
759 
760                /.
761                Record that a new intercept was found.
762                ./
763                ++ nhits;
764 
765                /.
766                Check results.
767 
768 
769                Compute the latitude and longitude of
770                the intercept. Make sure these agree
771                well with those of the vertex.
772                ./
773                reclat_c ( xpt, latcrd, latcrd+1, latcrd+2 );
774                radius = latcrd[0];
775 
776                /.
777                Recover the vertex longitude and latitude.
778                ./
779                reclat_c ( vtxarr[i], &vrad, &vlon, &vlat  );
780                latrec_c ( radius,     vlon,  vlat, xyzhit );
781 
782                d = vdist_c( xpt, xyzhit );
783 
784                if ( d/r > DTOL )
785                {
786                   printf ( "===========================\n" );
787                   printf ( "Lon = %f;  Lat = %f\n",
788                            lon, lat                        );
789                   printf ( "Bad intercept\n"               );
790                   printf ( "Distance error = %e\n", d      );
791                   printf ( "xpt    = (%e %e %e)\n",
792                            xpt[0], xpt[1], xpt[2] );
793                   printf ( "xyzhit = (%e %e %e)\n",
794                            xyzhit[0], xyzhit[1], xyzhit[2] );
795                   /.
796                   Display the intercept segment's plate ID if
797                   applicable.
798                   ./
799                   if ( xptDSKdsc.dtype == 2 )
800                   {
801                      printf ( "Plate ID = %d\n", (int)ic[0] );
802                   }
803 
804 
805                   ++ nderr;
806                }
807             }
808             else
809             {
810                /.
811                Missing the target entirely is a fatal error.
812 
813                This is true only for this program, not in
814                general. For example, if the target shape is
815                a torus, many rays would miss the target.
816                ./
817                printf ( "===========================\n" );
818                printf ( "Lon = %f;  Lat = %f\n",
819                         lon, lat                        );
820                printf ( "No intercept\n"                );
821                exit( 1 );
822             }
823          }
824          printf ( "Done.\n\n" );
825 
826          printf( "nrays = %d\n", (int)nrays );
827          printf( "nhits = %d\n", (int)nhits );
828          printf( "nderr = %d\n", (int)nderr );
829 
830          return ( 0 );
831       }
832 
833 
834    When this program was executed on a PC/Linux/gcc 64-bit
835    platform, using the meta-kernel shown above, the output was:
836 
837 
838       Computing intercepts...
839       Done.
840 
841       nrays = 32580
842       nhits = 32580
843       nderr = 0
844 
845 
846 -Restrictions
847 
848    1)  The frame designated by `fixref' must have a fixed
849        orientation relative to the frame of any DSK segment
850        used in the computation. This routine has no
851        practical way of ensuring that this condition is met;
852        so this responsibility is delegated to the calling
853        application.
854 
855 -Literature_References
856 
857    None.
858 
859 -Author_and_Institution
860 
861    N.J. Bachman    (JPL)
862 
863 -Version
864 
865    -CSPICE Version 1.0.0, 04-APR-2017 (NJB)
866 
867 -Index_Entries
868 
869    dsk ray-surface intercept with source information
870    dsk ray-surface intercept with handle and descriptors
871 
872 -&
873 */
874 
875 { /* Begin dskxsi_c */
876 
877    /*
878    Local variables
879    */
880    SpiceDouble             fDSKDescr [ SPICE_DSK_DSCSIZ ];
881 
882    SpiceInt                fDLADescr [ SPICE_DLA_DSCSIZ ];
883 
884    logical                 foundFlag;
885    logical                 priFlag;
886 
887 
888    /*
889    Participate in error tracing.
890    */
891    chkin_c ( "dskxsi_c" );
892 
893    /*
894    Check the input string arguments:
895 
896       target
897       fixref
898 
899    Make sure each pointer is non-null and each string contains
900    at least one data character: that is, one character
901    preceding the null terminator.
902    */
903    CHKFSTR ( CHK_STANDARD, "dskxsi_c", target );
904    CHKFSTR ( CHK_STANDARD, "dskxsi_c", fixref );
905 
906 
907    /*
908    The input prioritization flag must be converted to type
909    logical for the following call.
910    */
911    priFlag = (logical)pri;
912 
913    dskxsi_ ( (logical     *) &priFlag,
914              (char        *) target,
915              (integer     *) &nsurf,
916              (integer     *) srflst,
917              (doublereal  *) &et,
918              (char        *) fixref,
919              (doublereal  *) vertex,
920              (doublereal  *) raydir,
921              (integer     *) &maxd,
922              (integer     *) &maxi,
923              (doublereal  *) xpt,
924              (integer     *) handle,
925              (integer     *) fDLADescr,
926              (doublereal  *) fDSKDescr,
927              (doublereal  *) dc,
928              (integer     *) ic,
929              (logical     *) &foundFlag,
930              (ftnlen       ) strlen(target),
931              (ftnlen       ) strlen(fixref)  );
932 
933    /*
934    Regardless of whether the call succeeded, transfer data from the DLA
935    and DSK descriptors to their respective output arguments.
936 
937    Set the contents of the output DLA descriptor.
938    */
939    dladsc->bwdptr = fDLADescr[SPICE_DLA_BWDIDX];
940    dladsc->fwdptr = fDLADescr[SPICE_DLA_FWDIDX];
941    dladsc->ibase  = fDLADescr[SPICE_DLA_IBSIDX];
942    dladsc->isize  = fDLADescr[SPICE_DLA_ISZIDX];
943    dladsc->dbase  = fDLADescr[SPICE_DLA_DBSIDX];
944    dladsc->dsize  = fDLADescr[SPICE_DLA_DSZIDX];
945    dladsc->cbase  = fDLADescr[SPICE_DLA_CBSIDX];
946    dladsc->csize  = fDLADescr[SPICE_DLA_CSZIDX];
947 
948    /*
949    Set the contents of the output DSK descriptor.
950    */
951    dskdsc->surfce = fDSKDescr[SPICE_DSK_SRFIDX];
952    dskdsc->center = fDSKDescr[SPICE_DSK_CTRIDX];
953    dskdsc->dclass = fDSKDescr[SPICE_DSK_CLSIDX];
954    dskdsc->dtype  = fDSKDescr[SPICE_DSK_TYPIDX];
955    dskdsc->corsys = fDSKDescr[SPICE_DSK_SYSIDX];
956    dskdsc->frmcde = fDSKDescr[SPICE_DSK_FRMIDX];
957 
958    MOVED ( fDSKDescr + SPICE_DSK_PARIDX,
959            SPICE_DSK_NSYPAR,
960            dskdsc->corpar                );
961 
962    dskdsc->co1min = fDSKDescr[SPICE_DSK_MN1IDX];
963    dskdsc->co1max = fDSKDescr[SPICE_DSK_MX1IDX];
964    dskdsc->co2min = fDSKDescr[SPICE_DSK_MN2IDX];
965    dskdsc->co2max = fDSKDescr[SPICE_DSK_MX2IDX];
966    dskdsc->co3min = fDSKDescr[SPICE_DSK_MN3IDX];
967    dskdsc->co3max = fDSKDescr[SPICE_DSK_MX3IDX];
968    dskdsc->start  = fDSKDescr[SPICE_DSK_BTMIDX];
969    dskdsc->stop   = fDSKDescr[SPICE_DSK_ETMIDX];
970 
971    /*
972    Cast the logical found flag to the output type.
973    */
974 
975    *found = (SpiceBoolean) foundFlag;
976 
977 
978    chkout_c ( "dskxsi_c" );
979 
980 } /* End dskxsi_c */
981