1 /*
2 
3 -Procedure llgrid_pl02 ( Lon/lat grid using DSK type 2 plate model )
4 
5 -Abstract
6 
7    Deprecated: This routine has been superseded by the CSPICE routine
8    latsrf_c. This routine is supported for purposes of backward
9    compatibility only.
10 
11    Given the planetocentric longitude and latitude values of a set of
12    surface points on a specified target body, compute the corresponding
13    rectangular coordinates of those points.  The target body's
14    surface is represented by a triangular plate model contained in a
15    type 2 DSK segment.
16 
17 -Disclaimer
18 
19    THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE
20    CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S.
21    GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE
22    ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE
23    PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS"
24    TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY
25    WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A
26    PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC
27    SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE
28    SOFTWARE AND RELATED MATERIALS, HOWEVER USED.
29 
30    IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA
31    BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT
32    LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND,
33    INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS,
34    REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE
35    REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY.
36 
37    RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF
38    THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY
39    CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE
40    ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE.
41 
42 -Required_Reading
43 
44    FRAMES
45    PCK
46    SPK
47    TIME
48 
49 -Keywords
50 
51    GEOMETRY
52 
53 */
54 
55    #include "SpiceUsr.h"
56    #include "SpiceZfc.h"
57    #include "SpiceZmc.h"
58 
59 
llgrid_pl02(SpiceInt handle,ConstSpiceDLADescr * dladsc,SpiceInt npoints,ConstSpiceDouble grid[][2],SpiceDouble spoints[][3],SpiceInt plateIDs[])60    void llgrid_pl02 ( SpiceInt               handle,
61                       ConstSpiceDLADescr   * dladsc,
62                       SpiceInt               npoints,
63                       ConstSpiceDouble       grid     [][2],
64                       SpiceDouble            spoints  [][3],
65                       SpiceInt               plateIDs []     )
66 /*
67 
68 -Brief_I/O
69 
70    Variable  I/O  Description
71    --------  ---  --------------------------------------------------
72    handle     I   DSK handle.
73    dlasdc     I   DLA descriptor of target body segment.
74    npoints    I   Number of grid coordinate pairs.
75    grid       I   Lon/lat values of surface points (radians).
76    spoints    O   Rectangular coordinates of surface points.
77    plateIDs   O   DSK plate IDs of surface points.
78 
79 -Detailed_Input
80 
81    handle      is the DAS file handle of a DSK file open for read
82                access.  This kernel must contain a type 2 segment
83                that provides a plate model representing the entire
84                surface of the target body.
85 
86    dladsc      is the DLA descriptor of a DSK segment representing
87                the surface of a target body.
88 
89    npoints     is the number of longitude/latitude pairs in the array
90                of grid points `grid'.
91 
92    grid        is an array of planetocentric longitude/latitude pairs
93                to be mapped to surface points on the target body.
94                `grid' should be declared by the caller
95 
96                    SpiceDouble grid [npoints][2];
97 
98                Elements
99 
100                   grid[i][0]
101                   grid[i][1]
102 
103                are, respectively, the planetocentric longitude and
104                latitude of the ith grid point.
105 
106                Units are radians.
107 
108 -Detailed_Output
109 
110    spoints     is an array containing the rectangular (Cartesian)
111                coordinates of the surface points on the target body,
112                expressed relative to the body-fixed reference frame of
113                the target body, corresponding to the input grid points.
114 
115                `spoints' should be declared by the caller
116 
117                    SpiceDouble spoints [npoints][3];
118 
119 
120    plateIDs    is an array of integer ID codes of the plates on which
121                the surface points are located.  The ith plate ID
122                corresponds to the ith surface point. These ID codes can
123                be use to look up data associated with the plate, such
124                as the plate's vertices or outward normal vector.
125 
126                `plateIDs' should be declared by the caller
127 
128                   SpiceInt plateIDs [npoints];
129 
130 -Parameters
131 
132    None.
133 
134 -Exceptions
135 
136    If any of the listed errors occur, the output arguments are
137    left unchanged.
138 
139 
140    1) If a DSK providing a DSK type 2 plate model has not been
141       loaded prior to calling llgrid_pl02, the error will be
142       diagnosed and signaled by a routine in the call tree of this
143       routine.
144 
145    2) If the segment associated with the input DLA descriptor is not
146       of data type 2, the error SPICE(WRONGDATATYPE) is signaled.
147 
148    3) If a surface point cannot be computed because the ray corresponding
149       to a longitude/latitude pair fails to intersect the target
150       surface as defined by the plate model, the error
151       SPICE(NOINTERCEPT) is signaled.
152 
153 
154 -Files
155 
156    The following data are required:
157 
158       - DSK data:  a DSK file containing a plate model representing the
159         target body's surface must be loaded. This kernel must contain
160         a type 2 segment that contains data for the entire surface of
161         the target body.
162 
163    In all cases, kernel data are normally loaded once per program
164    run, NOT every time this routine is called.
165 
166 -Particulars
167 
168    See the headers of the CSPICE routines
169 
170       reclat_c
171       latrec_c
172 
173    for detailed definitions of Planetocentric coordinates.
174 
175 -Examples
176 
177    The numerical results shown for this example may differ across
178    platforms. The results depend on the SPICE kernels used as input,
179    the compiler and supporting libraries, and the machine specific
180    arithmetic implementation.
181 
182    In the following example program, the file
183 
184       phobos.3.3.bds
185 
186    is a DSK file containing a type 2 segment that provides a plate model
187    representation of the surface of Phobos.
188 
189    Find the surface points on a target body corresponding to a given
190    planetocentric longitude/latitude grid.  In order to duplicate
191    the example output, the kernel name
192 
193       phobos.3.3.bds
194 
195    should be supplied at the prompt.
196 
197 
198       #include <stdio.h>
199       #include <math.h>
200       #include "SpiceUsr.h"
201 
202       int main()
203       {
204          /.
205          Local parameters
206          ./
207          #define  FILSIZ         256
208          #define  NAMLEN         33
209          #define  NLAT           9
210          #define  NLON           9
211          #define  MAXGRID        ( NLAT * NLON )
212          #define  TOL            ( 1.e-12 )
213 
214          /.
215          Local variables
216          ./
217          SpiceBoolean            found;
218 
219          SpiceChar               dsk      [ FILSIZ ];
220 
221          SpiceDLADescr           dladsc;
222 
223          SpiceDouble             grid     [ MAXGRID ][2];
224          SpiceDouble             lat;
225          SpiceDouble             lon;
226          SpiceDouble             spoints  [ MAXGRID ][3];
227          SpiceDouble             xlat;
228          SpiceDouble             xlon;
229          SpiceDouble             xr;
230 
231          SpiceInt                handle;
232          SpiceInt                i;
233          SpiceInt                j;
234          SpiceInt                n;
235          SpiceInt                npoints;
236          SpiceInt                plateIDs [ MAXGRID ];
237 
238 
239 
240          /.
241          Prompt for the name of the DSK to read and the name of
242          the target body.
243          ./
244          prompt_c ( "Enter DSK name    > ", FILSIZ, dsk    );
245 
246          /.
247          Open the DSK file for read access.
248          We use the DAS-level interface for
249          this function.
250          ./
251          dasopr_c ( dsk, &handle );
252 
253          /.
254          Begin a forward search through the
255          kernel, treating the file as a DLA.
256          In this example, it's a very short
257          search.
258          ./
259          dlabfs_c ( handle, &dladsc, &found );
260 
261          if ( !found  )
262          {
263             /.
264             We arrive here only if the kernel
265             contains no segments.  This is
266             unexpected, but we're prepared for it.
267             ./
268             setmsg_c ( "No segments found in DSK file #.");
269             errch_c  ( "#",  dsk                         );
270             sigerr_c ( "SPICE(NODATA)"                   );
271          }
272 
273          /.
274          If we made it this far, DLADSC is the
275          DLA descriptor of the first segment.
276 
277          Now generate the grid points.  We generate
278          points along latitude bands, working from
279          north to south.  The latitude range is selected
280          to range from +80 to -80 degrees.  Longitude
281          ranges from 0 to 350 degrees.  The increment
282          is 20 degrees for latitude and 40 degrees for
283          longitude.
284          ./
285 
286          n = 0;
287 
288          for ( i = 0;  i < NLAT;  i++  )
289          {
290             lat = rpd_c() * ( 80.0 - 20.0*i );
291 
292             for ( j = 0;  j < NLON;  j++  )
293             {
294                lon = rpd_c() * 40.0*j;
295 
296                grid[n][0] = lon;
297                grid[n][1] = lat;
298 
299                ++n;
300             }
301          }
302          npoints = n - 1;
303 
304          /.
305          Find the surface points corresponding to the grid points.
306          ./
307          llgrid_pl02 ( handle,
308                        &dladsc,
309                        npoints,
310                        (ConstSpiceDouble (*)[2])grid,
311                        spoints,
312                        plateIDs                        );
313 
314          /.
315          Print out the surface points in latitudinal
316          coordinates and compare the derived lon/lat values
317          to those of the input grid.
318          ./
319          for ( i = 0;  i < npoints;  i++  )
320          {
321             /.
322             Use recrad_c rather than reclat_c to produce
323             non-negative longitudes.
324             ./
325             recrad_c ( spoints[i], &xr, &xlon, &xlat );
326 
327             printf ( "\n"
328                      "Intercept for grid point %d:\n"
329                      "   Plate ID:                 %d\n"
330                      "   Cartesian Coordinates:    (%e %e %e)\n"
331                      "   Latitudinal Coordinates:\n"
332                      "   Longitude (deg): %f\n"
333                      "   Latitude  (deg): %f\n"
334                      "   Radius     (km): %f\n"
335                      "\n"
336                      "Original grid coordinates:\n"
337                      "   Longitude (deg): %f\n"
338                      "   Latitude  (deg): %f\n"
339                      "\n",
340                      (int)i,
341                      (int)plateIDs[i],
342                      spoints[i][0], spoints[i][1], spoints[i][2],
343                      xlon * dpr_c(),
344                      xlat * dpr_c(),
345                      xr,
346                      grid[i][0] * dpr_c(),
347                      grid[i][1] * dpr_c()                         );
348 
349             /.
350             Perform sanity checks on the intercept
351             coordinates.  Stop the program if any error
352             is larger than our tolerance value.
353             ./
354             lon = grid[i][0];
355             lat = grid[i][1];
356 
357             if ( fabs(xlat-lat) > TOL )
358             {
359                sigerr_c ( "Latitude error!" );
360             }
361 
362             if (  (xlon - lon)  > pi_c()  )
363             {
364                xlon -= twopi_c();
365             }
366 
367             if (  (xlon - lon)  > TOL  )
368             {
369                sigerr_c ( "Longitude error!" );
370             }
371 
372          }
373 
374          /.
375          Close the kernel.  This isn't necessary in a stand-
376          alone program, but it's good practice in subroutines
377          because it frees program and system resources.
378          ./
379          dascls_c ( handle );
380 
381          return ( 0 );
382       }
383 
384 
385    When this program was executed on a PC/Linux/gcc platform,
386    the output for the first 3 points (the rest of the output
387    is not shown due to its large volume) was:
388 
389 
390       Enter DSK name    > phobos.3.3.bds
391 
392       Intercept for grid point 0:
393          Plate ID:                 306238
394          Cartesian Coordinates:    (1.520878e+00 -7.129713e-16 8.625327e+00)
395          Latitudinal Coordinates:
396          Longitude (deg): 360.000000
397          Latitude  (deg): 80.000000
398          Radius     (km): 8.758387
399 
400       Original grid coordinates:
401          Longitude (deg): 0.000000
402          Latitude  (deg): 80.000000
403 
404 
405       Intercept for grid point 1:
406          Plate ID:                 317112
407          Cartesian Coordinates:    (1.189704e+00 9.982799e-01 8.807772e+00)
408          Latitudinal Coordinates:
409          Longitude (deg): 40.000000
410          Latitude  (deg): 80.000000
411          Radius     (km): 8.943646
412 
413       Original grid coordinates:
414          Longitude (deg): 40.000000
415          Latitude  (deg): 80.000000
416 
417 
418       Intercept for grid point 2:
419          Plate ID:                 324141
420          Cartesian Coordinates:    (2.777752e-01 1.575341e+00 9.072029e+00)
421          Latitudinal Coordinates:
422          Longitude (deg): 80.000000
423          Latitude  (deg): 80.000000
424          Radius     (km): 9.211980
425 
426       Original grid coordinates:
427          Longitude (deg): 80.000000
428          Latitude  (deg): 80.000000
429 
430 
431 
432 
433 -Restrictions
434 
435    1) This routine assumes that the origin of the body-fixed reference
436       frame associated with the target body is located in the interior
437       of that body.
438 
439    2) The results returned by this routine may not be meaningful
440       if the target surface has multiple surface points associated
441       with some (longitude, latitude) coordinates.
442 
443 -Literature_References
444 
445    None.
446 
447 -Author_and_Institution
448 
449    N.J. Bachman   (JPL)
450 
451 -Version
452 
453    -CSPICE Version 2.0.0, 23-JUL-2016 (NJB)
454 
455        Added failed_c calls.
456 
457        Include file references have been updated. Now calls
458        zzdsksgr_ instead of dsksgr_. Integer output format
459        in example program has been updated.
460 
461    -Beta Version 1.3.0, 30-APR-2014 (NJB) (BVS)
462 
463        Now includes dsk_proto.h.
464 
465        Last update was 1.2.1, 07-APR-2014 (BVS)
466 
467        Changed FRAME to FRAMES in the Required_Reading section.
468 
469    -Beta Version 1.2.0, 14-MAY-2010 (NJB)
470 
471        Updated for compatibility with new DSK design.
472        DSK name was updated in example program.
473 
474    -Beta Version 1.1.0, 09-FEB-2007 (NJB)
475 
476        Bug fix:  type of local variable fDLADescr was changed to SpiceInt.
477 
478    -Beta Version 1.0.0, 06-NOV-2006 (NJB)
479 
480 -Index_Entries
481 
482    map latitudinal grid to DSK type 2 plate model surface
483 
484 -&
485 */
486 
487 { /* Begin llgrid_pl02 */
488 
489 
490    /*
491    Prototypes
492    */
493 
494 
495    /*
496    Local parameters
497    */
498    #define CTRIDX          1
499    #define TYPIDX          3
500 
501    /*
502    Local variables
503    */
504    SpiceBoolean            found;
505 
506    SpiceDouble             fDSKDescr  [ SPICE_DSK_DSCSIZ ];
507    SpiceDouble             maxrad;
508    SpiceDouble             raydir     [3];
509    SpiceDouble             scale;
510    SpiceDouble             vertex     [3];
511 
512    SpiceInt                centerID;
513    SpiceInt                dataType;
514    SpiceInt                fDLADescr  [ SPICE_DLA_DSCSIZ ];
515    SpiceInt                i;
516 
517 
518    /*
519    Participate in error tracing.
520    */
521    if ( return_c()  )
522    {
523       return;
524    }
525    chkin_c ( "llgrid_pl02" );
526 
527    /*
528    Fetch and examine the DSK descriptor of the segment from which we're
529    getting the shape data.  Make sure this is a type 2 segment for the
530    specified target.  Since we don't know a priori that the segment
531    has type 2, we can't use the type 2 fetch routine for this operation.
532    Instead, we use the f2c'd version of the Fortran routine dskgd.
533    We must prepare a Fortran-style DLA descriptor in order to call
534    this routine.
535 
536    Populate the Fortran DLA descriptor array fCurrent with the contents
537    of the input descriptor.
538    */
539    fDLADescr[SPICE_DLA_BWDIDX] = dladsc->bwdptr;
540    fDLADescr[SPICE_DLA_FWDIDX] = dladsc->fwdptr;
541    fDLADescr[SPICE_DLA_IBSIDX] = dladsc->ibase;
542    fDLADescr[SPICE_DLA_ISZIDX] = dladsc->isize;
543    fDLADescr[SPICE_DLA_DBSIDX] = dladsc->dbase;
544    fDLADescr[SPICE_DLA_DSZIDX] = dladsc->dsize;
545    fDLADescr[SPICE_DLA_CBSIDX] = dladsc->cbase;
546    fDLADescr[SPICE_DLA_CSZIDX] = dladsc->csize;
547 
548    /*
549    Call the f2c'd "get DSK descriptor" routine.
550    */
551    dskgd_ ( ( integer    * ) &handle,
552             ( integer    * ) fDLADescr,
553             ( doublereal * ) fDSKDescr  );
554 
555    if ( failed_c() )
556    {
557       chkout_c ( "llgrid_pl02" );
558       return;
559    }
560 
561    /*
562    Extract object ID and DSK data type from the descriptor.
563    */
564    centerID = (SpiceInt)fDSKDescr[CTRIDX];
565    dataType = (SpiceInt)fDSKDescr[TYPIDX];
566 
567 
568    if ( dataType != 2 )
569    {
570       setmsg_c ( "Input segment has DSK data type #.  A segment of "
571                  "type 2 is required."                               );
572       errint_c ( "#", dataType                                       );
573       sigerr_c ( "SPICE(WRONGDATATYPE)"                              );
574       chkout_c ( "llgrid_pl02"                                       );
575       return;
576    }
577 
578    /*
579    We're done with error checks on our inputs.
580 
581    Get the maximum radius value associated with the target body.
582    We'll use this later to compute a numerically safe ray vertex.
583    */
584    maxrad = zzdsksgr_ ( fDSKDescr );
585 
586    if ( failed_c() )
587    {
588       chkout_c ( "llgrid_pl02" );
589       return;
590    }
591 
592    for ( i = 0;  i < npoints;  i++  )
593    {
594       /*
595       Find the outward unit vector corresponding to the ith lon/lat pair.
596       Note:  longitude comes first!
597       */
598       latrec_c ( 1.0, grid[i][0], grid[i][1], vertex );
599 
600       vminus_c ( vertex, raydir );
601 
602       /*
603       To avoid numerical problems, we pick a vertex that is guaranteed
604       to be a reasonable distance away from the target's surface.
605       */
606       scale = maxd_c ( 2,  1.0,  2.0*maxrad );
607 
608       vscl_c ( scale, vertex, vertex );
609 
610 
611       /*
612       Find the surface intercept defined by the vertex, ray direction,
613       and surface plate model.
614       */
615       dskx02_c ( handle,       dladsc,      vertex,  raydir,
616                  plateIDs+i,   spoints[i],  &found          );
617 
618       if ( failed_c() )
619       {
620          chkout_c ( "llgrid_pl02" );
621          return;
622       }
623 
624       if ( !found  )
625       {
626          setmsg_c ( "Ray from vertex number # having longitude # "
627                     "and latitude # (radians) to center "
628                     "of target # did not intersect the surface  "
629                     "defined by the input handle and descriptor."  );
630          errint_c ( "#", i                                         );
631          errdp_c  ( "#", grid[i][0]                                );
632          errdp_c  ( "#", grid[i][1]                                );
633          errint_c ( "#", centerID                                  );
634          sigerr_c ( "SPICE(NOINTERCEPT)"                           );
635          chkout_c ( "llgrid_pl02"                                  );
636          return;
637       }
638    }
639 
640 
641    /*
642    At this point, `spoints' and `plateIDs' are set.
643    */
644 
645    chkout_c ( "llgrid_pl02" );
646 
647 } /* End llgrid_pl02 */
648