1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
//! # DSK Required Reading
//!
//! Last revised on 2021 OCT 22 by N. J. Bachman.
//!
//!
//!
//!
//!
//! ## Abstract
//!
//! The Digital Shape Kernel (DSK) subsystem is the component of SPICE
//! concerned with detailed shape models for extended objects.
//!
//!
//!
//!
//!
//! ### Purpose
//!
//! This document is a reference guide for the SPICE DSK subsystem. Here
//! you'll find
//!
//!
//!
//! * A discussion of the DSK subsystem's software. This includes the API
//! (application programming interface) routines---these are the routines that
//! may be called directly by SPICE-based user application code---and the SPICE
//! utility programs that work with DSK files.
//!
//! * Discussions of DSK concepts
//!
//! * A description of the DSK file format
//!
//! * Discussion of problems that may arise when using the DSK subsystem
//!
//! The DSK subsystem does not deal with triaxial ellipsoid shape models;
//! these models are usually provided by PCK files. See the PCK Required
//! Reading, [pck.req](crate::required_reading::pck), for further information.
//!
//!
//!
//!
//!
//! ### Intended Audience
//!
//! This document addresses the needs of several groups of SPICE users.
//! Users looking for a basic discussion of the capabilities of the SPICE
//! DSK subsystem should read the introduction below. Users planning to
//! write application code using the DSK subsystem may benefit from reading
//! the entire document, possibly excepting the description of the details
//! of DSK type 2, but in any case should read the "DSK Concepts" chapter.
//! Users planning to create DSK files are encouraged to read the entire
//! document.
//!
//! This document assumes you already have a strong understanding of SPICE
//! concepts and terminology.
//!
//!
//!
//!
//!
//! ### References
//!
//! The references listed below provide essential background for programmers
//! intending to use the DSK subsystem. They also document DSK utility
//! programs.
//!
//!
//!
//! * 1. DAS Required Reading ([das.req](crate::required_reading::das))
//!
//! * 2. DLA Required Reading ([dla.req](crate::required_reading::dla))
//!
//! * 3. NAIF Integer ID Codes ([naif_ids.req](crate::required_reading::naif_ids))
//!
//! * 4. Frames Required Reading ([frames.req](crate::required_reading::frames))
//!
//! * 5. Convert User's Guide ([convert.ug](crate::raw::convert.ug))
//!
//! * 6. DSKBRIEF User's Guide
//!
//! * 7. MKDSK User's Guide
//!
//! * 8. DSKEXP User's Guide
//!
//! * 9. DLACAT User's Guide.
//!
//! * 10. BINGO User's Guide.
//!
//! * 11. SPICE Tutorials. Thes are available on the NAIF web site at
//!
//! ```text
//! https://naif.jpl.nasa.gov/naif/tutorials.html
//! ```
//! The programs
//!
//!
//!
//! ```text
//! DLACAT
//! BINGO
//! ```
//!
//! are utilities that are not part of the SPICE Toolkit, but that operate
//! on DSK files. They are available on the NAIF web site at
//!
//!
//!
//! ```text
//! https://naif.jpl.nasa.gov/naif/utilities.html
//! ```
//!
//!
//! ## Introduction
//!
//! The Digital Shape Kernel (DSK) subsystem is the component of SPICE
//! concerned with detailed shape models for extended objects. These objects
//! typically are solar system bodies such as planets, dwarf planets,
//! natural satellites, asteroids, and comet nuclei. DSK data can represent
//! the shapes of such objects, as well as local topography, such as that in
//! the vicinity of a rover or a tracking station.
//!
//! DSK data also can represent shapes of artificial objects such as
//! spacecraft components, or represent abstractions such as the subset of a
//! target body's surface that has a property of interest.
//!
//! The DSK subsystem comprises software, the DSK file format specification,
//! and documentation.
//!
//! The primary purpose of the DSK subsystem is to enable SPICE-based
//! applications to conveniently and efficiently use detailed shape data in
//! geometry computations performed by SPICE routines. DSK data enable these
//! routines to produce more accurate results than those obtainable using
//! triaxial ellipsoid shape models. See the section below titled
//! "High-Level DSK-Enabled Geometry Routines" for details.
//!
//! The DSK implementation ensures that shape data used by SPICE are
//! accompanied by all of the attribute information necessary for correct,
//! programmatic use of the data---including, but not limited to, reference
//! frames, central bodies, coordinate systems, spatial coverage bounds, and
//! time bounds of applicability. The DSK format enables data to be
//! augmented by indexes, or other pre-computed parameters, that greatly
//! enhance the speed of common geometric computations, such as those of
//! ray-surface intercepts.
//!
//! DSK data sets can be distributed across multiple DSK files; this is
//! normal for large data sets. Such sets of files can be "loaded" (made
//! available for read access by SPICE software) concurrently; SPICE
//! software will select data from the appropriate files as needed to
//! perform computations.
//!
//! The DSK file format facilitates storage, transmission, and archival of
//! shape data. It allows the data to be annotated with free-form
//! descriptive comments, also called "metadata."
//!
//! DSK documentation uses the term "data type" to refer to types of
//! mathematical shape representations, associated DSK file formats, and
//! software. The DSK subsystem is designed to accommodate multiple data
//! types, and to enable high-level SPICE geometry software to function
//! independently of these types.
//!
//! Currently there is only one DSK data type, which represents the shape of
//! an object by a set of triangular plates. This representation is called a
//! "tessellated plate model" or "triangular plate model." The DSK
//! documentation refers to this type as "DSK type 2."
//!
//! Support for digital elevation models (DEMs) will be added in a later
//! version of the SPICE Toolkit; one or more new DSK data types will be
//! developed to support such data.
//!
//! Because many popular file formats for shape data exist, and because it
//! is impractical for these formats to be used directly by SPICE for
//! geometric computations, the DSK subsystem supports conversion of a
//! variety of text-based shape data file formats to DSK format; it also
//! supports conversion of DSK files to a variety of text formats.
//!
//!
//!
//!
//!
//! # DSK Software
//!
//! Below we list the SPICE routines that either work directly with DSK
//! files or that support DSK usage. We also briefly describe the SPICE
//! utility programs that work with DSK files.
//!
//!
//!
//!
//!
//! ## High-Level DSK-Enabled Geometry Routines
//!
//! High-level SPICE geometry routines constitute the principal application
//! programming interface to the DSK subsystem. The routines described here
//! are supported in all language versions of the SPICE Toolkit.
//!
//! All of these routines perform computations that involve a target body.
//! All can model the shape of that body using data provided by DSK files.
//! Many of the routines can use triaxial ellipsoid models as well.
//!
//! These routines have extensive header documentation. Each header
//! describes all input and output arguments and includes one or more
//! example programs accompanied by example meta-kernels and corresponding
//! program outputs.
//!
//!
//!
//! * [DSKXSI](crate::raw::dskxsi)
//!
//!
//! Ray-surface intercept with source information: compute a ray-surface
//! intercept using data provided by multiple loaded DSK segments. Return
//! information about the source of the data defining the surface on which
//! the intercept was found: DSK handle, DLA and DSK descriptors, and DSK
//! data type-dependent parameters. \[Compare with [SINCPT](crate::raw::sincpt).]
//!
//! * [DSKXV](crate::raw::dskxv)
//!
//!
//! Vectorized ray-surface intercept: compute ray-surface intercepts for a
//! set of rays, using data provided by multiple loaded DSK segments.
//! \[Compare with [SINCPT](crate::raw::sincpt).]
//!
//! * [GFOCLT](crate::raw::gfoclt)
//!
//!
//! Occultation search: determine time intervals when an observer sees one
//! target occulted by, or in transit across, another.
//!
//! * [ILLUMF](crate::raw::illumf)
//!
//!
//! Illumination angles: compute the illumination angles---phase,
//! incidence, and emission---at a specified point on a target body. Return
//! logical flags indicating whether the surface point is visible from the
//! observer's position and whether the surface point is illuminated.
//!
//! * [LATSRF](crate::raw::latsrf)
//!
//!
//! Compute surface points specified by longitudes and latitudes: map an
//! array of planetocentric longitude/latitude coordinate pairs to surface
//! points on a specified target body.
//!
//! * [LIMBPT](crate::raw::limbpt)
//!
//!
//! Find limb points on a target body: the limb is the set of points of
//! tangency on the target of rays emanating from the observer. The caller
//! specifies half-planes bounded by the observer-target center vector in
//! which to search for limb points.
//!
//! * [OCCULT](crate::raw::occult)
//!
//!
//! Occultation state: determine the occultation condition (not occulted,
//! partially, etc.) of one target relative to another target as seen by an
//! observer at a given time.
//!
//! * [SINCPT](crate::raw::sincpt)
//!
//!
//! Ray-surface intercept: for a given observer, target, and ray direction,
//! find the nearest intersection to the observer of the ray and target
//! body's surface, optionally corrected for light time and stellar
//! aberration.
//!
//! * [SRFNRM](crate::raw::srfnrm)
//!
//!
//! Surface normal vectors: map an array of surface points on a specified
//! target body to the corresponding unit length outward surface normal
//! vectors.
//!
//! * [SUBPNT](crate::raw::subpnt)
//!
//!
//! Sub-observer point: compute the rectangular coordinates of the
//! sub-observer point on a target body at a specified epoch, optionally
//! corrected for light time and stellar aberration.
//!
//! * [SUBSLR](crate::raw::subslr)
//!
//!
//! Sub-solar point: compute the rectangular coordinates of the sub-solar
//! point on a target body at a specified epoch, optionally corrected for
//! light time and stellar aberration.
//!
//! * [TERMPT](crate::raw::termpt)
//!
//!
//! Find terminator points on a target body: the terminator is the set of
//! points of tangency on the target body of planes tangent to both this
//! body and to a light source. The caller specifies half-planes, bounded
//! by the illumination source center-target center vector, in which to
//! search for terminator points.
//!
//!
//! ## DSK File Loading and Unloading
//!
//! DSK files are loaded and unloaded by the same routines used for all
//! other SPICE kernels:
//!
//!
//!
//! * [FURNSH](crate::raw::furnsh)
//!
//!
//! Load a SPICE kernel. DSK files can be loaded directly by [FURNSH](crate::raw::furnsh); they
//! also can be referenced in a meta-kernel which can be loaded by [FURNSH](crate::raw::furnsh).
//! The latter method is usually preferable; see the "Intro to Kernels"
//! tutorial on the NAIF web site.
//!
//! * [UNLOAD](crate::raw::unload)
//!
//!
//! Unload a SPICE kernel. [UNLOAD](crate::raw::unload) can unload both DSK files and
//! meta-kernels.
//!
//! * [KCLEAR](crate::raw::kclear)
//!
//!
//! Unload all SPICE kernels and clear the kernel pool.
//!
//!
//! ## DSK Utility Routines
//!
//! DSK utility routines perform functions other than geometry computations.
//!
//! Routines for DSK file creation:
//!
//!
//!
//! * [DSKOPN](crate::raw::dskopn)
//!
//!
//! Open a new DSK file for subsequent write operations.
//!
//! * [DSKCLS](crate::raw::dskcls)
//!
//!
//! Close a DSK file.
//!
//! Also see the data type-specific segment writing routines below.
//!
//! Routine for fetching DSK segment attributes:
//!
//!
//!
//! * [DSKGD](crate::raw::dskgd)
//!
//!
//! Return the DSK descriptor from a DSK segment identified by a DAS handle
//! and DLA descriptor.
//!
//! Routines for determining objects covered by DSK files:
//!
//!
//!
//! * [DSKOBJ](crate::raw::dskobj)
//!
//!
//! Find the set of body ID codes of all objects for which data are
//! provided in a specified DSK file.
//!
//! * [DSKSRF](crate::raw::dsksrf)
//!
//!
//! Find the set of surface ID codes for all surfaces associated with a
//! given body in a specified DSK file.
//!
//! Routines for fetching and adjusting DSK tolerances:
//!
//!
//!
//! * [DSKGTL](crate::raw::dskgtl)
//!
//!
//! Retrieve the value of a specified DSK tolerance or margin parameter.
//!
//! * [DSKSTL](crate::raw::dskstl)
//!
//!
//! Set the value of a specified DSK tolerance or margin parameter.
//!
//!
//! ## DSK Type 2 Routines
//!
//! The DSK routines specific to data type 2 are:
//!
//!
//!
//! * [DSKB02](crate::raw::dskb02)
//!
//!
//! Return bookkeeping data from a DSK type 2 segment.
//!
//! * [DSKD02](crate::raw::dskd02)
//!
//!
//! Fetch double precision data from a DSK type 2 segment. To fetch vertex
//! data, see [DSKV02](crate::raw::dskv02).
//!
//! * [DSKI02](crate::raw::dski02)
//!
//!
//! Fetch integer data from a DSK type 2 segment. To fetch plate data, see
//! [DSKP02](crate::raw::dskp02). To fetch vertex and plate counts, see [DSKZ02](crate::raw::dskz02).
//!
//! * [DSKMI2](crate::raw::dskmi2)
//!
//!
//! Make a spatial index for a DSK type 2 segment.
//!
//! * [DSKN02](crate::raw::dskn02)
//!
//!
//! Compute the outward unit normal vector for a specified plate in a DSK
//! type 2 segment.
//!
//! * [DSKP02](crate::raw::dskp02)
//!
//!
//! Fetch triangular plates from a DSK type 2 segment.
//!
//! * [DSKRB2](crate::raw::dskrb2)
//!
//!
//! Determine range bounds for a set of triangular plates to be stored in a
//! DSK type 2 segment.
//!
//! * [DSKV02](crate::raw::dskv02)
//!
//!
//! Fetch vertices from a DSK type 2 segment.
//!
//! * [DSKW02](crate::raw::dskw02)
//!
//!
//! Write a DSK type 2 segment to a DSK file.
//!
//! * [DSKZ02](crate::raw::dskz02)
//!
//!
//! Return plate count and vertex count of a DSK type 2 segment.
//!
//!
//! ## DLA and DAS Routines
//!
//! DSK files are instances of DLA files, which in turn are instances of DAS
//! files. See the chapter "DSK Files" for further information.
//!
//! Some lower-level functionality is provided by routines of the DLA and
//! DAS subsystems. The routines below support linear traversal of the
//! doubly linked list---also called "searching" the list---of DSK
//! segments within a DSK file:
//!
//!
//!
//! * DASOPR
//!
//!
//! Open a DAS file for reading.
//!
//! * [DASCLS](crate::raw::dascls)
//!
//!
//! Close a DAS file.
//!
//! * [DLABFS](crate::raw::dlabfs)
//!
//!
//! Begin a forward segment search in a DLA file.
//!
//! * [DLAFNS](crate::raw::dlafns)
//!
//!
//! Find the segment following a specified segment in a DLA file.
//!
//! * [DLABBS](crate::raw::dlabbs)
//!
//!
//! Begin a backward segment search in a DLA file.
//!
//! * DASFPS
//!
//!
//! Find the segment preceding a specified segment in a DLA file.
//!
//!
//! ## Surface Name and ID Conversion Routines
//!
//! The routines below map surface names to surface IDs and vice versa.
//!
//!
//!
//! * [SRFC2S](crate::raw::srfc2s)
//!
//!
//! Translate a surface ID code, together with a body ID code, to the
//! corresponding surface name.
//!
//! * [SRFCSS](crate::raw::srfcss)
//!
//!
//! Translate a surface ID code, together with a body string, to the
//! corresponding surface name.
//!
//! * [SRFS2C](crate::raw::srfs2c)
//!
//!
//! Translate a surface string, together with a body string, to the
//! corresponding surface ID code.
//!
//! * [SRFSCC](crate::raw::srfscc)
//!
//!
//! Translate a surface string, together with a body ID code, to the
//! corresponding surface ID code.
//!
//!
//! ## SPICE Toolkit DSK Utility Programs
//!
//! The DSK utility programs included in the SPICE Toolkit are
//!
//!
//!
//! * DSKBRIEF
//!
//!
//! Display summaries of one or more DSK files. See the DSKBRIEF User's
//! Guide, [dskbrief.ug](crate::raw::dskbrief.ug).
//!
//! * MKDSK
//!
//!
//! Create a DSK file from shape data provided in a text file. See the
//! MKDSK User's Guide, [mkdsk.ug](crate::raw::mkdsk.ug).
//!
//! * DSKEXP
//!
//!
//! "Export" (write) DSK data to one or more text files. See the DSKEXP
//! User's Guide, [dskexp.ug](crate::raw::dskexp.ug).
//!
//! * COMMNT
//!
//!
//! Read, extract, append to, or delete the contents of a DSK file's
//! comment area. See the COMMNT User's Guide, [commnt.ug](crate::raw::commnt.ug).
//!
//! * TOBIN, TOXFR
//!
//!
//! Convert a transfer format DSK file to binary format, and vice versa.
//! See the user's guide "Converting and Porting SPICE Binary Data
//! Files," [convert.ug](crate::raw::convert.ug).
//!
//!
//! ## Non-SPICE Toolkit DSK Utility Programs
//!
//! The utility programs below are not part of the SPICE Toolkit, but are
//! available, as is their documentation, from the NAIF server.
//!
//!
//!
//! * BINGO
//!
//!
//! Convert a binary DSK file from IEEE little-endian format to IEEE
//! big-endian format, or vice versa.
//!
//! * DLACAT
//!
//!
//! Concatenate DLA files (DSK files are instances of DLA files) into a
//! single file.
//!
//!
//! # DSK Concepts
//!
//!
//!
//!
//!
//! ## Shapes and Surfaces
//!
//! The terms "shape data," "surface data," and "topography" are
//! generally used as synonyms in DSK documentation. The term "surface,"
//! when applied to DSK data, refers solely to the geometric form of the
//! surface---never to associated properties such as albedo or chemical
//! composition.
//!
//! The term "surfaces" is also used to refer to DSK data sets themselves,
//! particularly when there are multiple data sets, differing in some
//! aspects, that provide data for a given body. For example, Mars
//! topography data sets based on MGS MOLA data might be referred to as the
//! "64 pixels/degree surface" or the "128 pixels/degree surface."
//!
//!
//!
//!
//!
//! ## Surface IDs
//!
//! To facilitate run-time selection of DSK data, SPICE provides DSK
//! segments with a second identifying attribute in addition to the
//! "central body": the "surface ID code" (or "surface ID"). Different
//! DSK data sets for a given body may be assigned distinct surface IDs.
//!
//! At run time, calls from user applications to SPICE routines can restrict
//! the DSK data used to those from specified surfaces. For example, a user
//! application might direct the SPICE sub-observer point routine [SUBPNT](crate::raw::subpnt) to
//! to use a high-resolution surface for a spacecraft altitude computation,
//! versus a low-resolution surface for plotting the spacecraft's ground
//! track.
//!
//! Because surface IDs enable SPICE applications to select data from among
//! those available in loaded DSK files, it is not necessary for
//! applications to repeatedly load and unload DSK files to control which
//! shape data are used for a given body and computation. Applications
//! normally can load at start-up all of the DSK data for a given body, then
//! select the data to be used on a per-computation basis.
//!
//! Avoiding repetitive DSK loading tends to improve an application's
//! computation speed. This is because after any change to the set of loaded
//! DSK files, the DSK subsystem must perform some bookkeeping computations
//! before DSK-based computations can be performed. Degradation of overall
//! execution speed due to these computations is slight as long as they're
//! performed infrequently.
//!
//! SPICE surface IDs are associated with surface names; these associations
//! are made via assignments in SPICE text kernels. Surface name-ID
//! associations are made for specific bodies: the combination of a body
//! name or body ID and surface name can be mapped to a surface ID code, and
//! the combination of a body name or body ID and a surface ID code can be
//! mapped to a surface name.
//!
//! A given surface ID code can be re-used for different bodies without
//! ambiguity. For a given body, it's important for users to coordinate
//! assignment of surface names and surface IDs.
//!
//! For a given body, the surface name to surface ID mapping may be
//! many-to-one. If multiple surface names are associated with a surface ID
//! for a specified body, then the surface ID-to-name conversion routines
//! will map that surface ID to the last name associated with the ID. The
//! surface name-to-ID mapping routines will map any of the surface names to
//! that surface ID.
//!
//! The SPICE routines for converting between surface IDs and surface names
//! are listed in the section "Surface Name and ID Conversion Routines"
//! above.
//!
//!
//!
//!
//!
//! ### Defining Surface Name-ID Mappings
//!
//! Surface name-to-ID mappings may be defined at run time by loading text
//! kernels containing kernel variable assignments of the form
//!
//!
//!
//! ```text
//! NAIF_SURFACE_NAME += ( <surface name 1>, ... )
//! NAIF_SURFACE_CODE += ( <surface code 1>, ... )
//! NAIF_SURFACE_BODY += ( <body code 1>, ... )
//! ```
//!
//! Above, the Ith elements of the lists on the assignments' right hand
//! sides together define the Ith surface name/ID mapping.
//!
//! The same effect can be achieved using assignments formatted as follows:
//!
//!
//!
//! ```text
//! NAIF_SURFACE_NAME += <surface name 1>
//! NAIF_SURFACE_CODE += <surface code 1>
//! NAIF_SURFACE_BODY += <body code 1>
//!
//! NAIF_SURFACE_NAME += <surface name 2>
//! NAIF_SURFACE_CODE += <surface code 2>
//! NAIF_SURFACE_BODY += <body code 2>
//!
//! ...
//! ```
//!
//! Note the use of the
//!
//!
//!
//! ```text
//! +=
//! ```
//!
//! operator; this operator appends to rather than overwrites the kernel
//! variable named on the left hand side of the assignment.
//!
//! Multiple surface names, also called "surface aliases," can be mapped
//! to a surface ID for a given body as follows:
//!
//!
//!
//! ```text
//! NAIF_SURFACE_NAME += <surface name 1>
//! NAIF_SURFACE_CODE += <surface code 1>
//! NAIF_SURFACE_BODY += <body code 1>
//!
//! NAIF_SURFACE_NAME += <surface name 2>
//! NAIF_SURFACE_CODE += <surface code 1>
//! NAIF_SURFACE_BODY += <body code 1>
//! ```
//!
//! Using this mapping, body code 1 and either surface name will be mapped
//! by the surface name-to-ID conversion routines to surface code 1. Body
//! code 1 and surface code 1 will be mapped by the surface ID-to-name
//! routines to surface name 2.
//!
//!
//!
//!
//!
//! ## Segments
//!
//! Data in every DSK file are grouped into one or more subsets called
//! "segments." DSK segments are implemented as DLA segments, also called
//! "arrays." Each DSK segment has double precision and integer
//! components.
//!
//! Each DSK segment contains data for some or all of the surface of a
//! single body object. This object is called the "body," "central
//! body," or "center," even though it need not be a natural solar system
//! body.
//!
//! Within a segment, the data have the following attributes in common:
//!
//!
//!
//! * Body
//!
//! * Surface
//!
//! * Reference frame
//!
//! * Coordinate system
//!
//! * Coordinate system parameters, if applicable (for example, planetodetic
//! equatorial radius and flattening coefficient)
//!
//! * Spatial coverage bounds
//!
//! * Time bounds
//!
//! * Data type
//!
//! * Data class
//!
//! These attributes are discussed in the following sections.
//!
//! When DSK files are loaded via one or more calls to [FURNSH](crate::raw::furnsh), all segments
//! from those files become available to the DSK subsystem for use in
//! computations. At run time, when a request for shape data for a specified
//! body is made to the DSK subsystem, all segments for that body can be
//! considered as possible sources of data to satisfy the request.
//!
//! For small DSK data sets, such as low-resolution shape models for
//! asteroids, a single segment can suffice to store all of the data for the
//! model. Large DSK data sets typically consist of tens or hundreds of
//! segments distributed over multiple DSK files. Normally all segments for
//! a given body can be loaded at one time. The limit on the total number of
//! DSK segments for all bodies that can be loaded is given in Appendix B.
//!
//! DSK utilities typically create or operate on segments:
//!
//!
//!
//! * MKDSK creates a single-segment DSK file
//!
//! * DSKBRIEF displays summary information for groups of segments having common
//! attributes, or for individual segments
//!
//! * DSKEXP exports data from DSK segments to separate output files
//!
//!
//! ### DLA and DSK Descriptors
//!
//! Lower-level SPICE DSK routines refer to DSK segments by means of data
//! structures called DLA and DSK "descriptors."
//!
//! The DLA descriptor of a DSK segment indicates the location of the
//! segment's data in the DSK file containing that segment. DLA descriptors
//! contain DAS base addresses and sizes of the double precision and integer
//! components of the associated segments. DLA descriptors are integer
//! arrays.
//!
//! User applications can locate all segments in a DSK file by calling the
//! DLA "begin forward search" routine [DLABFS](crate::raw::dlabfs), then repeatedly calling the
//! DLA "find next segment" routine [DLAFNS](crate::raw::dlafns). See the API documentation of
//! those routines for details and code examples.
//!
//! The DSK descriptor of a DSK segment contains the segment's attribute
//! information; these are the attributes listed above. User applications
//! can determine attributes of a DSK segment by obtaining the DLA
//! descriptor of the segment, then calling the SPICE routine [DSKGD](crate::raw::dskgd) to
//! obtain the segment's DSK descriptor.
//!
//! See the chapter "DSK Files" for details.
//!
//!
//!
//!
//!
//! ### Reference Frames
//!
//! Each DSK segment has an associated reference frame. That frame is fixed
//! to the central body. The center of the frame need not be the central
//! body. For example, a segment containing data for Mars could use a
//! topocentric reference frame centered at a specified surface point on
//! Mars.
//!
//! Within a DSK segment, all shape data are expressed relative to that
//! segment's reference frame.
//!
//! For example, if a segment containing data for Phobos uses the IAU_PHOBOS
//! body-fixed frame, and if the segment contains vertices of triangular
//! plates, the coordinates of those vertices are expressed in the
//! IAU_PHOBOS reference frame.
//!
//! The set of DSK segments to be used in a computation for a given body
//! need not be associated with a single reference frame, but using data
//! from mixed frames should be done cautiously. It is up to the user to
//! combine data in ways that make sense.
//!
//! For example, Mars data expressed in the Mars-centered IAU_MARS frame can
//! be used together with Mars data expressed in one or more Mars
//! topocentric frames.
//!
//! On the other hand, it doesn't make sense to combine earth data expressed
//! in the ITRF93 frame with data expressed in the IAU_EARTH frame, because
//! those frames have some relative rotation. The same is true for data
//! expressed in the IAU_MOON and MOON_ME frames: even though these are
//! realizations of the same reference frame, the approximation error in the
//! IAU_MOON frame is time-dependent, so these frames have relative
//! rotation.
//!
//!
//!
//!
//!
//! ### Coordinate Systems and Spatial Coverage
//!
//! For the purpose of segment selection, the spatial coverage of a DSK
//! segment is considered to be three-dimensional: it is a region of space
//! within which the segment provides data for the associated body.
//!
//! The supported coordinate systems are:
//!
//!
//!
//! * Latitudinal (planetocentric)
//!
//! * Planetodetic
//!
//! * Rectangular
//!
//! Planetocentric coordinates are appropriate for most natural bodies.
//!
//! Planetodetic coordinates should be used only for large bodies having
//! surfaces well approximated by spheroids.
//!
//! Rectangular coordinates may be appropriate for data sets expressed in
//! topocentric reference frames, for artificial structures, and for
//! extremely irregular natural bodies.
//!
//! A segment's coordinate system is used to represent the segment's
//! coverage bounds.
//!
//! For example, a DSK segment that uses the Phobos planetocentric
//! coordinate system and IAU_PHOBOS reference frame might contain surface
//! data for Phobos within the spatial region
//!
//!
//!
//! ```text
//! Planetocentric latitude: -90 to +90 degrees
//! Planetocentric longitude: -180 to +180 degrees
//! Radius: 0 to 10 km
//! ```
//!
//! Here the planetocentric coordinate system's equatorial plane is the X-Y
//! plane of the IAU_PHOBOS frame. The prime meridian of the coordinate
//! system lies in the frame's X-Z plane and intersects the +X axis of the
//! frame.
//!
//! Another example: a DSK segment that uses a Mars planetodetic coordinate
//! system might contain surface data for Mars within the spatial region
//!
//!
//!
//! ```text
//! Planetodetic latitude: -30 to +30 degrees
//! Planetodetic longitude: +60 to +90 degrees
//! Altitude: -10 to +20 km
//! ```
//!
//! Here the planetodetic coordinate system's equatorial plane is the X-Y
//! plane of the segment's reference frame, for example the IAU_MARS frame.
//! The prime meridian of the coordinate system lies in the frame's X-Z
//! plane and intersects the +X axis of the frame. The altitude is measured
//! relative to a reference spheroid, the size and shape parameters of which
//! are contained in the segment.
//!
//! A third example: a DSK segment that contains data for a horizon mask for
//! a tracking station might use rectangular coordinates and a topocentric
//! frame having axis directions
//!
//!
//!
//! ```text
//! X: north
//! Y: west
//! Z: up
//! ```
//!
//! The region covered by the segment might be
//!
//!
//!
//! ```text
//! X: -0.5 to +0.5 km
//! Y: -0.5 to +0.5 km
//! Z: -0.2 to +0.2 km
//! ```
//!
//! In this case the horizon mask need not model the topography surrounding
//! the station; it can simply model obscuration due to the topography. So
//! the coverage region need not extend to the horizon; it can be contained
//! in a small box enclosing the station.
//!
//!
//!
//!
//!
//! ### Spatial coverage: Dimensions
//!
//! The coverage bounds of a segment enable the DSK subsystem to rapidly
//! determine whether the segment may be applicable for a given geometric
//! computation such as a ray-surface intercept. For this purpose, it is
//! convenient to consider the coverage of a segment to be
//! three-dimensional.
//!
//! For many applications, it is more natural to consider the spatial
//! coverage of a segment to be two-dimensional. This is true when the
//! surface represented by the segment can be expressed as a function that
//! maps a two-dimensional region to radius or height values. For example,
//! surface height relative to a reference spheroid can be a function of
//! planetodetic longitude and latitude. In a topocentric frame, the Z
//! coordinate of a surface can be a function of the X and Y coordinates.
//!
//! In cases where a surface is viewed as a function of two coordinates,
//! those coordinates are called the "domain coordinates." In some DSK
//! documentation, the terms "horizontal" or "tangential" coordinates
//! may be used as synonyms.
//!
//! The DSKBRIEF summary utility displays spatial coverage in three
//! dimensions for individual segments. It treats spatial coverage as
//! two-dimensional for the purpose of displaying combined coverage of
//! multiple segments, and for displaying gaps within that combined
//! coverage. For such displays, coverage and gaps will be displayed as
//! longitude-latitude rectangles in the planetocentric or planetodetic
//! systems, or as X-Y rectangles in the rectangular system.
//!
//!
//!
//!
//!
//! ### Spatial coverage: Gaps and Padding
//!
//! In general, the spatial bounds of a DSK segment don't imply that there
//! is complete coverage of the domain coordinates within those bounds;
//! spatial coverage can have gaps. In some cases this is an inevitable
//! consequence of the shape of the body: for example, if the coordinate
//! system is rectangular and the body is a torus lying on the X-Y plane,
//! there will be no data for some (X,Y) coordinates.
//!
//! Spatial coverage gaps also can occur due to the way data are grouped in
//! segments by a DSK file's creator. Normally DSK file creators should
//! ensure that segments don't have coverage gaps that users would not
//! expect. Coverage gaps can cause geometric computations to fail at run
//! time.
//!
//! The concept of spatial coverage gaps normally applies to a segment's
//! domain coordinates, such as longitude and latitude. It is also possible
//! for a surface's maximum or minimum height, radius, or Z coordinate to
//! be, respectively, strictly less than or strictly greater than the
//! corresponding upper or lower bound. The term "gap" usually does not
//! apply to such differences; these differences usually have no impact on
//! computations.
//!
//! Data for a segment need not be confined to the spatial region delimited
//! by the spatial bounds. DSK creators can include in DSK segments
//! "padding" data that extend slightly beyond the segments' spatial
//! bounds. Padding data can ensure that coverage implied by a segment's
//! domain coordinate bounds is really present.
//!
//!
//!
//!
//!
//! ### Time Bounds
//!
//! Segments in a DSK file provide data for a time interval determined by
//! the DSK file's creator.
//!
//! For a surface having a shape that evolves over a time span of interest,
//! multiple versions of the surface corresponding to different time
//! intervals can be created. When a computation is performed for a
//! particular time, only segments providing data for time intervals that
//! include that time will be considered.
//!
//! In many cases the surface represented by a DSK segment is considered to
//! be constant with respect to time, so the start and stop time bounds may
//! be set, respectively, to values far in the past and future (for example,
//! plus or minus one century) relative to the time range for which the
//! segment is expected to be used.
//!
//!
//!
//!
//!
//! ### Data Types
//!
//! The DSK subsystem supports multiple forms of mathematical
//! representations of shape data. For each such form, there is a
//! corresponding DSK segment type and set of routines that can access
//! segments of that type. Collectively the form of representation, the
//! segment structure and associated software are called a "DSK data
//! type."
//!
//! DSK data type 2 represents body shapes using collections of triangular
//! plates. Another DSK data type, not yet implemented, will represent
//! surfaces as digital elevation models (DEMs).
//!
//! The SPICE system's high-level geometry routines operate without
//! reference to the data types of DSK segments providing shape data to
//! these routines. These routines require lower-level, type-dependent
//! routines to provide functionality that is common across all DSK data
//! types, such as "find the intercept of a ray with the surface defined by
//! a segment," or "return the unit length outward normal vector at a
//! specified point on the surface defined by a segment."
//!
//! Some SPICE routines perform functions specific to particular data types.
//! For example, the routines [DSKV02](crate::raw::dskv02) and [DSKP02](crate::raw::dskp02) return, respectively,
//! vertices and plates from a type 2 segment.
//!
//!
//!
//!
//!
//! ### Data Classes
//!
//! The "data class" of a segment indicates aspects of the topology of the
//! shape defined by that segment. There are currently two data classes:
//!
//!
//!
//! * Class 1: single-valued surface. The surface is a single-valued function of
//! the segment's domain coordinates.
//!
//! * Class 2: arbitrary surface. Any surface for which there are multiple points
//! for a given longitude and latitude, or for a given X and Y, belongs to
//! class 2.
//!
//! * Surfaces that have features such as overhanging cliffs, arches, or caves
//! belong to class 2.
//!
//! * Any DSK type 2 surface having an "inward-facing" plate---one for which
//! the outward normal vector has negative dot product with any of the plate's
//! vertices---is a class 2 surface.
//!
//! * The nucleus of the comet Churyumov-Gerasimenko is an example of a class 2
//! shape.
//!
//!
//! ## Data Competition and Priority
//!
//! Two segments containing data for the same body, surface, location, and
//! time are said to contain "competing" data. Segment priority is a
//! scheme for determining which segment's data to use in case of
//! competition.
//!
//! Unlike the other SPICE binary kernel systems, the DSK subsystem does not
//! necessarily make use of segment priority for a given computation.
//! Instead, a user application can specify that a computation is
//! "unprioritized." This means that all loaded data for the given body
//! and a specified list of surfaces are to be used together to represent
//! the shape to be used in the computation.
//!
//! When DSK data for different surfaces for one body are loaded
//! concurrently, surface lists, which are inputs to SPICE API routines that
//! use DSK data, can be used to ensure that the correct set of DSK data are
//! used for a given computation, and that none of the data compete. It is
//! not necessary to load or unload DSK files to give the desired data top
//! priority.
//!
//! See the API documentation for any high-level SPICE geometry routine, for
//! example [SINCPT](crate::raw::sincpt), for a discussion of surface lists.
//!
//! In the N0066 SPICE Toolkit, all high-level geometry routines that work
//! with DSK data support only unprioritized computations.
//!
//! Although not currently used, the DSK subsystem does have a priority
//! scheme: as in the SPICE SPK, CK, and binary PCK subsystems, when two
//! segments from the same file compete, the one located later in the file
//! (at higher addresses) takes precedence. When two segments from different
//! files compete, the one from the file loaded later takes precedence.
//!
//!
//!
//!
//!
//! ## Greedy Algorithms
//!
//! A numerical problem affecting DSK computations is the possibility of
//! "false negatives": finding no result when one should be expected. An
//! example of this is not finding a ray-surface intercept when one clearly
//! should exist.
//!
//! The possibility of false negatives, at a minimum, complicates the design
//! of user applications that depend on DSK data.
//!
//! Aside from errors in DSK files themselves, the main cause of false
//! negative results is round-off error.
//!
//! Round-off error can cause a ray that should hit the common edge between
//! two plates to be determined, according to double precision arithmetic,
//! to miss both plates. Similarly, round-off error can cause a ray that
//! should hit the common longitude boundary or latitude boundary shared by
//! two DSK segments to hit neither segment boundary.
//!
//! The DSK subsystem uses several techniques to avoid false negative
//! results for ray-surface intercepts. These fall into the category of
//! "greedy algorithms": they effectively treat segments and data as
//! though they occupy not only the spatial regions implied by their
//! boundaries, but the surrounding regions as well. (An examination of the
//! default DSK "greedy" parameters will reveal that the greediness of DSK
//! algorithms is a mild case. See "Access to DSK Tolerances and Margin
//! Values" below.)
//!
//! For example, when a ray-surface intercept computation is attempted, an
//! intercept is considered to exist if the ray passes sufficiently close to
//! the target---not only if it hits.
//!
//!
//!
//!
//!
//! ### Greedy Ray-Segment Boundary Intercepts
//!
//! In the discussion below, we refer to both "segment boundaries" and
//! "tangent surfaces." Both terms require definition:
//!
//!
//!
//! * Segment boundary
//!
//!
//! This is the set of surfaces forming the boundary of the spatial region
//! defined by the coordinate bounds in a segment's DSK descriptor. There
//! are six such surfaces: for each one, one coordinate is at the segment's
//! minimum or maximum value for that coordinate, and the other coordinates
//! vary from their minimum to their maximum.
//!
//! * For example, a segment using planetocentric latitudinal coordinates
//! might have the longitude range 0:30 degrees, latitude range 0:45
//! degrees, and radius range 6300:6400 km. Then the segment's boundary on
//! the sphere of radius 6400 km has longitude ranging from 0 to 30
//! degrees, and latitude ranging from 0 to 45 degrees.
//!
//! * Tangent surface
//!
//!
//! This a "level surface" in geometric terms: a surface defined by
//! setting one coordinate to a segment's minimum or maximum bound for that
//! coordinate. For the segment above, the sphere of radius 6400 km is one
//! such tangent surface. As in this example, the tangent surfaces may
//! include areas that are not part of the segment's boundary.
//!
//! One step in the ray-surface intercept computation is determination of
//! the set of applicable segments that are hit by the ray. The segments
//! that have the appropriate attributes are tested to see whether the ray
//! hits the tangent surfaces defined by the coordinate ranges in the
//! segments' DSK descriptors.
//!
//! By default, when the ray's intersection with a segment's tangent surface
//! is computed, if that intersection is close to the spatial region
//! indicated by the segment's boundaries, an intersection with the segment
//! is considered to exist. In the example we're using, a ray's intersection
//! with the sphere of radius 6400 km that has longitude slightly greater
//! than 30 degrees and latitude slightly greater than 45 degrees could be
//! considered an intersection with the segment's boundary, if the longitude
//! and latitude excursions are within margins.
//!
//! The goal is to ensure that any segment that the ray might hit is
//! considered for a more detailed intercept computation.
//!
//!
//!
//!
//!
//! ### DSK Type 2 Plate Expansion
//!
//! By default, to eliminate the problem of false negatives from ray-surface
//! intercept computations, where the surface is defined by the data in a
//! selected type 2 segment, the DSK type 2 ray-surface intercept
//! computation expands plates slightly before attempting to compute the
//! ray's intersection with them. The expansion is done by scaling up, by a
//! factor slightly greater than 1, each of a plate's centroid-vertex
//! vectors. The expanded plate lies in the plane of the original plate, its
//! edges are parallel to those of the original plate, and its centroid
//! coincides with that of the original plate.
//!
//! The default plate expansion fraction is 1e-10. The expansion factor is
//!
//!
//!
//! ```text
//! 1 + expansion_fraction
//! ```
//!
//!
//! ### Additional Greedy Algorithms
//!
//! Greedy algorithms are also used for
//!
//!
//!
//! * Determining whether a ray-plate intercept, once found, is close enough to a
//! segment's boundary to be considered inside the segment
//!
//! * Determining whether a point is close enough to a plate to be considered to
//! belong to that plate
//!
//!
//! ### DSK Tolerances
//!
//! Some DSK tolerance parameters do not strictly support "greedy"
//! behavior, but rather enhances the DSK software's usability. For example,
//! there is a DSK parameter that is used to decide whether a longitude
//! value is close enough to a segment's longitude range to be considered to
//! lie within that range. Another tolerance parameter is used to decide
//! whether angular values are valid. For example, a latitude that exceeds
//! pi/2 radians by a positive number less than this tolerance is treated as
//! though it were exactly pi/2.
//!
//!
//!
//!
//!
//! ### Drawbacks
//!
//! A possible negative consequence of greedy algorithms is that some
//! results derived using them may be quite different from those derived
//! without them.
//!
//! For example, if a ray hits the edge of an expanded plate, and that plate
//! has a maximum edge length of 1 km, then the ray might have missed the
//! original plate by as much as 0.1 millimeters. After missing the original
//! plate, the ray might hit the surface far from that plate, or it might
//! miss the target altogether.
//!
//! This issue, while it may appear serious, is a normal consequence of
//! using finite precision arithmetic. A comparable difference in results
//! might be observed were the computation without plate expansion performed
//! on two different computer systems.
//!
//!
//!
//!
//!
//! ### Access to DSK Tolerances and Margin Values
//!
//! The greedy algorithms described above rely on tolerance parameters.
//! These and other DSK tolerance and margin parameters are assigned default
//! values in the include file dsktol.inc.
//!
//! The parameters used for greedy algorithms are user-adjustable.
//! Applications can call the routines [DSKGTL](crate::raw::dskgtl) or [DSKSTL](crate::raw::dskstl) to fetch or reset
//! these parameters at run time.
//!
//! It is recommended that the parameters be reset only by expert users.
//!
//!
//!
//!
//!
//! # DSK Files
//!
//! The SPICE DSK file format is designed to support rapid access to large
//! data sets. It is designed to be portable, and to support inclusion of
//! documentation within DSK files.
//!
//! The DSK file format is based on two lower-level SPICE file formats: the
//! DSK format is a special case of the SPICE DLA format, which in turn is a
//! special case of SPICE DAS format.
//!
//!
//!
//!
//!
//! ## DAS Files
//!
//! Most DSK properties are inherited from the "Direct Access Segregated"
//! (DAS) specification. The properties visible to SPICE users are:
//!
//!
//!
//! * Binary file format: integers and double precision numbers are stored in
//! binary format for compactness and speed of read access.
//!
//! * Direct access: data from any part of the file can be read in constant time,
//! aside from latency of the storage medium.
//!
//! * Array abstraction: the data portion of a DAS file appears to user
//! application code as three arrays of contiguous data: one each of
//! characters, integers, and double precision numbers. User applications can,
//! for example, directly read the Nth double precision number from a DAS file.
//! Fortran I/O features such as record numbers, record lengths, and logical
//! units (or C emulations of these features) are hidden from the user
//! application's view.
//!
//! * Portability: DAS files can be transferred from IEEE big-endian to IEEE
//! little-endian platforms, and vice-versa, requiring no modification to be
//! readable on the target platform.
//!
//! * DAS files can be transferred to ANY platform on which SPICE is supported;
//! this is done by first converting the files to an ASCII "transfer" format
//! on the source platform, moving the files, then converting the transfer
//! format files to binary files on the target platform.
//!
//! * Platform-independent buffering: DAS software buffers data read from DAS
//! files using a built-in mechanism that's independent of any buffering
//! mechanism provided by the host platform.
//!
//! * Comment area: DAS files contain a data structure called the "comment
//! area"; this area can contain an arbitrary quantity of free-form, ASCII
//! text. The comment area enables DAS file creators to include explanatory
//! documentation in the files.
//!
//! * The SPICE Toolkit contains API routines to access the comment area. Also,
//! the Toolkit contains a utility program, COMMNT, that can read, delete, or
//! append to comments in the comment area.
//!
//! See the DAS Required Reading [das.req](crate::required_reading::das) for details concerning the DAS
//! subsystem and DAS file format.
//!
//!
//!
//!
//!
//! ## DLA Files
//!
//! The DLA file format organizes data into a doubly linked list of virtual
//! segments. DLA routines enable application software to traverse such
//! segment lists. Since the DSK file format is an instance of the DLA
//! format, this traversal capability is inherited by the DSK subsystem.
//!
//! DLA files indicate the DAS addresses and sizes of their segments'
//! character, double precision, and integer components using data
//! structures called "DLA descriptors." The DLA segment descriptor
//! members are:
//!
//!
//!
//! ```text
//!
//! +---------------+
//! | BACKWARD PTR | Linked list backward pointer
//! +---------------+
//! | FORWARD PTR | Linked list forward pointer
//! +---------------+
//! | BASE INT ADDR | Base DAS integer address
//! +---------------+
//! | INT COMP SIZE | Size of integer segment component
//! +---------------+
//! | BASE DP ADDR | Base DAS d.p. address
//! +---------------+
//! | DP COMP SIZE | Size of d.p. segment component
//! +---------------+
//! | BASE CHR ADDR | Base DAS character address
//! +---------------+
//! | CHR COMP SIZE | Size of character segment component
//! +---------------+
//!
//! ```
//!
//! The "base address" of a segment component of a given data type is the
//! address, in the DAS address space of that type, preceding the first
//! element of that component. All DAS addresses are 1-based.
//!
//! DLA descriptors are used in the DSK subsystem to identify locations of
//! the components of DSK segments within DSK files.
//!
//! See the DLA Required Reading, [dla.req](crate::required_reading::dla), for details concerning the DLA
//! subsystem and file format.
//!
//!
//!
//!
//!
//! ## DSK File Format
//!
//! For the majority of practical DSK applications, the DSK file format can
//! be adequately understood using the following simplified model:
//!
//!
//!
//! ```text
//! +----------------------------------+
//! | File Record |
//! +----------------------------------+
//! | Comment Area |
//! +----------------------------------+
//! | Segment 1 |
//! +----------------------------------+ -+
//! | ... | |
//! +----------------------------------+ | Optional
//! | Segment N | |
//! +----------------------------------+ -+
//! ```
//!
//! That is, a DSK file contains some identification and bookkeeping
//! information called a "file record," it has a comment area, and it has
//! one or more DSK segments containing shape data.
//!
//! The segments are connected to each other as a doubly linked list, and
//! the list can be traversed in forward or backward order. (In the N0066
//! Mice and Icy Toolkits, only forward traversal is supported.)
//!
//! Each DSK segment has integer and double precision components. These
//! components occupy, respectively, contiguous ranges of DAS integer and
//! double precision addresses:
//!
//!
//!
//! ```text
//! +----------------------------------+
//! | Segment I | =
//! +----------------------------------+
//!
//! +--------------+ +------------------+
//! | | | |
//! | Segment I: | | Segment I: |
//! | | | |
//! | Integer | + | Double |
//! | Component | | Precision |
//! | (optional) | | Component |
//! | | | |
//! +--------------+ | |
//! | |
//! +------------------+
//! ```
//!
//! The double precision component of a segment can be further expanded as:
//!
//!
//!
//! ```text
//! +------------------+
//! | |
//! | Segment I: |
//! | |
//! | Double |
//! | Precision | =
//! | Component |
//! | |
//! | |
//! +------------------+
//!
//! +--------------+ +------------------+
//! | Segment I: | | Segment I: |
//! | | | |
//! | DSK Segment | + | Double |
//! | Descriptor | | Precision |
//! +--------------+ | Data |
//! | (optional) |
//! | |
//! | + Bookkeeping |
//! | Information |
//! | (optional) |
//! | |
//! +------------------+
//! ```
//!
//! The base addresses and sizes of a DSK segment's integer and double
//! precision components are given by the segment's DLA descriptor. The DAS
//! integer address range of a DSK segment is
//!
//!
//!
//! ```text
//! integer base address+1 : integer base address+
//! integer component size
//! ```
//!
//! Similarly, the DAS double precision address range of a DSK segment is
//!
//!
//!
//! ```text
//! d.p. base address+1 : d.p. base address+
//! d.p. component size
//! ```
//!
//! Low-level details of the general DSK file format, if not discussed in
//! this document, can be obtained from the DAS Required Reading, [das.req](crate::required_reading::das),
//! and from the DLA Required Reading, [dla.req](crate::required_reading::dla).
//!
//! An abstract view of a DSK segment---a view that ignores physical file
//! layout and numeric data types---is
//!
//!
//!
//! ```text
//!
//! DSK segment =
//!
//! +-------------------------------------+
//! | DSK Descriptor |
//! +-------------------------------------+
//! | Type-specific shape data |
//! +-------------------------------------+
//! | Type-specific ancillary information |
//! +-------------------------------------+
//!
//! ```
//!
//! DSK segments of all data types contain DSK descriptors.
//!
//! Further details of the DSK segment's structure are data type-dependent.
//! Currently there is just one DSK data type: type 2. It is discussed
//! below.
//!
//!
//!
//!
//!
//! # DSK Type 2: Triangular Plate Model
//!
//! The following discussion of shape data may be of interest to any DSK
//! users. The discussion of type 2 ancillary information is quite detailed
//! and likely is not of interest to most DSK users. It may be useful for
//! DSK creators, especially those interested in optimizing performance.
//!
//!
//!
//!
//!
//! ## Type 2 Shape Data
//!
//! DSK type 2 represents shapes of objects as collections of triangular
//! plates. This data type can model nearly any shape: the shape need not be
//! smooth, connected, or continuously deformable to sphere.
//!
//! Each triangular plate has three vertices: type 2 data consist of a set
//! of vertices and a set of "plates" to which the vertices belong.
//!
//!
//!
//!
//!
//! ### Vertices
//!
//! Vertices are vectors in three-dimensional space: each vertex is
//! represented by a double precision array consisting of the vertex's X, Y,
//! and Z components, in that order.
//!
//! The components of a vertex are expressed in the body-fixed reference
//! frame of the DSK segment to which the vertex belongs. Each vertex
//! represents an offset from the center of that reference frame.
//!
//! The center of a type 2 segment's reference frame need not coincide with
//! the body for which the segment provides data. For example, vertices for
//! a DSK segment representing Mars topography might be expressed in a Mars
//! topocentric frame; the vertices would then represent offsets from the
//! Mars surface point at the center of that frame.
//!
//! Within a type 2 segment, vertex components are always expressed in units
//! of km, regardless of the units associated with the input data from which
//! the segment was constructed.
//!
//! Each vertex has an associated integer ID; vertex IDs range from 1 to NV,
//! where NV is the number of vertices in the segment. This 1-based
//! numbering scheme is used for all language versions of SPICE, so the
//! vertex IDs in a DSK file match those used in SPICE DSK code on all
//! platforms.
//!
//!
//!
//!
//!
//! ### Plates
//!
//! The term "plate" refers to both a planar surface with a triangular
//! boundary in 3-dimensional space, and to a data structure.
//!
//! As a data structure, a plate is a 3-tuple of integer vertex IDs that
//! indicate which vertices belong to that plate.
//!
//! Each plate has an associated "outward normal" direction: this
//! direction is perpendicular to the plate. For surfaces that constitute
//! boundaries of solid objects---for example, a sphere---the outward normal
//! direction has the usual meaning: it points toward the exterior of the
//! object. For other surfaces, for example a single plate, the outward
//! normal direction may be an arbitrary choice.
//!
//! The order of a plate's vertices implies the outward normal direction: if
//! the vertices are
//!
//!
//!
//! ```text
//! V(1), V(2), V(3)
//! ```
//!
//! then the outward normal direction is
//!
//!
//!
//! ```text
//! ( V(2) - V(1) ) x ( V(3) - V(2) )
//! ```
//!
//! where "x" denotes the vector cross product operator.
//!
//! DSK creators must take vertex order into account when they define the
//! plates of a DSK type 2 segment.
//!
//! As the formula above shows, the outward normal direction is undefined if
//! two or three vertices of a plate coincide; in this case the "plate" is
//! actually a line segment or a point. Plates having these characteristics
//! are termed "degenerate." Even if all of a plate's vertices are
//! distinct, the normal direction vector suffers great loss of precision if
//! the angle between two plate edges is very close to zero.
//!
//! Degenerate and nearly degenerate plates are allowed in type 2 segments,
//! but it is strongly recommended that DSK creators exclude them from input
//! data sets. Such plates can cause run-time failures of user applications
//! performing functions that require outward normal directions to exist,
//! for example computing emission and solar incidence angles.
//!
//! Each plate has an associated integer ID; plate IDs range from 1 to NP,
//! where NP is the number of plates in the segment. This 1-based numbering
//! scheme is used for all language versions of SPICE, so the plate IDs in a
//! DSK file match those used in SPICE DSK code on all platforms.
//!
//!
//!
//!
//!
//! ## Type 2 Ancillary Information
//!
//! Much of the "added value" provided by DSK type 2 segments derives from
//! their spatial indexes: these enable rapid association between spatial
//! regions and plates, and between vertices and plates.
//!
//! A DSK type 2 spatial index consists of a "voxel-plate mapping" and
//! optionally, a "vertex-plate mapping," as well as various associated
//! parameters.
//!
//! All DSK type 2 segments contain a voxel-plate mapping. This mapping
//! enables DSK type 2 software to rapidly determine which plates are near a
//! specified ray or point.
//!
//!
//!
//!
//!
//! ## Pointers and Offsets
//!
//! In a DSK type 2 segment, integers that refer to locations of data or
//! ancillary information are called "pointers" or "offsets." In this
//! context "pointer" is not a Fortran data type (Fortran 77 does not have
//! a pointer type) but an indication of the role of the integer.
//!
//! In a DSK type 2 segment, pointers and offsets are expressed relative to
//! the DAS base addresses of that segment, or relative to the DAS addresses
//! of other members of the segment. This ensures that the segment is
//! "relocatable": it has no dependence on its absolute DAS addresses and
//! can be moved or copied without corrupting its contents.
//!
//!
//!
//!
//!
//! ## DSK Type 2 Segment Parameters
//!
//! The DSK type 2 parameters are constant values stored in both the integer
//! and double precision components of a DSK type 2 segment. These are
//! distinct from parameters belonging to the segment's DSK descriptor.
//!
//! A subset of these parameters refer to the segment's voxel grids. They
//! are listed here; they are explained later in context.
//!
//! The integer parameters are:
//!
//!
//!
//! * Vertex count
//!
//! * Plate count
//!
//! * Fine voxel count (redundant, used for convenience)
//!
//! * Fine voxel grid extents in the X, Y, and Z directions
//!
//! * Coarse voxel scale
//!
//! * Size of voxel-plate pointer array
//!
//! * Size of voxel-plate association array
//!
//! * Size of vertex-plate association array
//!
//! The double precision parameters are:
//!
//!
//!
//! * Fine voxel size (km)
//!
//! * Vertex bounds in the X, Y, and Z directions (km)
//!
//! * Voxel grid origin (3-vector, km)
//!
//!
//! ## Spatial Index: Voxel-Plate Mapping
//!
//! The voxel-plate mapping associates regions of space with plates that
//! intersect those regions.
//!
//! The voxel-plate mapping plays a critical role in DSK geometry
//! computations, because it enables plates relevant to computation to be
//! located quickly:
//!
//!
//!
//! * For ray-surface intercept computations, the voxel-plate mapping is used to
//! quickly find the plates that are close enough to the ray to be tested for
//! intersection.
//!
//! * For association of an individual point with a plate, the voxel-plate
//! mapping is used to quickly find plates that are close enough to the point
//! so that inclusion of the point by those plates should be tested.
//!
//! The voxel-plate mapping is implemented as a data structure comprising
//! four sub-structures and several associated parameters. The
//! sub-structures are
//!
//!
//!
//! * The fine voxel grid (aka the "fine grid")
//!
//! * The coarse voxel grid (aka the "coarse grid")
//!
//! * The voxel-plate pointer array
//!
//! * The voxel-plate association array
//!
//! The structures refer to each other as shown in the following diagram:
//!
//!
//!
//! ```text
//!
//! +---------------+
//! | |
//! | |
//! | |
//! | | +-------------+
//! | | | |
//! | | | |
//! | | | |
//! | | +-------------+ | |
//! | | | | | |
//! | | +--------+ | | | |
//! | | | | | | | |
//! | Fine | | Coarse | | Voxel-plate | | Voxel-plate |
//! | voxel |-->| voxel |-->| pointer |-->| association |
//! | grid | | grid | | array | | array |
//! | | | | | | | |
//! | | +--------+ | | | |
//! | | | | | |
//! | | +-------------+ | |
//! | | | |
//! | | | |
//! | | | |
//! | | +-------------+
//! | |
//! | |
//! | |
//! +---------------+
//!
//! ```
//!
//! The structures shown above enable DSK software to map a point in
//! 3-dimensional space to a set of nearby plates as follows:
//!
//!
//!
//! * 1. The fine voxel containing the point is identified. This is done by a
//! constant-time arithmetic calculation.
//!
//! * 2. The coarse voxel containing the fine voxel is identified. This is done by a
//! constant-time address calculation.
//!
//! * 3. The voxel-plate pointer corresponding to the fine voxel is identified. This
//! is done by a constant-time address calculation.
//!
//! * 4. The list of plates associated with the voxel is fetched. The time used by
//! this process is linear with respect to the count of the voxel's associated
//! plates.
//!
//! These structures are described in detail in the following sections.
//!
//!
//!
//!
//!
//! ### Fine Voxel Grid
//!
//! The fine voxel grid is an array, also called a "grid," of cubical
//! regions in 3-dimensional space. The cubical regions are called "fine
//! voxels" or simply "voxels" when the term is unambiguous. The overall
//! shape of the grid is that of a box (a 3-dimensional solid having six
//! rectangular sides).
//!
//! The sides of the grid are aligned with the coordinate axes of the DSK
//! segment's reference frame.
//!
//! A segment's fine voxel grid contains all vertices in the segment (and
//! therefore all plates); a small margin is used so that no plate contacts
//! the grid's boundary. Thus no point on or outside of the grid's boundary
//! can touch a plate.
//!
//! The fine voxel grid is fully characterized by
//!
//!
//!
//! * An origin. This is a 3-vector representing an offset from the reference
//! frame's center. The origin is always placed at the minimum X, Y, and Z
//! coordinates of the grid.
//!
//! * A voxel size. This is the common edge length of the cubes making up the
//! grid. Units are km. See the discussion of the "fine voxel scale" below.
//!
//! * X, Y, and Z grid extents. These are the counts of the grid's fine voxels in
//! the directions of the reference frame's coordinate axes.
//!
//! The fine voxel grid is not implemented by a physical array; there is no
//! storage cost associated with a large count of fine voxels. (There are
//! consequences other than storage cost if the fine voxel size is too
//! small: see the section below titled "Size of the Voxel-Plate
//! Association Array.")
//!
//! The diagram below shows the position of the fine voxel grid relative to
//! its origin, the orientation of the grid relative to the reference
//! frame's axes, and the relationship between the grid extents and the
//! dimensions of the fine voxel grid.
//!
//! In this diagram
//!
//!
//!
//! * VGREXT is a 3-dimensional integer array containing the X, Y, and Z grid
//! extents
//!
//! * VOXSIZ is the fine voxel edge length, in km
//!
//! * O represents the grid's origin
//!
//! ```text
//!
//!
//!
//! .------------. ^ fine voxel count =
//! / /| | VGREXT(3)
//! / / | |
//! / / | | length =
//! / / | | VGREXT(3) * VOXSIZ (km)
//! ^ +Z / / . . v
//! | . .------------. / /
//! | / | | / /
//! | /+Y | | / / fine voxel count = VRGEXT(2)
//! | / | | / /
//! |/ | |/ / length =
//! *-------> O------------* * VGREXT(2) * VOXSIZ (km)
//! +X
//! <------------>
//!
//! fine voxel count = VGREXT(1)
//! length = VGREXT(1) * VOXSIZ (km)
//!
//!
//!
//! ```
//!
//! ### Fine Voxel Scale
//!
//! The fine voxel scale is a parameter that relates the fine voxel size
//! (referred to above as VOXSIZ) to the average extent of the plates in a
//! DSK type 2 segment.
//!
//! A plate's "extent" in the direction of coordinate axis i is the
//! maximum value of coordinate i, taken over the plate's three vertices,
//! minus the minimum value of coordinate i, also taken over the plate's
//! three vertices. The average extent of a segment's plate set is the
//! average of all the the plates' extents in the X, Y, and Z directions.
//!
//! The fine voxel scale maps the plate set's extents to a voxel size by:
//!
//!
//!
//! ```text
//! VOXSIZ = file_voxel_scale * average_plate_extent
//! ```
//!
//!
//! ### Coarse Voxel Grid
//!
//! The coarse voxel grid is a data structure that represents the same
//! spatial region as the fine voxel grid. Unlike the fine grid, the coarse
//! grid is implemented by an array in the DSK segment. The term "coarse
//! voxel grid" may refer to either the spatial region or the data
//! structure, depending on context.
//!
//! The voxels of the coarse grid are cubes of identical size. The edge
//! length of the coarse voxels is an integer multiple of the fine voxels'
//! edge length. Let CGRSCL represent this multiple; then each coarse voxel
//! contains
//!
//!
//!
//! ```text
//! 3
//! CGRSCL
//! ```
//!
//! fine voxels.
//!
//! We use the term "parent" to refer to the unique coarse voxel that
//! contains a specified fine voxel.
//!
//! Each extent of the fine voxel grid is
//!
//!
//!
//! ```text
//! CGRSCL
//! ```
//!
//! times the corresponding extent of the coarse grid.
//!
//! The diagram below shows the relationship between the coarse voxel grid's
//! extents and edge lengths. The integer array VGREXT, as above, contains
//! the extents of the fine voxel grid. The parameter VOXSIZ contains the
//! fine voxels' edge length.
//!
//!
//!
//! ```text
//!
//!
//!
//! .------------. ^ coarse voxel count =
//! / /| | VGREXT(3) / CGRSCL
//! / / | |
//! / / | | length =
//! / / | | VGREXT(3) * VOXSIZ (km)
//! / / . . v
//! .------------. / /
//! | | / / coarse voxel count = VRGEXT(2)/CGRSCL
//! | | / /
//! | | / / length =
//! | |/ / VGREXT(2) * VOXSIZ (km)
//! *------------* *
//!
//! <------------>
//!
//! coarse voxel count = VGREXT(1) / CGRSCL
//! length = VGREXT(1) * VOXSIZ (km)
//!
//!
//!
//!
//! ```
//!
//! In the description below, the term "integer" refers to an element of
//! the DAS integer address space.
//!
//! The DSK integer array representing the coarse voxel grid has one element
//! for each coarse voxel. If any plates intersect the spatial region
//! corresponding to a coarse voxel, the corresponding coarse voxel grid
//! array element contains a pointer into the voxel-plate pointer array. If
//! no plates intersect that spatial region, the voxel contains the value
//! zero, which represents a null pointer. (Caution: for reasons of backward
//! compatibility, the values zero and -1 are used in different parts of DSK
//! type 2 segments indicate null pointers.)
//!
//! Note that during the construction of a spatial index, plate-voxel
//! "intersection" may be determined using a margin so that plates very
//! near a voxel are considered to intersect it. This is the case for DSK
//! type 2 segments created by [DSKW02](crate::raw::dskw02) and by MKDSK.
//!
//! A non-null pointer in a given coarse voxel is a 1-based index of a
//! pointer set within the voxel-plate pointer array. The pointer set
//! indicates the locations of plate lists associated with the fine voxels
//! having the coarse voxel as a parent.
//!
//! The maximum coarse voxel count within a segment, MAXCGR, is set to
//!
//!
//!
//! ```text
//! 100000
//! ```
//!
//! This value cannot be changed in any future version of SPICE.
//!
//! The value is small enough to make it practical for DSK type 2 software
//! to buffer the entire coarse voxel grid in memory.
//!
//! In all DSK type 2 segments, MAXCGR integers are allocated for the coarse
//! voxel grid, even if the grid is smaller.
//!
//!
//!
//!
//!
//! ### Purpose of the Coarse Voxel Grid
//!
//! Below, the term "empty" means "not intersected by any plates."
//!
//! The coarse voxel grid allows type 2 segments to avoid storing pointers
//! for all fine voxels, since only fine voxels belonging to non-empty
//! coarse voxels require pointers. Since in many practical cases, the
//! majority of coarse voxels are empty, this often greatly reduces the
//! required number of pointers.
//!
//! The coarse voxel grid also tends to reduce the number of physical file
//! reads necessary to determine the plate set relevant to a given
//! computation, since DSK type 2 software often can use it to quickly
//! determine that a given fine voxel is empty, without looking up a
//! voxel-plate pointer and then a plate list for that voxel. Any fine voxel
//! that belongs to an empty coarse voxel is empty as well, and typically
//! the majority of empty fine voxels do belong to empty coarse voxels.
//!
//!
//!
//!
//!
//! ### Voxel-Plate Pointer Array
//!
//! The voxel-plate pointer array contains a contiguous set of pointers for
//! each non-empty coarse voxel. There is one pointer for each fine voxel
//! having the associated coarse voxel as a parent. Each such "pointer" is
//! a 1-based index in the voxel-plate association array of the start of the
//! plate list corresponding to a fine voxel. Null pointers in this
//! structure are indicated by the value -1.
//!
//! The pointer set for a given coarse voxel contains one pointer for each
//! fine voxel having that coarse voxel as a parent, so there are
//!
//!
//!
//! ```text
//! 3
//! CGRSCL
//! ```
//!
//! pointers in each set.
//!
//! Let NNECVX indicate the number of non-empty coarse voxels. Then the
//! voxel-plate pointer array has the form:
//!
//!
//!
//! ```text
//!
//! +---------------------+
//! | pointer set 1 |
//! +---------------------+
//! ...
//! +---------------------+
//! | pointer set NNECVX | (number of non-empty coarse voxels)
//! +---------------------+
//!
//! ```
//!
//! The mapping from the coarse voxel grid to pointer sets in the
//! voxel-plate pointer array is determined by the segment's data, the voxel
//! grid parameters, and the order in which the data are processed. As
//! indicated in the following diagram, no particular relationship should be
//! assumed to exist between a non-empty coarse voxel's coordinates in the
//! coarse grid and the position of its pointer set in the voxel-plate
//! pointer array:
//!
//!
//!
//! ```text
//!
//! Coarse voxel grid Voxel-plate pointer array
//!
//! +--------------------------------+
//! .->| pointer set for coarse voxel v |
//! / +--------------------------------+
//! /
//! +----------------+ /
//! | NULL | /
//! +----------------+ /
//! | coarse voxel u |--./ ...
//! +----------------+ /\
//! | coarse voxel v |-* \
//! +----------------+ \
//! ... \ +--------------------------------+
//! +----------------+ *--> | pointer set for coarse voxel u |
//! | NULL | +--------------------------------+
//! +----------------+ ...
//! | coarse voxel w |--.
//! +----------------+ \ +--------------------------------+
//! | NULL | *-----> | pointer set for coarse voxel w |
//! +----------------+ +--------------------------------+
//!
//! ```
//!
//! Above, the letters
//!
//!
//!
//! ```text
//! u, v, w
//! ```
//!
//! indicate arbitrary voxel indices. The positions of the null values were
//! selected for this example. They're not representative of an actual DSK
//! segment.
//!
//! Within the voxel-plate pointer array, each pointer set has the form:
//!
//!
//!
//! ```text
//!
//! +-----------+
//! | pointer | voxel 1
//! +-----------+
//! ...
//! +-----------+
//! | pointer | voxel CGRSCL**3
//! +-----------+
//!
//! ```
//!
//! Each pointer corresponds to a fine voxel in the coarse voxel associated
//! with the pointer set. Treating the fine voxels in this coarse voxel as a
//! 1-dimensional array, the first fine voxel maps to the first pointer, and
//! so on. The ordering of the fine voxels is Fortran-style, so a fine voxel
//! with 1-based indices (I, J, K) relative to its parent coarse voxel has
//! the one-dimensional index
//!
//!
//!
//! ```text
//!
//! 2
//! I + (J-1)*CGRSCL + (K-1)*CGRSCL
//!
//! ```
//!
//! The fine voxel with coordinates (1, 1, 1) relative to the parent coarse
//! voxel is located in parent voxel's corner having minimum X, Y, and Z
//! values in the Cartesian coordinate system associated with the segment's
//! reference frame.
//!
//!
//!
//!
//!
//! ### Voxel-Plate Association Array
//!
//! The voxel-plate association array contains, for each non-empty fine
//! voxel, a list of plate IDs identifying the plates that intersect that
//! voxel, and a plate count.
//!
//! Let NNEFVX be the total number of non-empty fine voxels in the fine
//! grid. Let
//!
//!
//!
//! ```text
//! v_1, v_2, ..., v_NNEFVX
//! ```
//!
//! indicate NNEFVX indices of non-empty fine voxels in arbitrary order. The
//! voxel-plate association array has the form:
//!
//!
//!
//! ```text
//!
//! +-------------------------+
//! | List for voxel v_1 |
//! +-------------------------+
//! | List for voxel v_2 |
//! +-------------------------+
//! ...
//! +-------------------------+
//! | List for voxel v_NNEFVX | (number of non-empty fine voxels)
//! +-------------------------+
//!
//! ```
//!
//! Let N be the number of plates in the plate list for voxel v_i. Let
//!
//!
//!
//! ```text
//! p_1, p_2, ..., p_N
//! ```
//!
//! be the plate IDs of these plates. The plate list for the fine voxel at
//! index v_i has the form
//!
//!
//!
//! ```text
//!
//! +--------------------+
//! | List count = N |
//! +--------------------+
//! | Plate ID p_1 |
//! +--------------------+
//! ...
//! +--------------------+
//! | Plate ID p_N |
//! +--------------------+
//!
//! ```
//!
//! The mapping from a pointer in the voxel-plate pointer array to a plate
//! list in the voxel-plate association array is determined by the segment's
//! data, the voxel grid parameters, and the order in which the data are
//! processed. As indicated in the following diagram, no particular
//! relationship should be assumed to exist between the position of a
//! pointer in the voxel-plate pointer array and the position of the
//! corresponding plate list in the voxel-plate association array:
//!
//!
//!
//! ```text
//!
//!
//! Voxel-plate Voxel-plate association array
//! pointer array
//! +-------------------------------+
//! .->| plate list for voxel u_2 |
//! / +-------------------------------+
//! /
//! /
//! pointer set u /
//! +----------------+ /
//! | voxel u_1 |--./ ...
//! +----------------+ /\
//! | voxel u_2 |-* \
//! +----------------+ \
//! ... \ +-------------------------------+
//! +----------------+ *--->| plate list for voxel u_1 |
//! | NULL | +-------------------------------+
//! +----------------+ ...
//! | voxel u_n |--.
//! +----------------+ \ +-------------------------------+
//! | NULL | *------>| plate list for voxel u_n |
//! +----------------+ +-------------------------------+
//!
//! 3
//! CGRSCL elements
//!
//!
//! ```
//!
//! Above, the letter "u" indicates an arbitrary pointer set in the
//! voxel-plate pointer array, which contains NNECVX such sets. The
//! positions of the null values were selected for this example. They're not
//! representative of an actual DSK segment.
//!
//!
//!
//!
//!
//! ### Size of the Voxel-Plate Association Array
//!
//! This section likely is of interest only to DSK creators.
//!
//! Other than the optional vertex-plate association array, the voxel-plate
//! association array is the largest ancillary data structure in a DSK type
//! 2 segment. The size, in units of integers, of this array is affected by
//! the fine voxel scale, which is a user-selectable parameter. For a given
//! plate and vertex set, the size of fine voxels varies in proportion to
//! the fine voxel scale.
//!
//! Let NVOXPL be the size, in units of integers, of the voxel-plate
//! association array; as above, let NNEFVX be the total count of non-empty
//! fine voxels; let NP be the segment's plate count. A lower bound on
//! NVOXPL is
//!
//!
//!
//! ```text
//!
//! NNEFVX + NP
//!
//! ```
//!
//! This number reflects the plate counts for the plate lists of each
//! non-empty fine voxel, plus the presence of each plate ID on at least one
//! list.
//!
//! Normally, a large number of plates cross voxel boundaries and so have
//! their IDs on multiple lists. Hence NVOXPL is normally larger than the
//! lower bound shown above.
//!
//! Reducing the fine voxel size improves the discrimination of the fine
//! grid, which can improve the efficiency of algorithms that must operate
//! on plates associated with a specified spatial region. For example, in
//! the ray-surface intercept computation, the count of plates associated
//! with voxels intersected by the ray will usually decrease as the voxel
//! size is reduced.
//!
//! However, as the fine voxel size is reduced, more plates cross voxel
//! boundaries---such plates are on the plate list of each voxel they
//! touch---and NVOXPL increases. The memory required to hold the spatial
//! index increases as well; it may become too large to allow a program
//! calling [DSKW02](crate::raw::dskw02) (the utility MKDSK is one such program) to run
//! successfully. If a DSK segment with a very large value of NVOXPL is
//! successfully created, its large size may have a detrimental effect on
//! disk access time.
//!
//!
//!
//!
//!
//! ## Spatial Index: Vertex-Plate Mapping
//!
//! Recall that a "plate" is a 3-tuple of integer vertex IDs. Given a
//! vertex ID, the vertex-plate mapping enables DSK software to quickly find
//! the plates that include that vertex ID as one of their own. This enables
//! geometric algorithms to quickly find the plates that lie close to a
//! given plate.
//!
//! Currently (as of the time of release of the N0066 SPICE Toolkit) there
//! are no SPICE routines that rely on the vertex-plate mapping. Creation of
//! this mapping is therefore optional. Both the DSK type 2 writer routine
//! [DSKW02](crate::raw::dskw02) and the utility program MKDSK enable users to indicate whether to
//! create a vertex-plate mapping in an output DSK segment.
//!
//!
//!
//!
//!
//! ### Structure of the Vertex-Plate Mapping
//!
//! The vertex-plate mapping consists of two arrays in DAS integer address
//! space: the vertex-plate pointer array and the vertex-plate association
//! array. Elements of the former array refer to positions in the latter:
//!
//!
//!
//! ```text
//!
//!
//! +--------------+
//! | |
//! | |
//! +---------------+ | |
//! | | | |
//! | | | |
//! | | | |
//! | Vertex-plate |-->| Vertex-plate |
//! | pointer array | | association |
//! | | | array |
//! | | | |
//! +---------------+ | |
//! | |
//! | |
//! +--------------+
//!
//!
//! ```
//!
//! Let NV be the number of vertices in the segment. Then the vertex-plate
//! pointer array contains NV elements, and the ith element indicates the
//! plate list associated with vertex i.
//!
//! The vertex-plate association array contains a plate list for each
//! vertex:
//!
//!
//!
//! ```text
//!
//! +----------------------+
//! | List for vertex v_1 |
//! +----------------------+
//! | List for vertex v_2 |
//! +----------------------+
//! ...
//! +----------------------+
//! | List for vertex v_NV |
//! +----------------------+
//!
//! ```
//!
//! Let N be the number of plates in the plate list for vertex i. Let
//!
//!
//!
//! ```text
//! p_1, p_2, ..., p_N
//! ```
//!
//! be the plate IDs of these plates. The plate list for vertex i has the
//! form
//!
//!
//!
//! ```text
//!
//!
//! +--------------------+
//! | List count = N |
//! +--------------------+
//! | Plate ID p_1 |
//! +--------------------+
//! ...
//! +--------------------+
//! | Plate ID p_N |
//! +--------------------+
//!
//! ```
//!
//! The mapping from a vertex to a plate list in the vertex-plate
//! association array is determined by the segment's data, the voxel grid
//! parameters, and the order in which the data are processed. No particular
//! relationship should be assumed to exist between a vertex ID and the
//! position of the corresponding plate list in the vertex-plate association
//! array.
//!
//!
//!
//!
//!
//! ### Size of the Vertex-Plate Mapping Array
//!
//! This section likely is of interest only to DSK creators.
//!
//! Let NV be a DSK type 2 segment's vertex count, and let NP be the
//! segment's plate count. Then the size, in units of integers, of the
//! vertex-plate pointer array is
//!
//!
//!
//! ```text
//! NV
//! ```
//!
//! and the size of the vertex-plate association array is
//!
//!
//!
//! ```text
//! NV + 3*NP
//! ```
//!
//! The latter value is due to the facts that
//!
//!
//!
//! * Each plate ID is on exactly three lists
//!
//! * There is a list for each of the NV vertices
//!
//! * Each list contains a plate count
//!
//! The potentially large size of the vertex-plate association array makes
//! the optional vertex-plate mapping a good candidate for omission when a
//! DSK type 2 segment is created.
//!
//!
//!
//!
//!
//! ## Layout of DSK Type 2 Segments
//!
//! Below we describe the organization of integer and double precision data
//! and ancillary information in DSK type 2 segments.
//!
//!
//!
//!
//!
//! ### DSK Type 2 Integer Segment Component
//!
//! The layout in DAS integer address space of the integer items in a DSK
//! type 2 segment is:
//!
//!
//!
//! ```text
//!
//! +-----------------+
//! | NV | number of vertices
//! +-----------------+
//! | NP | number of plates
//! +-----------------+
//! | NVXTOT | total number of voxels
//! +-----------------+
//! | VGREXT | voxel grid extents, 3 integers
//! +-----------------+
//! | CGRSCL | coarse voxel grid scale
//! +-----------------+
//! | VOXNPT | size of voxel-plate pointer list
//! +-----------------+
//! | VOXNPL | size of voxel-plate association list
//! +-----------------+
//! | VTXNPL | size of vertex-plate association list
//! +-----------------+
//! | PLATES | NP 3-tuples of vertex IDs
//! +-----------------+
//! | VOXPTR | voxel-plate pointer array, variable size
//! +-----------------+
//! | VOXPLT | voxel-plate association list, variable size
//! +-----------------+
//! | VTXPTR | vertex-plate pointer array, 0 or
//! | | NV integers
//! +-----------------+
//! | VTXPLT | vertex-plate association list,
//! | | 0 or NV + 3*NP integers
//! +-----------------+
//! | CGRPTR | coarse grid pointers, MAXCGR integers
//! +-----------------+
//!
//! ```
//!
//! The sizes of all variable-size items are stored at known locations, so
//! the starting position of any item can be calculated. Parameters
//! specifying offsets of the items from the segment's base integer address
//! are declared in dsk02.inc. The segment's base integer address is
//! available from the segment's DLA descriptor.
//!
//! SPICE provides the low-level utility routine [DSKI02](crate::raw::dski02) to fetch any of the
//! items shown above. Plates and the plate count may be fetched more
//! conveniently using the routines [DSKP02](crate::raw::dskp02) and [DSKZ02](crate::raw::dskz02).
//!
//!
//!
//!
//!
//! ### DSK Type 2 Double Precision Segment Component
//!
//! The layout in DAS double precision address space of the double precision
//! items in a DSK type 2 segment is:
//!
//!
//!
//! ```text
//!
//! +-------------------+
//! | DSK descriptor | DSKDSZ d.p. values
//! +-------------------+
//! | Vertex bounds | 6 d.p. values (min/max for each component)
//! +-------------------+
//! | Voxel grid origin | 3 d.p. values
//! +-------------------+
//! | Fine voxel size | 1 d.p. value
//! +-------------------+
//! | Vertices | 3*NV d.p. values
//! +-------------------+
//!
//! ```
//!
//! The parameter DSKDSZ is declared in dskdsc.inc.
//!
//! SPICE provides the low-level utility routine [DSKD02](crate::raw::dskd02) to fetch any of the
//! items shown above. Vertices and the vertex count may be fetched more
//! conveniently using the routines [DSKV02](crate::raw::dskv02) and [DSKZ02](crate::raw::dskz02).
//!
//! The DSK segment descriptor layout is:
//!
//!
//!
//! ```text
//!
//! +---------------------+
//! | Surface ID code |
//! +---------------------+
//! | Center ID code |
//! +---------------------+
//! | Data class code |
//! +---------------------+
//! | Data type |
//! +---------------------+
//! | Ref frame code |
//! +---------------------+
//! | Coord sys code |
//! +---------------------+
//! | Coord sys parameters| 10 d.p. values
//! +---------------------+
//! | Min coord 1 |
//! +---------------------+
//! | Max coord 1 |
//! +---------------------+
//! | Min coord 2 |
//! +---------------------+
//! | Max coord 2 |
//! +---------------------+
//! | Min coord 3 |
//! +---------------------+
//! | Max coord 3 |
//! +---------------------+
//! | Start time |
//! +---------------------+
//! | Stop time |
//! +---------------------+
//!
//! ```
//!
//! The DSK descriptor of a DSK segment may be fetched using the routine [DSKGD](crate::raw::dskgd).
//!
//!
//!
//!
//!
//! ### Coordinate System Parameters
//!
//! The coordinate system parameter section of a DSK descriptor always
//! contains 10 elements.
//!
//! The contents of this section are dependent on the coordinate system. For
//! planetodetic coordinates, the contents are:
//!
//!
//!
//! ```text
//!
//! +------------------------+
//! | Equatorial radius (km) |
//! +------------------------+
//! | Flattening coefficient |
//! +------------------------+
//! | <undefined> | 8 d.p. values
//! +------------------------+
//!
//! ```
//!
//! These parameters define the axes of a reference ellipsoid. The length of
//! the polar axis is
//!
//!
//!
//! ```text
//!
//! polar_axis = (1 - flattening_coefficient) * equatorial_axis
//!
//! ```
//!
//! For planetocentric latitudinal and rectangular coordinates, all elements
//! are undefined.
//!
//! DSK subsystem computations involving a DSK segment always use the
//! coordinate parameters stored in that segment. These parameters may
//! differ from those specified in a text PCK used by the same application
//! program, or from those specified in a different segment for the same
//! body.
//!
//! It is not necessarily an error for different sets of coordinate
//! parameters to be used in a computation, but DSK users should be aware of
//! which parameters are used for which purpose.
//!
//!
//!
//!
//!
//! # Common Problems
//!
//!
//!
//!
//!
//! ## Slow DSK Computations
//!
//! Depending on the computation and the DSK data used, DSK-based geometry
//! computations can range from imperceptibly slower to orders of magnitude
//! slower than those using triaxial ellipsoid shape models.
//!
//! SPICE users can speed up DSK computations by several means:
//!
//!
//!
//! * 1. Store DSK files on a fast medium, such as a solid-state drive.
//!
//! * Most DSK applications perform a large number of physical file reads, so
//! speeding up these operations has a large effect on overall speed.
//!
//! * For applications using large data sets, the speed of the storage medium can
//! be the dominant factor affecting overall program execution speed.
//!
//! * 2. Use the lowest-resolution shape model that's suitable for the computation.
//!
//! * For example, for a small target body, generation of graphics overlays for
//! limbs, terminators, and subspacecraft points may require a type 2 shape
//! model with only a few thousand plates.
//!
//! * Large data sets generally result in slower data access performance. This is
//! due to both slower access to the storage medium, and to the fact that, for
//! some DSK data types, DSK software must perform more operations to find data
//! of interest in a large data set than in a small one. This latter point
//! applies to DSK data type 2.
//!
//! * 3. Choose the proper computation method for the problem.
//!
//! * For example, for a ray-surface intercept computation where there are
//! multiple rays for a given observer, target, and observation time, if it's
//! valid to use the same aberration corrections for all of the rays, then the
//! lower-level routine [DSKXV](crate::raw::dskxv) will perform the computation far faster than
//! [SINCPT](crate::raw::sincpt).
//!
//! * Another example: for large target bodies having shapes that are well
//! approximated by ellipsoids, limb and terminator points might be
//! sufficiently accurate if computed using the "GUIDED" rather than the
//! "TANGENT" method. See the API documentation of [LIMBPT](crate::raw::limbpt) and [TERMPT](crate::raw::termpt) for
//! further information.
//!
//! * Another example: for an illumination angle computation, a low-resolution
//! surface may, in some cases, yield smoother and more meaningful results than
//! a high-resolution surface.
//!
//!
//! ## Non-Portable and Unstable Results
//!
//! Round-off errors can cause valid yet unexpected results due to the fact
//! that round-off errors can differ from one computer platform (this term
//! refers not only to hardware but to math libraries and even compilation
//! options) to the next. For example:
//!
//!
//!
//! * A ray-surface intercept computation, given identical inputs, may result in
//! an intercept on one platform and a miss on another.
//!
//! * The ID of the plate on which a given ray hits a target body may change from
//! one platform to the next.
//!
//! * This situation is not hard to contrive in test software: a program designed
//! to aim rays at a type 2 segment's plate edges and vertices can demonstrate
//! it.
//!
//! * The altitude of an observer above the surface, given identical inputs to
//! the computation, might change drastically from one platform to the next.
//!
//! "Unstable" results are those that vary greatly in response to small
//! changes in input values. A small difference in input times, with all
//! other inputs equal, can make the difference between a ray-surface
//! intersection and non-intersection, or between spacecraft altitude
//! measured relative to a plateau vs terrain at the base of a cliff.
//!
//! These problems are best avoided at the time application software is
//! designed: software developers must account for the effects of round-off
//! error.
//!
//!
//!
//!
//!
//! ## Non-Convex and Multi-Valued Surfaces
//!
//! Non-convex surfaces can thwart logic that is valid for triaxial
//! ellipsoid models. For example, at a given point on a non-convex surface,
//! for a specified observer, an emission angle of less than 90 degrees
//! doesn't necessarily imply that the point is visible from the observer.
//! Similarly, a solar incidence angle of less than 90 degrees doesn't
//! necessarily imply the point is illuminated by the sun.
//!
//! Even a slight deviation from convexity can change numerical results
//! considerably from those obtained using a triaxial ellipsoid model. For
//! example, depending on whether there is a mountain in the foreground or
//! whether the intercept lies in a valley (oriented in the general
//! direction of the ray's projection on the surface), the range from an
//! observer to a ray-surface intercept point can be much shorter or longer
//! than the distance to the ray's intercept on the target body's reference
//! ellipsoid.
//!
//! Non-convex surfaces can, in some cases, render some geometric quantities
//! undefined or unusable. For example, the nearest surface point to a given
//! point, not on the surface, can have multiple solutions, all in
//! substantially different directions from the given point. Another
//! example: the origin of a body-fixed reference frame for an object may be
//! outside of the object--- a surface modeling a planetary ring would have
//! this property.
//!
//! Multi-valued surfaces are those for which, for a given latitude and
//! longitude, or for a given (X,Y) value, there are multiple radius or
//! height values. These surfaces can occur due to presence of topographic
//! features such as cliffs, caves, and arches. They can also occur due to
//! the large-scale shape of an object, as is the case for the nucleus of
//! the comet Churyumov-Gerasimenko.
//!
//! Multi-valued surfaces invite new categories of errors not possible with
//! single-valued, non-convex surfaces. For example, for a given observer
//! position, the sub-observer point can vary depending on the observer's
//! altitude. Software meant for use with single-valued surfaces, for
//! example the routine [LATSRF](crate::raw::latsrf), may yield incorrect results for such cases.
//!
//! Multi-valued surfaces can yield discontinuities in derived quantities
//! that are well-behaved when an ellipsoid is used to model the target's
//! shape. For example, when an observing spacecraft overflies a cliff, the
//! observer's altitude can change discontinuously. If the sub-spacecraft
//! point is corrected for light time, the light time algorithm may converge
//! slowly or not at all.
//!
//! Again, these problems are best solved by designing application software
//! to avoid assumptions appropriate only for ellipsoids.
//!
//!
//!
//!
//!
//! ## DSK File Creation Errors
//!
//! The variety of possible DSK file creation errors is limited only by the
//! fact that inputs to the process contain a finite number of bytes. We'll
//! mention only some of the common ones.
//!
//!
//!
//!
//!
//! ### MKDSK Setup File Errors
//!
//! While MKDSK can check for obviously invalid values, there are some
//! values that it either cannot or does not check:
//!
//!
//!
//! * Central body ID code
//!
//! * Surface ID code
//!
//! * Central body reference frame---is it the one to which the data are actually
//! referenced?
//!
//! * Segment coordinate bounds---are they compatible with the data?
//!
//! * Angular and distance units
//!
//! MKDSK does place a copy of the setup file in the comment area of the
//! output DSK file, so users can check it.
//!
//!
//!
//!
//!
//! ### Data Errors
//!
//! Some data properties are allowed by MKDSK and [DSKW02](crate::raw::dskw02), but result in DSK
//! segments that may be unsuitable for some computations. These include:
//!
//!
//!
//! * Degenerate plates. Some plate generation algorithms can create plates that
//! have zero-length edges (in fact, MKDSK can be induced to do this). Such
//! plates can be written to a DSK segment, but they will cause failure of
//! algorithms that need to compute the outward normal vectors of plates.
//!
//! * Missing data. Missing data can cause failure of some algorithms such as the
//! sub-observer point computation.
//!
//!
//! ### Segment Coverage Errors
//!
//! It is possible for DSK creators to create segments that don't have the
//! coverage claimed in the segments' DSK descriptors and intended by the
//! creator to be present.
//!
//! This is an easy error to make when a large data set is distributed
//! across multiple DSK files. The DSK creator may assume that the original
//! plate set, partitioned among various files, will yield the same coverage
//! as if all plates were stored in a single segment. Not so---each segment
//! can only provide the coverage its DSK descriptor claims it has, so if a
//! plate needed by a segment to provide coverage near, but within, that
//! segment's boundary is allocated to a different segment, the first
//! segment's coverage will have a gap.
//!
//! An artificial, but simple, example of this is a tessellation of a
//! sphere, using triangular plates. Suppose that the surface is partitioned
//! into a 6 x 12 grid of segments, each covering a 30 degree by 30 degree
//! region of planetocentric longitude and latitude. Suppose each segment
//! contains 225 pairs of plates such that each pair covers a
//! longitude-latitude rectangle having angular extent 2 degrees by 2
//! degrees, so each segment is "covered" by 450 plates.
//!
//! Consider the segment covering the coordinate rectangle
//!
//!
//!
//! ```text
//! Planetocentric longitude (deg): 0 to +30
//! Planetocentric latitude (deg): +30 to +60
//! ```
//!
//! For each plate having two vertices on the segment's southern boundary,
//! the edge of that plate connecting those vertices has latitude greater
//! than 30 degrees everywhere but at the vertices themselves. At the
//! midpoint of that edge, the latitude is actually about 30.00378 degrees.
//!
//! A ray aimed from an exterior vertex to the center of the sphere will
//! miss the surface if the longitude of the vertex is 15 degrees and
//! latitude of the vertex is above 30 degrees but less than the latitude of
//! the edge's midpoint.
//!
//! The solution is to create each segment using "padding"---additional
//! plates extending slightly beyond the segment's southern boundary, so no
//! ray emanating from the origin and hitting the sphere within the
//! segment's longitude-latitude coverage can miss all of the segment's
//! plates.
//!
//! The same problem exists for all southern segment latitude boundaries
//! having positive latitude, and for all northern segment latitude
//! boundaries having negative latitude. All of these boundaries require
//! padding in order to achieve the intended coverage.
//!
//!
//!
//!
//!
//! ### Poor Data Distribution Across Segments
//!
//! It's possible to create DSK segments that are technically valid but that
//! give rise to very slow run-time performance.
//!
//! A seemingly attractive choice that can lead to this problem is
//! partitioning a large data set into a small number of files, each of
//! which contains a large number of plates.
//!
//! Type 2 segments can contain 10000000 or more plates (see Appendix B),
//! but as a segment's plate count increases, the speed of DSK ray-surface
//! intercept computations decreases.
//!
//! Experience indicates that DSK ray-surface intercepts exhibit an
//! "economy of small scale" phenomenon, whereby spreading data across
//! multiple, small segments tends to improve performance. This is true only
//! up to a point: as the number of segments grows, the amount of time spent
//! reading new data when switching from one segment to another grows. At
//! some point this overhead becomes a significant drag on performance.
//!
//!
//!
//!
//!
//! # Appendix A --- Revision History
//!
//!
//!
//!
//!
//! ### 2017 APR 05 by N. J. Bachman.
//!
//! Initial release.
//!
//!
//!
//!
//!
//! # Appendix B --- DSK Subsystem Limits
//!
//! The limits shown here apply to the N0066 SPICE Toolkit.
//!
//! See the files
//!
//!
//!
//! ```text
//! dskdsc.inc
//! dsk02.inc
//! ```
//!
//! for declarations of public parameters defining DSK limits.
//!
//!
//!
//!
//!
//! ## General Limits
//!
//!
//!
//! * Maximum number of loaded DSK files: 5000
//!
//! * The practical limit is lower, since the total number of kernels of all
//! types that can be loaded is 5000.
//!
//! * Maximum number of loaded DSK segments: 10000
//!
//! * Note that the DSK subsystem, unlike the SPK, CK, and binary PCK subsystems,
//! does not search kernels for segments in "search without buffering" mode.
//! Thus instead of suffering greatly degraded performance, a user's
//! application will receive a SPICE error signal if an attempt is made to load
//! too many segments.
//!
//! * Maximum number of surfaces in a surface list: 100
//!
//! * This applies to surface lists in calls to the SPICE APIs that use them.
//!
//! * Maximum number of surface name-ID pairs that can be defined at run time:
//! 2003
//!
//!
//! ## DSK Type 2 Segment Limits
//!
//! For all platforms:
//!
//!
//!
//! * Maximum number of coarse voxels:
//!
//!
//! 100000
//!
//! * Maximum number of fine voxels:
//!
//!
//! 100000000
//!
//! For the platforms
//!
//!
//!
//! ```text
//! PC-64BIT-MS_C
//! PC-CYGWIN-64BIT-GCC_C
//! PC-CYGWIN-64BIT-GFORTRAN
//! PC-CYGWIN-GFORTRAN
//! PC-CYGWIN_C
//! PC-MS_C
//! PC-WINDOWS-64BIT-IFORT
//! PC-WINDOWS-IFORT
//! SUN-SOLARIS
//! SUN-SOLARIS-64BIT-GCC_C
//! SUN-SOLARIS-64BIT-NATIVE_C
//! SUN-SOLARIS-GCC_C
//! SUN-SOLARIS-NATIVE_C
//! ```
//!
//! the following limits apply:
//!
//!
//!
//! * Maximum number of plates:
//!
//!
//! 10000000
//!
//! * Maximum number of vertices:
//!
//!
//! 5000002
//!
//! For all others, the limits are:
//!
//!
//!
//! * Maximum number of plates:
//!
//!
//! 32000000
//!
//! * Maximum number of vertices:
//!
//!
//! 16000002
//!
//!